[PYTHON] 클래스 '__new__ 메소드를 팩토리로 사용 : __init__이 두 번 호출 됨
PYTHON클래스 '__new__ 메소드를 팩토리로 사용 : __init__이 두 번 호출 됨
나는 파이썬에서 이상한 버그를 만났습니다. __new__ 메소드를 팩토리로 사용하면 인스턴스화 된 클래스의 __init__ 메소드가 두 번 호출됩니다.
이 아이디어는 원래 mother 클래스의 __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__을 호출합니다. Triangle ()을 호출하여 __new__ 내부에서 객체를 만들면 __new__ 및 __init__이 추가로 호출됩니다.
객체를 생성 할 때 Python은 __new__ 메소드를 호출하여 객체를 생성 한 다음 반환 된 객체에서 __init__을 호출합니다. Triangle ()을 호출하여 __new__ 내부에서 객체를 만들면 __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)
__init__에 대한 호출을 트리거하지 않고 Rectangle 또는 Triangle을 생성 한 다음 __init__은 한 번만 호출됩니다.
수퍼 워크가 어떻게 작동하는지에 대한 @ Adrian의 질문에 답하기 위해 편집하십시오.
super (Shape, cls)는 cls .__ mro__을 검색하여 Shape를 찾은 다음 나머지 시퀀스를 검색하여 속성을 찾습니다.
삼각형 .__ mro__은 (삼각형, 도형, 객체)이며 Rectangle .__ mro__은 (Rectangle, Shape, object)이고 Shape .__ mro__은 그냥 (Shape, object)입니다. super (Shape, cls)를 호출 할 때, Mroquence의 모든 것을 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, 객체)를 검색하지만 D 인스턴스가있는 경우 B에서 동일한 호출이 (C, A, 객체)를 검색합니다. D .__ mro__는 (B, C, A, object)입니다.
따라서이 특별한 경우에 셰이프의 구성 동작을 수정하는 새로운 mixin 클래스를 정의 할 수 있으며 기존 삼각형과 사각형을 상속 받지만 다르게 구성되는 특수화 된 삼각형과 사각형을 가질 수 있습니다.
-
==============================
2.내 질문을 게시 한 후, 해킹과 같은 문제를 해결할 수있는 방법을 찾은 솔루션을 계속 찾았습니다. Duncan의 솔루션보다 열등하지만 나는 아무 것도 언급하지 않는 것이 흥미로울 수 있다고 생각했습니다. 낫 (Shapeclass)
내 질문을 게시 한 후, 해킹과 같은 문제를 해결할 수있는 방법을 찾은 솔루션을 계속 찾았습니다. Duncan의 솔루션보다 열등하지만 나는 아무 것도 언급하지 않는 것이 흥미로울 수 있다고 생각했습니다. 낫 (Shapeclass)
class ShapeFactory(type): def __call__(cls, desc): if cls is Shape: if desc == 'big': return Rectangle(desc) if desc == 'small': return Triangle(desc) return type.__call__(cls, desc) class Shape(object): __metaclass__ = ShapeFactory def __init__(self, desc): print "init called" self.desc = desc
-
==============================
3.필자가 설치 한 파이썬 인터프리터 중 하나에서이 동작을 실제로 재현 할 수는 없습니다. 따라서 이것은 추측의 일부입니다. 하나...
필자가 설치 한 파이썬 인터프리터 중 하나에서이 동작을 실제로 재현 할 수는 없습니다. 따라서 이것은 추측의 일부입니다. 하나...
__init__은 두 개의 객체, 즉 원래의 Shape 객체와 그 하위 객체 중 하나를 초기화하기 때문에 두 번 호출됩니다. __init__을 변경하여 초기화되는 객체의 클래스도 인쇄하도록하면이를 볼 수 있습니다.
print type(self), "init called"
__new __ ()에서 참조를 반환하지 않으므로 원래 Shape은 삭제되므로 무해한 것입니다.
함수를 호출하는 것은 클래스를 인스턴스화하는 것과 문법적으로 동일하므로 다른 것을 변경하지 않고이 함수를 함수로 변경할 수 있습니다. 그렇게하는 것이 좋습니다. 나는 네가 꺼리는 것을 이해하지 못한다.
from https://stackoverflow.com/questions/5953759/using-a-class-new-method-as-a-factory-init-gets-called-twice by cc-by-sa and MIT license
'PYTHON' 카테고리의 다른 글
[PYTHON] keras가 gpu 버전의 tensorflow를 사용하고 있는지 어떻게 확인합니까? (0) | 2018.10.22 |
---|---|
[PYTHON] matplotlib의 텍스트 주위 상자 (0) | 2018.10.22 |
[PYTHON] 모델없이 Django 폼을 가질 수 있습니까? (0) | 2018.10.22 |
[PYTHON] 파이썬에서 기본 __hash__은 무엇입니까? (0) | 2018.10.22 |
[PYTHON] shlex.split의 반대는 무엇입니까? (0) | 2018.10.22 |