调用内置 class 的 __init__() 和用户定义 class 的 __init__() 的区别
Difference between calling __init__() of build-in class and __init__() of user-defined class
我正在学习 python classes 并且无法理解以下行为:
在下面的示例中,我正在扩展内置 str
class:
class uStr(str):
def __init__(self,u_str):
str.__init__(u_str) #<<<------- no self is needed
def underline(self):
underlines = format('', '-^' + str(len(self)))
return str.__str__(self) + '\n' + underlines
在下面的例子中,我扩展了一个用户定义的 class Fraction
:
from fraction import *
class MixedFraction(Fraction):
def __init__(self, *args):
Fraction.__init__(self, args[0], args[1]) #<<<-------self is needed
def getWholeNum(self):
return self.getNumerator() // self.getDenominator()
为什么我们需要在第二个例子中调用 __init__
的 super class 作为参数,而在调用时不需要给出 self
str
的 __init__
.
首先,您根本不需要那些 __init__
实现。您可以只继承超类实现。如果您确实需要自定义构造,那么对于 uStr
,您应该在 __new__
而不是 __init__
.
中进行
str
doesn't have 自己的 __init__
。它在 __new__
中进行所有初始化,因为 str
实例是不可变的,而在 __init__
中初始化是可变的。 str
从 object
.
继承 __init__
object.__init__
和 object.__new__
有点奇怪。如果恰好 object.__init__
或 object.__new__
中的一个被覆盖,那么如果给定参数(超出 self
),被覆盖的一个将抛出错误,而另一个忽略参数,以节省您必须做的工作提供一个无所事事的覆盖。但是,如果两者都被覆盖或两者都没有被覆盖,那么如果给定参数(超出 self
),两者都会抛出错误。您可以在源代码的 big comment 中看到这一点的解释。
str
实现了 __new__
,但从 object
继承了 __init__
。当您覆盖 __init__
并调用 str.__init__
时,您实际上是在调用 object.__init__
.
当您调用 str.__init__(u_str)
时,您实际上是在 object.__init__
调用 u_str
错误的对象,而不是 self
。因为 u_str
没有 __init__
覆盖(并且因为你只传递一个参数,它被解释为 self
),object.__init__
默默地什么都不做。
当您调用 str.__init__(self, u_str)
时,您正在为 self
调用 object.__init__
,但是由于 self
同时具有 __new__
和 __init__
被覆盖,object.__init__
抱怨 u_str
参数。
看起来您实际上根本不需要在子类中重写构造。如果这样做,自定义构造 str
子类的正确方法是覆盖 __new__
。如果由于某些奇怪的原因你不得不调用 str.__init__
,正确的调用应该是 str.__init__(self)
或 super().__init__()
。由于 object.__init__
不进行任何初始化,您也可以省略超类构造函数调用。
我正在学习 python classes 并且无法理解以下行为:
在下面的示例中,我正在扩展内置 str
class:
class uStr(str):
def __init__(self,u_str):
str.__init__(u_str) #<<<------- no self is needed
def underline(self):
underlines = format('', '-^' + str(len(self)))
return str.__str__(self) + '\n' + underlines
在下面的例子中,我扩展了一个用户定义的 class Fraction
:
from fraction import *
class MixedFraction(Fraction):
def __init__(self, *args):
Fraction.__init__(self, args[0], args[1]) #<<<-------self is needed
def getWholeNum(self):
return self.getNumerator() // self.getDenominator()
为什么我们需要在第二个例子中调用 __init__
的 super class 作为参数,而在调用时不需要给出 self
str
的 __init__
.
首先,您根本不需要那些 __init__
实现。您可以只继承超类实现。如果您确实需要自定义构造,那么对于 uStr
,您应该在 __new__
而不是 __init__
.
str
doesn't have 自己的 __init__
。它在 __new__
中进行所有初始化,因为 str
实例是不可变的,而在 __init__
中初始化是可变的。 str
从 object
.
__init__
object.__init__
和 object.__new__
有点奇怪。如果恰好 object.__init__
或 object.__new__
中的一个被覆盖,那么如果给定参数(超出 self
),被覆盖的一个将抛出错误,而另一个忽略参数,以节省您必须做的工作提供一个无所事事的覆盖。但是,如果两者都被覆盖或两者都没有被覆盖,那么如果给定参数(超出 self
),两者都会抛出错误。您可以在源代码的 big comment 中看到这一点的解释。
str
实现了 __new__
,但从 object
继承了 __init__
。当您覆盖 __init__
并调用 str.__init__
时,您实际上是在调用 object.__init__
.
当您调用 str.__init__(u_str)
时,您实际上是在 object.__init__
调用 u_str
错误的对象,而不是 self
。因为 u_str
没有 __init__
覆盖(并且因为你只传递一个参数,它被解释为 self
),object.__init__
默默地什么都不做。
当您调用 str.__init__(self, u_str)
时,您正在为 self
调用 object.__init__
,但是由于 self
同时具有 __new__
和 __init__
被覆盖,object.__init__
抱怨 u_str
参数。
看起来您实际上根本不需要在子类中重写构造。如果这样做,自定义构造 str
子类的正确方法是覆盖 __new__
。如果由于某些奇怪的原因你不得不调用 str.__init__
,正确的调用应该是 str.__init__(self)
或 super().__init__()
。由于 object.__init__
不进行任何初始化,您也可以省略超类构造函数调用。