Python で奇妙なバグに遭遇しました。__new__
クラスのメソッドをファクトリとして使用すると、__init__
インスタンス化されたクラスのメソッドが 2 回呼び出されることになります。
元々のアイデアは__new__
、クラス外でファクトリ関数を宣言することなく、渡されたパラメータに応じて親クラスのメソッドを使用して子クラスの特定のインスタンスを返すというものでした。
ここでファクトリ関数を使用するのが最適な設計パターンであることはわかっていますが、プロジェクトのこの時点で設計パターンを変更するとコストがかかります。そこで質問したいのは、このようなスキーマで の二重呼び出しを回避し__init__
、 の単一呼び出しのみを取得する方法はあるかということです。__init__
class Shape(object):
def __new__(cls, desc):
if cls is Shape:
if desc == 'big': return Rectangle(desc)
if desc == 'small': return Triangle(desc)
else:
return super(Shape, cls).__new__(cls, desc)
def __init__(self, desc):
print "init called"
self.desc = desc
class Triangle(Shape):
@property
def number_of_edges(self): return 3
class Rectangle(Shape):
@property
def number_of_edges(self): return 4
instance = Shape('small')
print instance.number_of_edges
>>> init called
>>> init called
>>> 3
どのような助けでも大歓迎です。
ベストアンサー1
オブジェクトを構築すると、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)
これにより、の呼び出しをトリガーせずにRectangle
またはが作成され、 は1 回だけ呼び出されます。Triangle
__init__
__init__
スーパーがどのように機能するかについての@Adrianの質問に答えるために編集します:
super(Shape,cls)
検索cls.__mro__
して見つけShape
、次にシーケンスの残りの部分を検索して属性を見つけます。
Triangle.__mro__
は でありですが(Triangle, Shape, object)
、はだけです。いずれの場合も、を呼び出すと、mro シーケンス内の までのすべてが無視されるため、残るのは単一の要素タプルのみであり、これを使用して目的の属性が検索されます。Rectangle.__mro__
(Rectangle, Shape, object)
Shape.__mro__
(Shape, object)
super(Shape, cls)
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__
は であるためです。(B, C, A, object)
したがって、この特定のケースでは、図形の構築動作を変更する新しいミックスイン クラスを定義し、既存のものから継承しながらも異なる方法で構築された特殊な三角形と四角形を作成できます。