隐式调用父类初始化器
class A(object):
def __init__(self, a, b, c):
#super(A, self).__init__()
super(self.__class__, self).__init__()
class B(A):
def __init__(self, b, c):
print super(B, self)
print super(self.__class__, self)
#super(B, self).__init__(1, b, c)
super(self.__class__, self).__init__(1, b, c)
class C(B):
def __init__(self, c):
#super(C, self).__init__(2, c)
super(self.__class__, self).__init__(2, c)
C(3)
在上面的代码中,注释掉的 __init__
调用似乎是普遍接受的进行超类初始化的“智能”方法。然而,如果类层次结构可能发生变化,我一直使用未注释的形式,直到最近。
看来,在上述层次结构中对 B
的超级构造函数的调用中,再次调用了 B.__init__
,self.__class__
是实际上是C
,而不是我一直假设的B
。
Python-2.x 中是否有某种方法可以在调用超级构造函数而不命名当前类(B in
super(B, self).__init__(1, b, c)
)?
class A(object):
def __init__(self, a, b, c):
#super(A, self).__init__()
super(self.__class__, self).__init__()
class B(A):
def __init__(self, b, c):
print super(B, self)
print super(self.__class__, self)
#super(B, self).__init__(1, b, c)
super(self.__class__, self).__init__(1, b, c)
class C(B):
def __init__(self, c):
#super(C, self).__init__(2, c)
super(self.__class__, self).__init__(2, c)
C(3)
In the above code, the commented out __init__
calls appear to the be the commonly accepted "smart" way to do super class initialization. However in the event that the class hierarchy is likely to change, I have been using the uncommented form, until recently.
It appears that in the call to the super constructor for B
in the above hierarchy, that B.__init__
is called again, self.__class__
is actually C
, not B
as I had always assumed.
Is there some way in Python-2.x that I can maintain proper MRO (with respect to initializing all parent classes in the correct order) when calling super constructors while not naming the current class (the B
in in super(B, self).__init__(1, b, c)
)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
简短的回答:不,在 Python 2.x 中,无法使用正确父类的正确参数隐式调用正确的
__init__
。顺便说一句,此处显示的代码是不正确的:如果您使用 super().
__init__
,则层次结构中的所有类都必须在其__init__
方法中具有相同的签名。否则,如果您引入使用多重继承的新子类,您的代码可能会停止工作。有关问题的详细说明,请参阅 http://fuhm.net/super-harmful/ (有图片)。
Short answer: no, there's no way to implicitly invoke the right
__init__
with the right arguments of the right parent class in Python 2.x.Incidentally, the code as shown here is incorrect: if you use super().
__init__
, then all classes in your hierarchy must have the same signature in their__init__
methods. Otherwise your code can stop working if you introduce a new subclass that uses multiple inheritance.See http://fuhm.net/super-harmful/ for a longer description of the issue (with pictures).
您的代码与方法解析顺序无关。方法解析出现在多重继承的情况下,这不是您的示例的情况。您的代码完全错误,因为您假设
self.__class__
实际上与定义该方法的类是同一类,这是错误的:所以当您应该调用时:
您确实在调用:
编辑:试图更好地回答这个问题。
打印:(
模板模式的修改版本)。
现在父母的方法确实是隐式调用的,但我必须同意 python zen 的观点,即显式优于隐式,因为代码可读性较差,收益也很差。但请注意,所有
_init
方法都有相同的参数,你不能完全忘记父母,我不建议这样做。对于单继承,更好的方法是显式调用父级的方法,而不调用
super
。这样做你不必命名当前类,但你仍然必须关心谁是父类。好的读物是: how-does-pythons-super-do-the-正确的事情以及该问题中建议的链接,特别是Python的Super很漂亮,但是你可以不要使用它
如果层次结构可能会发生变化,则这是不良设计的症状,并且会对使用该代码的所有部分产生影响,因此不应鼓励这样做。
编辑2
我想到了另一个例子,但它使用元类。 Urwid 库使用元类来存储属性,
__super< /code>,在类中,这样您只需要访问该属性即可。
前任:
Your code has nothing to do with method resolution order. Method resolution comes in the case of multiple inheritance which is not the case of your example. Your code is simply wrong because you assume that
self.__class__
is actually the same class of the one where the method is defined and this is wrong:so when you should call:
you are indeed calling:
EDIT: trying to better answer the question.
prints:
(A modified version of template pattern).
Now parents' methods are really called implicitly, but i have to agree with python zen where explicit is better than implicit because the code is lesser readable and the gain is poor. But beware that all
_init
methods have the same parameters, you cannot completely forget about parents and I don't suggest to do so.For single inheritance, a better approach is explicitly calling parent's method, without invoking
super
. Doing so you don't have to name the current class, but still you must care about who is the parent's class.Good reads are: how-does-pythons-super-do-the-right-thing and the links suggested in that question and in particularity Python's Super is nifty, but you can't use it
If hierarchy is likely to change is symptoms of bad design and has consequences in all the parts who are using that code and should not be encouraged.
EDIT 2
Another example comes me in mind, but which uses metaclasses. Urwid library uses metaclass to store an attribute,
__super
, in class so that you need just to access to that attribute.Ex:
也许您正在寻找的是元类?
打印“我是 A 类”
元类所做的是覆盖 B 类(而不是对象)的初始创建,并确保每个 B 对象的内置字典现在包含一个基数组,您可以在其中找到 B 的所有基类
Perhaps what you are looking for is metaclasses?
Prints "I am class A"
What the metaclass does is overriding the initial creation of the B class (not the object) and makes sure that the builtin dictionary for each B object now contains a bases array where you can find all the baseclasses for B
据我所知,以下操作并不常见。但它似乎确实有效。
给定类定义中的方法始终会破坏双下划线属性以包含定义它们的类的名称。因此,如果您以名称破坏的形式存储对该类的引用,实例可以看到它,则可以使用在对
super
的调用中。通过在基类上实现
__new__
来存储对象本身的引用的示例:并且,执行类似的操作,但使用元类并将
__class
引用存储在类对象本身:将其作为一个源文件一起运行:
To my knowledge, the following isn't commonly done. But it does seem to work.
Methods in a given class definition always mangle double-underscore attributes to include the name of the class they're defined in. So, if you stash a reference to the class in name-mangled form where the instances can see it, you can use that in the call to
super
.An example stashing the references on the object itself, by implementing
__new__
on the baseclass:And, doing a similar thing, but using a meta-class and stashing the
__class
references on the class objects themselves:Running this all together, as one source file: