我正在查看一些带有拼写错误的__init__()
函数的代码(它总共有3个underbars而不是4个)。我意识到当一个对象找不到合适的__init__()
时,我真的不知道Python会发生什么。
是否有自动插入的默认初始值设定项?是否有被调用的默认__new__
?为什么带参数的构造函数失败?
class TestClass(object):
def do_something(self):
print("Hello From TestClass!")
# What is called here?
instance = TestClass()
instance.do_something()
# Why does this fail?
argument = 100
instance = TestClass(argument)
答案 0 :(得分:2)
是否有自动插入的默认初始化程序?
是。除非被覆盖/继承,否则每个类都有一个默认的伪构造函数。
是否有被调用的默认
__new__
?
是。默认情况下,除了实际创建对象并设置其类型外,它没有做太多工作。
为什么带参数的构造函数失败?
因为默认构造函数不带参数而什么也不做。
答案 1 :(得分:1)
所有内容都继承自Python 3中的object
,因此如果没有提供基类,则会使用默认值。
@freakish回答了你的问题,但我会添加一个编码示例来补充他的解释。
让我们创建一个新的baseClass
我们的新班级myclass
将继承:
class baseClass:
def __init__(self):
print("Inherited __init__ got called")
def __new__(self, *args, **kwargs):
print("Inherited __new__ got called")
return object.__new__(self, *args, **kwargs)
此类重载__init__
和__new__
,因此任何子类化的类都将获得这些方法。让我们创建一个继承自baseClass
的样本类:
class mycls(baseClass):
pass
空,没有定义的dunders。当我们创建这个类的实例时,我们可以看到baseClass
的继承方法被调用:
m = mycls()
Inherited __new__ got called
Inherited __init__ got called
正如您所看到的,我们将获得继承树中父母所定义的所有内容。但是,因为没有显式父级的类总是继承自object
:
class f: pass
f.__bases__ # bases gives us the inherited classes
Out[218]: (object,)
我们将始终使用这些方法来定义默认行为。 对于默认的__init__
,这意味着没有参数,您需要重新定义它才能自定义它!
答案 2 :(得分:1)
您要问的是两个经常混淆的主题:初始值设定项__init__
和构造函数__new__
。另外,我认为你把Python与像Java这样的语言混淆了,其中构造函数是一个大交易而不像其他人,构造和初始化在一个进程中混合在一起(因此对Python新手的程序员来说是一个常见的误解) )。
在Python中,构造函数和初始化程序都是方法,与任何其他方法没有区别。有一个命名约定,解释器会调用两端带有双下划线的(某些)方法而不必明确地执行它,但是如果你愿意,可以自己调用它们,并且你会得到相同的结果。
简而言之:如果您了解__str__
,则了解__init__
和__new__
。
(对于一些有经验的程序员来说,我认为Python最奇怪的是它不会每次都会特殊情况下埋伏你。)
方法解析订单
Python 2.3的new-style classes通过从对象的类开始查找方法名,然后查找该类的祖先,直到它找到要查找的名称或用完要搜索的类。
您可以通过查看其__mro__
字段来查看任何类的方法解析顺序:
>>> TestClass.__mro__
(<class '__main__.TestClass'>, <class 'object'>)
>>> float.__mro__
(<class 'float'>, <class 'object'>)
>>> object.__mro__
(<class 'object'>,)
(Python使用C3 Method Resolution Order algorithm构造元组,但是对于像你这样的简单案例来说它太过分了.C3主要关注的是将复杂的多继承图形线性化为可以在一个类中搜索的类的元组。可预测的顺序。)
任何方法查找,即使是__init__
或__new__
,都遵循方法解决顺序。对于元组中的每个类,Python在其类'__init__'
中查找字符串(如__dict__
);如果该字符串存在,则其相关值---无论它是什么---将作为方法查找的结果返回。
在您的情况下,Python会查找不存在的TestClass.__new__
,然后查找object.__new__
。然后执行object.__new__
(自动填充一些参数)来构造新的TestClass
对象。 __init__
的初始化是相同的,除了您可能自己提供一些额外的参数。
证明(在Python 3中):
>>> class A: pass
...
>>> A.__init__ is object.__init__
True
>>> A.__new__ is object.__new__
True
>>> A.__repr__ is object.__repr__
True
>>> A.__str__ is object.__str__
True
__init__
您尝试将参数传递给object.__init__
失败,因为该方法不接受任何参数(self
除外,已经为您填写)。看起来或多或少是这样的:
class Object:
def __init__(self):
return
<强>结论强>
Python不会为你的类“创建”默认构造函数或初始化程序,就像(IIRC)Java那样。但它有一个位于object
类中的每一个,所以如果你不编写自己的,你将继承它们。