Pet*_*erE 9 python inheritance
假设我们有一个类'Parent',由于某种原因已__new__定义,并且继承了它的类'Child'.(在我的情况下,我试图继承我无法修改的第三方课程)
class Parent:
def __new__(cls, arg):
# ... something important is done here with arg
Run Code Online (Sandbox Code Playgroud)
我的尝试是:
class Child(Parent):
def __init__(self, myArg, argForSuperclass):
Parent.__new__(argForSuperclass)
self.field = myArg
Run Code Online (Sandbox Code Playgroud)
但同时
p = Parent("argForSuperclass")
Run Code Online (Sandbox Code Playgroud)
按预期工作
c = Child("myArg", "argForSuperclass")
Run Code Online (Sandbox Code Playgroud)
失败,因为'Child'试图调用__new__它从'Parent'而不是它自己的__init__方法继承的方法.
为了获得预期的行为,我必须在"儿童"中进行哪些更改?
bra*_*zzi 11
首先,__new__为了避免这些问题,完全覆盖并不是最佳做法......但我知道,这不是你的错.对于这种情况,覆盖的最佳做法__new__是使其接受可选参数......
class Parent(object):
def __new__(cls, value, *args, **kwargs):
print 'my value is', value
return object.__new__(cls, *args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
......所以孩子们可以得到自己的:
class Child(Parent):
def __init__(self, for_parent, my_stuff):
self.my_stuff = my_stuff
Run Code Online (Sandbox Code Playgroud)
然后,它会工作:
>>> c = Child(2, "Child name is Juju")
my value is 2
>>> c.my_stuff
'Child name is Juju'
Run Code Online (Sandbox Code Playgroud)
但是,您父类的作者并不是那么明智并且给了您这个问题:
class Parent(object):
def __new__(cls, value):
print 'my value is', value
return object.__new__(cls)
Run Code Online (Sandbox Code Playgroud)
在这种情况下,只需覆盖__new__子进程,使其接受可选参数,并调用父__new__进程:
class Child(Parent):
def __new__(cls, value, *args, **kwargs):
return Parent.__new__(cls, value)
def __init__(self, for_parent, my_stuff):
self.my_stuff = my_stuff
Run Code Online (Sandbox Code Playgroud)
Child 不会调用 Parent's__new__而不是它自己的__init__,而是在 之前调用它自己的__new__(继承自 Parent)。 __init__
您需要了解这些方法的用途以及 Python 何时调用它们。__new__被调用以产生一个实例对象,然后__init__被调用以初始化该实例的属性。Python 会将相同的参数传递给这两种方法:传递给类以开始该过程的参数。
所以当你从一个类继承时你所做的__new__正是你在继承任何其他方法时所做的,这些方法在父级中具有与你想要的不同的签名。您需要覆盖__new__以接收 Child 的参数并Parent.__new__使用它期望的参数进行调用。然后您__init__完全单独覆盖(尽管使用相同的参数列表,并且同样需要__init__使用其自己的预期参数列表调用 Parent 的)。
但是,有两个潜在的困难可能会妨碍您,因为这__new__是自定义获取新实例的过程。它没有理由必须实际创建一个新实例(它可以找到一个已经存在的实例),实际上它甚至不必返回类的实例。这可能会导致以下问题:
如果__new__返回一个现有的对象(比如,因为 Parent 希望能够缓存它的实例),那么你可能会发现你的__init__在已经存在的对象上被调用,如果您的对象应该具有可变状态,这可能非常糟糕。但是,如果 Parent 希望能够做这种事情,它可能会期望对它的使用方式有一堆约束,并以任意打破这些约束的方式对其进行子类化(例如,将可变状态添加到一个类中)期望是不可变的,因此它可以缓存和回收其实例)几乎肯定不会工作,即使您可以正确初始化您的对象。如果发生这种事情,并且没有任何文档告诉您应该如何对 Parent 进行子类化,那么第三方可能不打算让您对 Parent 进行子类化,事情会变得很困难为你。__new__而不是__init__,丑陋的那样。
Python仅__init__在类的__new__方法实际返回类的实例时才调用该方法。如果 Parent 使用它的__new__方法作为某种“工厂函数”来返回其他类的对象,那么以直接方式进行子类化很可能会失败,除非您需要做的就是改变“工厂”的工作方式。
| 归档时间: |
|
| 查看次数: |
5015 次 |
| 最近记录: |