creating-a-singleton-in-python和what-is-a-metaclass-in-python
下面这两段代码的执行结果反映了一个问题:很明显元类的存在会影响__call__和__new__的优先级,请问大神能否分析一下两者执行结果不同的原因?
class Singleton(object):
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
print('__new__')
return cls._instance
def __call__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
cls._instance = super(Singleton, cls).__call__(*args, **kwargs)
print('__call__')
return cls._instance
class Foo(Singleton):
pass
print('1')
foo1 = Foo()
print('2')
foo2 = Foo()
print(foo1 is foo2) # True
上面这段代码的执行结果
$ python non_metaclass.py
1
__new__
2
__new__
True
class Singleton(type):
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
print('__new__')
return cls._instance
def __call__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
cls._instance = super(Singleton, cls).__call__(*args, **kwargs)
print('__call__')
return cls._instance
class Foo(metaclass=Singleton):
# 不兼容Python2
pass
print('1')
foo1 = Foo()
print('2')
foo2 = Foo()
print (foo1 is foo2) # True
上面这段代码的执行结果
$ python metaclass.py
__new__
1
__call__
2
__call__
True
如果描述不够详细,请在评论区留一下言,我再改进。
여기서 수정해서 자세히 설명드리겠습니다
메타클래스는 클래스 구조 속성을 정의하며 클래스의 "__new__" 및 "__init__" 메서드는 클래스 인스턴스를 처리하는 데 사용됩니다.
우리가 정의하는 모든 클래스는 유형의 인스턴스로 이해될 수 있습니다
으아아아알겠습니다. "__new__" 및 "__call__"로 돌아갑니다
메타클래스에서는 클래스를 정의하면 "__new__"가 한 번만 실행됩니다. 두 클래스가 이 메타클래스를 사용하면 두 번 실행됩니다.
으아아아그리고 __call__은 인스턴스화할 때마다 호출됩니다. 실제로 Foo.__new__와 동일합니다. 즉, Foo가 __new__를 정의하면 메타클래스의 __call__이 실행되지 않습니다.
으아아아메타클래스의 "__new__"는 정의한 유형을 변경할 수 있습니다. 여기서 Foo를 목록으로 정의했습니다.
으아아아글을 너무 많이 쓰는데 메타클래스를 제대로 이해하는 사람이 거의 없어요. 질문해주셔서 어떻게 감사해야 할지 모르겠습니다
이것은 new와 call의 우선순위에 영향을 미치는 메타클래스의 문제가 아니지만, 메타클래스의 __new__는 클래스 생성 시 한 번만 호출됩니다. 그리고 이 __new__는 귀하의 질문에서와 같이 우리 수업을 만드는 데 사용됩니다. 언제 만들어졌나요? 인터프리터가 Foo 클래스를 해석할 때 클래스 정의에서 __metaclass__ 속성을 찾고, 발견되면 이를 사용하여 클래스를 만듭니다. 찾을 수 없으면 내장 유형을 사용하여 클래스를 생성합니다. 다시 호출하면 어떨까요? 메타클래스가 이미 클래스를 생성했기 때문에 Foo()가 호출될 때마다 클래스를 다시 생성할 수는 없습니다. foo2 = Foo()가 __new__를 출력하지 않는다는 것도 출력에서 볼 수 있습니다. 이때 클래스는 메타클래스, 즉
Singleton
에 의해 생성되었기 때문에 바로 사용하면 됩니다. 우리가 일반적으로 사용하는 클래스와 다르지 않아서 생성될 때마다 새로운 객체가 생성됩니다. 그리고 __call__을 사용하는 이유는 무엇입니까?Foo는 메타클래스 Singleton에 의해 생성된 클래스이므로 Foo를 Singleton의 인스턴스 객체로 생각할 수 있습니다. 따라서 Foo()가 호출될 때마다 __call__이 호출됩니다. __call__에서는 이미 생성된 인스턴스 객체를 얻습니다. 그냥 싱글톤 아닌가요? .
코드를 통해 자세히 설명해보자
으아악실행 후 __call__ 함수의 cls는 메타클래스인 Foo에서 처음이자 유일한 __new__를 호출하여 생성된 클래스이고 cls._instance는 Foo의 인스턴스 객체임을 알 수 있습니다. Foo()가 호출될 때마다 동일한 인스턴스 객체를 얻습니다. 메타클래스는 결국 클래스를 생성하는 클래스입니다. 일단 생성된 클래스는 일반적으로 정의하는 클래스와 다르지 않습니다.