>  기사  >  백엔드 개발  >  Python 클래스 및 메타클래스 심층 분석 II

Python 클래스 및 메타클래스 심층 분석 II

高洛峰
高洛峰원래의
2016-11-22 17:06:191181검색

한 레벨로 돌아가서 클래스 객체 자체가 어떻게 생성되는지 살펴보겠습니다.

type() 메소드가 객체의 유형을 확인하거나 객체가 생성된 클래스를 결정할 수 있다는 것을 알고 있습니다.

print(type(12))
print(type('python'))
<class &#39;int&#39;>
<class &#39;str&#39;>
class A:
    passprint(type(A))
<class &#39;type&#39;>

Pass 이 코드에서 볼 수 있듯이 클래스 객체 A는 type()에 의해 생성됩니다. 즉, 유형을 사용하여 새 객체를 생성할 수도 있고, 생성된 것은 클래스 객체이므로 모든 클래스 객체의 클래스입니다. :

print(type.__doc__)
type(object_or_name, bases, dict)
type(object) -> the object&#39;s type
type(name, bases, dict) -> a new type

class 클래스를 정의하는 구문은 실제로 type(name, bases, dict)로 변환됩니다. 여기서 name 매개변수는 클래스의 이름이고 bases는 상속받는 튜플입니다. 부모 클래스이고 dict가 속성과 메서드입니다.

class A:
    pass# 实际上等于B = type(&#39;A&#39;, (), {})

print(A.__name__ == B.__name__)
True

이론적으로는 메타클래스의 의미이지만, 실용적인 관점에서 보면 분명히 사용하기 더 편리하고 합리적입니다. 클래스 구문이며 메타클래스의 실제 의미는 클래스 유형을 상속하여 새로운 메타클래스를 구성하고 특정 작업을 수행하여 특정 동작을 가진 클래스 객체를 생성하는 것입니다. 이러한 관점에서 볼 때, 클래스 유형을 상속한다는 점을 제외하면 그 본질은 일반 클래스 객체와 다르지 않습니다.

인스턴스를 생성할 때 __init__ 메서드를 호출하여 초기화됩니다. 실제로 그 전에는 __new__ 메서드를 호출하여 인스턴스를 생성한 다음 마치 __new__가 변수 선언을 담당하는 것처럼 __init__에 의해 초기화됩니다. , __init__는 선언된 변수 초기화를 담당합니다. 여기에는 __new__(cls,)의 반환 값이 cls 매개 변수의 인스턴스여야 한다는 규칙이 있습니다. 그렇지 않으면 __init__이 트리거되지 않습니다. 예를 들어 enum.Enum의 정의에서는 열거형 유형이 싱글톤 모드이기 때문입니다. 이므로 __new__ 정의에서 해당 인스턴스가 반환되지 않으면 초기화되지 않습니다.

class Enum:
    def __new__(cls, value):
        print(cls, value)
        return value
    def __init__(self):
        print("Will not be called!")
e = Enum(1)
<class &#39;__main__.Enum&#39;> 1

일반적으로 __new__를 직접 정의할 때 다음을 호출하여 cls 인스턴스를 생성해야 합니다. 상위 클래스의 __new__ 메소드, 그리고 메타클래스를 정의할 때 위에서 언급한 유형의 사용법을 호출할 때(메타클래스가 유형에서 상속되기 때문에):

class MetaEnum(type):
    def __new__(metaclass, name, base, attrs):
        print("Metaclass: {}\nName: {}\nParents: {}\nAttributes: {}".format(metaclass, name, base, attrs))
        return super().__new__(metaclass, name, base, attrs)
class Enum(metaclass=MetaEnum):
    # Python 2.7 中定义元类的方法是使用 __metaclass__ 变量
    # [PEP 3115](https://www.python.org/dev/peps/pep-3115/)
    # 将 Python 3.0 以后语法改为 class Cls(metaclass=Meta)
    test = 0
Metaclass: <class &#39;__main__.MetaEnum&#39;>
Name: Enum
Parents: ()
Attributes: {&#39;__qualname__&#39;: &#39;Enum&#39;, &#39;__module__&#39;: &#39;__main__&#39;, &#39;test&#39;: 0}

이때 우리는 더 이상 유형이 아닌 Enum 클래스의 메타클래스 MetaEnum:

type(Enum)
__main__.MetaEnum

__new__ 메서드 외에도 PEP 3115 또한 초기화된 네임스페이스(즉, 유형의 세 번째 매개변수)를 설정하기 위한 __prepare__ 속성을 정의하거나 enum.Enum을 예로 들어 열거 유형의 속성 이름이 재사용되지 않도록 제한해야 하며 그런 다음 동작을 제한할 수 있습니다.

# 定义新的字典类,在赋值新的 dict[k] = v 时
# 检查 k 是否重复
class _EnumDict(dict):
    def __init__(self):
        super().__init__()
        self.members = []
    def __setitem__(self, k, v):
        if k in self.members:
            raise TypeError("Attempted to reuse key: &#39;{}&#39;".format(k))
        else:
            self.members.append(k)
            super().__setitem__(k, v)

class MetaEnum(type):
    @classmethod
    def __prepare__(metaclass, cls, bases):
        return _EnumDict()
    def __new__(metaclass, name, base, attrs):
        return super().__new__(metaclass, name, base, attrs)
class Enum(metaclass=MetaEnum):
    pass

class Color(Enum):
    try:
        red = 1
        red = 2
    except TypeError:# 这里没有使用 as err: 的原因是?
        print("TypeError catched")
TypeError catched

Python의 모든 객체는 특정 클래스의 인스턴스이거나 특정 메타클래스 유형의 인스턴스입니다.

Python 클래스 및 메타클래스 심층 분석 II

요약

메타클래스는 Python에서 상대적으로 심오한 흑마술이며 일반적인 일상 응용 프로그램에서는 일반적으로 사용되지 않을 수 있지만, 그 뒤에 있는 원리를 이해하는 것은 Python에서 필수적입니다. Python 객체 지향 프로그래밍을 이해하면 클래스를 크게 변경해야 하는 경우 최소한 어디서부터 시작해야 하는지 알면 도움이 됩니다.


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.