您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

使用类的__new__方法作为工厂:__init__被调用两次

使用类的__new__方法作为工厂:__init__被调用两次

当构造一个对象时,Python会调用__new__方法来创建该对象,然后__init__在返回的对象上进行调用。当您__new__通过调用从内部创建对象时Triangle(),将导致对__new__和的进一步调用__init__

您应该做的是:

class Shape(object):
    def __new__(cls, desc):
        if cls is Shape:
            if desc == 'big':   return super(Shape, cls).__new__(Rectangle)
            if desc == 'small': return super(Shape, cls).__new__(Triangle)
        else:
            return super(Shape, cls).__new__(cls, desc)

它会创建一个RectangleTriangle不触发调用__init__,然后__init__仅被调用一次。

编辑以回答@Adrian关于super如何工作的问题:

super(Shape,cls)搜索cls.__mro__以查找Shape,然后向下搜索序列的其余部分以找到属性

Triangle.__mro__(Triangle, Shape, object)Rectangle.__mro__(Rectangle, Shape, object)Shape.__mro__而是正义(Shape, object)。对于任何一种情况,当您调用super(Shape, cls)它时,它都会忽略mro序列中的所有内容Shape因此只剩下单个元素元组(object,),它用于查找所需的属性

如果您拥有钻石继承关系,这将变得更加复杂:

class A(object): pass
class B(A): pass
class C(A): pass
class D(B,C): pass

现在B中的方法可能会使用super(B, cls),如果是B的实例会搜索(A, object)但是如果你有一个D实例,相同的调用B搜索(C, A, object)因为D.__mro__is是(B, C, A, object)

因此,在这种特殊情况下,您可以定义一个新的mixin类,该类可以修改形状的构造行为,并且可以具有从现有的三角形和矩形继承但构造不同的专用三角形和矩形。

其他 2022/1/1 18:37:50 有393人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶