设计模式 - Python元类中的__call__和__new__的区别?
大家讲道理
大家讲道理 2017-04-18 10:04:49
0
2
572

参考文档

creating-a-singleton-in-python和what-is-a-metaclass-in-python

问题描述

下面这两段代码的执行结果反映了一个问题:很明显元类的存在会影响__call__和__new__的优先级,请问大神能否分析一下两者执行结果不同的原因?

实例代码

1.不含元类的单例模式

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

2.含有元类的单例模式

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

如果描述不够详细,请在评论区留一下言,我再改进。

大家讲道理
大家讲道理

光阴似箭催人老,日月如移越少年。

모든 응답(2)
黄舟

여기서 수정해서 자세히 설명드리겠습니다

메타클래스는 클래스 구조 속성을 정의하며 클래스의 "__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()가 호출될 때마다 동일한 인스턴스 객체를 얻습니다. 메타클래스는 결국 클래스를 생성하는 클래스입니다. 일단 생성된 클래스는 일반적으로 정의하는 클래스와 다르지 않습니다.

최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!