파이썬의 메타 클래스는 무엇입니까?


질문

 

파이썬에서 메타 클래스는 무엇이며 우리가 무엇을 위해 사용합니까?


답변

 

물체로 클래스

메타 클래스를 이해하기 전에 파이썬에서 클래스를 마스터해야합니다.파이썬은 작은 수업이 어떤 수업이 있는지에 대한 매우 특이한 아이디어를 가지고 있습니다.

대부분의 언어에서는 수업이 객체를 생성하는 방법을 설명하는 코드 조각입니다.그건 파이썬에서도 진실이야 :

>>> class ObjectCreator(object):
...       pass
...

>>> my_object = ObjectCreator()
>>> print(my_object)
<__main__.ObjectCreator object at 0x8974f2c>

그러나 수업은 파이썬에서 그 이상입니다.클래스도 개체입니다.

예, 객체.

키워드 클래스를 사용하자마자 파이썬이 실행되고 생성됩니다. 객체.지침서

>>> class ObjectCreator(object):
...       pass
...

Memory에서 Name objectCreator가있는 객체를 만듭니다.

이 객체 (클래스)는 자체가 개체 (인스턴스)를 생성 할 수 있습니다. 그리고 이것이 그것이 수업이기 때문입니다.

그러나 여전히, 그것은 객체이며 따라서 :

변수에 할당 할 수 있습니다 당신은 그것을 복사 할 수 있습니다 속성을 추가 할 수 있습니다 기능 매개 변수로 전달할 수 있습니다

예 :

>>> print(ObjectCreator) # you can print a class because it's an object
<class '__main__.ObjectCreator'>
>>> def echo(o):
...       print(o)
...
>>> echo(ObjectCreator) # you can pass a class as a parameter
<class '__main__.ObjectCreator'>
>>> print(hasattr(ObjectCreator, 'new_attribute'))
False
>>> ObjectCreator.new_attribute = 'foo' # you can add attributes to a class
>>> print(hasattr(ObjectCreator, 'new_attribute'))
True
>>> print(ObjectCreator.new_attribute)
foo
>>> ObjectCreatorMirror = ObjectCreator # you can assign a class to a variable
>>> print(ObjectCreatorMirror.new_attribute)
foo
>>> print(ObjectCreatorMirror())
<__main__.ObjectCreator object at 0x8997b4c>

동적으로 클래스 만들기

클래스는 객체이기 때문에 모든 객체와 같이 비행기에 그들을 만들 수 있습니다.

먼저 클래스를 사용하여 함수에서 클래스를 만들 수 있습니다.

>>> def choose_class(name):
...     if name == 'foo':
...         class Foo(object):
...             pass
...         return Foo # return the class, not an instance
...     else:
...         class Bar(object):
...             pass
...         return Bar
...
>>> MyClass = choose_class('foo')
>>> print(MyClass) # the function returns a class, not an instance
<class '__main__.Foo'>
>>> print(MyClass()) # you can create an object from this class
<__main__.Foo object at 0x89c6d4c>

그러나 당신이 여전히 전체 수업을 직접 쓸 필요가 있기 때문에 그렇게 역동적이지 않습니다.

클래스는 객체이므로 뭔가에 의해 생성되어야합니다.

클래스 키워드를 사용하면 파이썬 이이 객체를 자동으로 생성합니다.그러나 ~함에 따라 Python에서 대부분의 것들을 사용하면 수동으로 수행 할 수있는 방법을 제공합니다.

함수 유형을 기억 하시겠습니까?무엇을 알 수있는 좋은 오래된 기능 객체를 입력하는 것은 다음과 같습니다.

>>> print(type(1))
<type 'int'>
>>> print(type("1"))
<type 'str'>
>>> print(type(ObjectCreator))
<type 'type'>
>>> print(type(ObjectCreator()))
<class '__main__.ObjectCreator'>

음, 유형은 완전히 다른 능력을 가지고 있으며, 또한 플라이 클래스를 만들 수 있습니다.유형 매개 변수로 클래스의 설명을 취할 수 있습니다. 클래스를 반환합니다.

(나는 동일한 기능이 통과하는 매개 변수에 따라 두 가지 완전히 다른 용도를 가질 수 있다는 것이 어리석은 것입니다. 뒤로 인한 문제입니다. 파이썬의 호환성)

유형이 방법으로 작동합니다.

type(name, bases, attrs)

어디에:

이름 : 클래스의 이름 기지 : 상위급의 튜플 (상속, 비어있을 수 있음) attrs : 속성 이름과 값을 포함한 사전

예 :

>>> class MyShinyClass(object):
...       pass

수동 으로이 방법으로 만들 수 있습니다.

>>> MyShinyClass = type('MyShinyClass', (), {}) # returns a class object
>>> print(MyShinyClass)
<class '__main__.MyShinyClass'>
>>> print(MyShinyClass()) # create an instance with the class
<__main__.MyShinyClass object at 0x8997cec>

우리는 클래스의 이름으로 myShinyClass를 사용한다는 것을 알 수 있습니다. 클래스 참조를 유지하는 변수로그들은 다를 수 있고, 그러나 물건을 복잡하게 할 이유가 없습니다.

유형은 클래스의 속성을 정의하기 위해 사전을 수락합니다.그래서:

>>> class Foo(object):
...       bar = True

번역 될 수 있습니다 :

>>> Foo = type('Foo', (), {'bar':True})

정상급으로 사용 :

>>> print(Foo)
<class '__main__.Foo'>
>>> print(Foo.bar)
True
>>> f = Foo()
>>> print(f)
<__main__.Foo object at 0x8a9b84c>
>>> print(f.bar)
True

물론, 당신은 그것으로부터 상속받을 수 있습니다.

>>>   class FooChild(Foo):
...         pass

있을 것입니다 :

>>> FooChild = type('FooChild', (Foo,), {})
>>> print(FooChild)
<class '__main__.FooChild'>
>>> print(FooChild.bar) # bar is inherited from Foo
True

결국, 수업에 메소드를 추가하려고합니다.그냥 기능을 정의하십시오 적절한 서명을 사용하여 속성으로 할당하십시오.

>>> def echo_bar(self):
...       print(self.bar)
...
>>> FooChild = type('FooChild', (Foo,), {'echo_bar': echo_bar})
>>> hasattr(Foo, 'echo_bar')
False
>>> hasattr(FooChild, 'echo_bar')
True
>>> my_foo = FooChild()
>>> my_foo.echo_bar()
True

그리고 일반적으로 생성 된 클래스 개체에 메서드를 추가하는 것과 같이 클래스를 동적으로 생성 한 후에도 더 많은 방법을 추가 할 수 있습니다.

>>> def echo_bar_more(self):
...       print('yet another method')
...
>>> FooChild.echo_bar_more = echo_bar_more
>>> hasattr(FooChild, 'echo_bar_more')
True

우리가가는 곳을 알 수 있습니다. 파이썬에서 클래스는 객체이며 비행기에서 클래스를 만들 수 있습니다.

이것은 키워드 클래스를 사용할 때 파이썬이 수행하는 것입니다. 메타 클래스를 사용하여 그렇게합니다.

Metaclasses 란 무엇입니까 (마지막으로)

메타 클래스는 수업을 만드는 '재료'입니다.

객체를 만들려면 클래스를 정의합니다.

그러나 우리는 파이썬 클래스가 객체임을 배웠습니다.

음, 메타 클래스는 이러한 객체를 만드는 것입니다.그들은 수업 수업이며, 이 방법으로 그림을 볼 수 있습니다.

MyClass = MetaClass()
my_object = MyClass()

그 유형이 당신이 이렇게하는 것을 할 수있게 보았습니다.

MyClass = type('MyClass', (), {})

함수 유형이 실제로 메타 클래스에 있기 때문입니다.유형은입니다 Metaclass Python은 장면 뒤에있는 모든 클래스를 만드는 데 사용합니다.

이제 "지대가 소문자로 작성된 이유가 있고 유형이 아닌 이유는 무엇입니까?"

글쎄, 나는 그것이 STR와의 일관성이라는 일이라고 생각한다. strings objects 및 int 정수 오브젝트를 만드는 클래스입니다.유형입니다 클래스 객체를 만드는 클래스입니다.

__class__ 속성을 확인하여이를 볼 수 있습니다.

모든 것, 나는 모든 것을 의미한다, 파이썬의 물체이다.정수가 포함 된, 문자열, 함수 및 클래스.그들 모두는 객체입니다.그리고 그들 모두는 가지고 있습니다 수업에서 생성되었습니다 :

>>> age = 35
>>> age.__class__
<type 'int'>
>>> name = 'bob'
>>> name.__class__
<type 'str'>
>>> def foo(): pass
>>> foo.__class__
<type 'function'>
>>> class Bar(object): pass
>>> b = Bar()
>>> b.__class__
<class '__main__.Bar'>

이제 __class__의 __class__는 무엇입니까?

>>> age.__class__.__class__
<type 'type'>
>>> name.__class__.__class__
<type 'type'>
>>> foo.__class__.__class__
<type 'type'>
>>> b.__class__.__class__
<type 'type'>

따라서 메타 클래스는 클래스 객체를 만드는 것들입니다.

원하는 경우 '클래스 팩토리'라고 부를 수 있습니다.

유형은 내장 메타클래스 파이썬이 사용하지만 물론, 당신은 당신을 만들 수 있습니다 자신의 메타클래스.

__metaclass__ 특성

파이썬 2에서 클래스를 작성할 때 __metaclass__ 속성을 추가 할 수 있습니다 (Python 3 구문에 대한 다음 섹션 참조).

class Foo(object):
    __metaclass__ = something...
    [...]

그렇게하면 Python은 메타 클래스를 사용하여 클래스 foo를 만듭니다.

조심해서 까다 롭습니다.

클래스 foo (객체)를 먼저 작성하지만 클래스 오브젝트 foo가 생성되지 않습니다. 아직 메모리에.

파이썬은 클래스 정의에서 __metaclass__를 찾습니다.그것이 그것을 발견하면, 객체 클래스 foo를 만드는 데 사용합니다.그렇지 않으면 사용할 것입니다 클래스를 만들려면 입력하십시오.

그걸 여러 번 읽으십시오.

당신이 할 때 :

class Foo(Bar):
    pass

파이썬은 다음을 수행합니다.

Foo에 __metaclass__ 속성이 있습니까?

예, 메모리에있는 클래스 객체를 만듭니다 (나는 여기에있는 클래스 객체가 여기에 머물러 있습니다.

파이썬이 __metaclass__을 찾을 수없는 경우 모듈 수준에서 __metaclass__를 찾아 똑같이 수행하려고 시도합니다 (기본적으로 오래된 스타일 클래스를 상속하지 않는 수업에만 해당).

그런 다음 __metaclass__를 전혀 찾을 수 없으면 클래스 오브젝트를 작성하기위한 바 (기본 유형 일 수 있음) 자체 메타 클래스 (기본 유형 일 수 있음)를 사용합니다.

__metaclass__ 속성이 상속되지 않으면 여기에서 상위의 메타 클래스 (bar .__ class__)가 될 것입니다.막대가 __metaclass__ 형을 형성하는 __metaclass__ 속성을 사용하는 경우 (____ (__ (__ (__ (__ (__ (______ ()을 입력하지 않아) 하위 클래스는 그 동작을 상속하지 않습니다.

이제 큰 질문은 __metaclass__에 무엇을 넣을 수 있습니까?

대답은 수업을 만들 수있는 것입니다.

그리고 수업을 만들 수있는 것은 무엇입니까?유형 또는 서브 클래스 또는 사용하는 모든 것.

파이썬 3의 메타 클래스

메타 클래스를 설정하는 구문이 파이썬 3에서 변경되었습니다.

class Foo(object, metaclass=something):
    ...

I.E.E. __metaclass__ 속성은 기본 클래스 목록의 키워드 인수에 유리하게 사용되지 않습니다.

메타 클래스의 행동은 크게 머물러 있습니다.

Python 3의 메타 클래스에 추가 된 것은 속성을 메타 클래스로 키워드 인수로 전달할 수 있다는 것입니다.

class Foo(object, metaclass=something, kwarg1=value1, kwarg2=value2):
    ...

Python이이를 처리하는 방법에 대해 아래 섹션을 읽으십시오.

맞춤 메타

메타 클래스의 주요 목적은 클래스를 자동으로 변경하는 것입니다. 생성 될 때.

일반적으로 API를 위해이 작업을 수행합니다. 현재 컨텍스트.

모듈의 모든 클래스가 결정을 결정하는 어리석은 예를 상상해보십시오. 속성이 대문자로 작성되어야합니다.몇 가지 방법이 있습니다 이렇게하려면 모듈 수준에서 __metaclass__을 한 가지 방법으로 설정하는 것입니다.

이렇게하면이 모듈의 모든 클래스 가이 메타 클래스를 사용하여 생성됩니다. 모든 속성을 대문자로 전환하도록 메타클래스에 알려야합니다.

운 좋게도, __metaclass__는 실제로 어떤 호출 할 수 없을 수 있습니다. 공식 수업 (나는 그 이름으로 '클래스'를 가진 뭔가가있을 필요가 없다. 클래스, Go Figure ... 그러나 도움이됩니다).

따라서 기능을 사용하여 간단한 예제로 시작합니다.

# the metaclass will automatically get passed the same argument
# that you usually pass to `type`
def upper_attr(future_class_name, future_class_parents, future_class_attrs):
    """
      Return a class object, with the list of its attribute turned
      into uppercase.
    """
    # pick up any attribute that doesn't start with '__' and uppercase it
    uppercase_attrs = {
        attr if attr.startswith("__") else attr.upper(): v
        for attr, v in future_class_attrs.items()
    }

    # let `type` do the class creation
    return type(future_class_name, future_class_parents, uppercase_attrs)

__metaclass__ = upper_attr # this will affect all classes in the module

class Foo(): # global __metaclass__ won't work with "object" though
    # but we can define __metaclass__ here instead to affect only this class
    # and this will work with "object" children
    bar = 'bip'

점검 해보자:

>>> hasattr(Foo, 'bar')
False
>>> hasattr(Foo, 'BAR')
True
>>> Foo.BAR
'bip'

이제 정확히 동일하게 해보도록 해보자 메타 클래스에 대한 실제 클래스를 사용하겠습니다.

# remember that `type` is actually a class like `str` and `int`
# so you can inherit from it
class UpperAttrMetaclass(type):
    # __new__ is the method called before __init__
    # it's the method that creates the object and returns it
    # while __init__ just initializes the object passed as parameter
    # you rarely use __new__, except when you want to control how the object
    # is created.
    # here the created object is the class, and we want to customize it
    # so we override __new__
    # you can do some stuff in __init__ too if you wish
    # some advanced use involves overriding __call__ as well, but we won't
    # see this
    def __new__(upperattr_metaclass, future_class_name,
                future_class_parents, future_class_attrs):
        uppercase_attrs = {
            attr if attr.startswith("__") else attr.upper(): v
            for attr, v in future_class_attrs.items()
        }
        return type(future_class_name, future_class_parents, uppercase_attrs)

위의 것을 다시 작성하겠습니다. 그러나 더 짧고 현실적인 변수 이름으로 이제 우리가 의미하는 것을 알고 있습니다.

class UpperAttrMetaclass(type):
    def __new__(cls, clsname, bases, attrs):
        uppercase_attrs = {
            attr if attr.startswith("__") else attr.upper(): v
            for attr, v in attrs.items()
        }
        return type(clsname, bases, uppercase_attrs)

당신은 여분의 인수 CLS를 알아 냈을 것입니다.있다 특별한 것은 없습니다. __new__ 항상 첫 번째 매개 변수로 정의 된 클래스를 항상받습니다.인스턴스가 첫 번째 매개 변수로 인스턴스를 수신하는 일반적인 방법 또는 클래스 메소드의 정의 클래스를 사용하는 것과 같습니다.

그러나 이것은 적절한 OOP이 아닙니다.우리는 직접 타입을 호출하고 부모의 __new__을 재정의하거나 호출하지 않습니다.대신 해보자 :

class UpperAttrMetaclass(type):
    def __new__(cls, clsname, bases, attrs):
        uppercase_attrs = {
            attr if attr.startswith("__") else attr.upper(): v
            for attr, v in attrs.items()
        }
        return type.__new__(cls, clsname, bases, uppercase_attrs)

우리는 슈퍼를 사용하여 클리너를 만들 수 있습니다. 이는 상속을 완화 할 수 있습니다 (예, 메타 클래스를 가져올 수 있으므로 메타 클래스를 상속받을 수 있으므로) :

class UpperAttrMetaclass(type):
    def __new__(cls, clsname, bases, attrs):
        uppercase_attrs = {
            attr if attr.startswith("__") else attr.upper(): v
            for attr, v in attrs.items()
        }
        return super(UpperAttrMetaclass, cls).__new__(
            cls, clsname, bases, uppercase_attrs)

오, 이와 같이 키워드 인수 로이 호출을 수행하면 Python 3입니다.

class Foo(object, metaclass=MyMetaclass, kwarg1=value1):
    ...

메타 클래스에서이를 사용하여이를 사용합니다.

class MyMetaclass(type):
    def __new__(cls, clsname, bases, dct, kwargs1=default):
        ...

그게 다야 해.메타 슬라스에는 정말로 아무 것도 없습니다.

메타 클래스를 사용하는 코드의 복잡성 뒤에있는 이유는 메타 클래스의 경우, 일반적으로 트위스트가있는 물건을 사용하기 위해 메타클스를 사용하기 때문입니다. 내성을 조작하고, __dict__ 등의 vars를 조작하고, introspection에 의존하고 있습니다.

실제로, 메타 류는 특히 흑인 마술을하는 것이 유용하므로 복잡한 물건.그러나 스스로는 간단합니다.

클래스 생성을 가로 챌 수 있습니다 클래스 수정 수정 된 클래스를 반환합니다

함수 대신 메타 클래스 클래스를 사용하겠습니까?

__metaclass__는 모든 호출 가능성을 수락 할 수 있으므로 클래스를 사용하겠습니까? 분명히 더 복잡하기 때문에?

그렇게해야 할 몇 가지 이유가 있습니다.

의도는 분명합니다.SportTryclass (유형)를 읽을 때 알고 있습니다. 무엇을 할 것인가? OOP를 사용할 수 있습니다.메타클래스는 메타클래스에서 상속받을 수 있으며 부모 메서드를 재정의합니다.메타 클래스는 Metaclasses를 사용할 수도 있습니다. Class의 하위 클래스는 메타 클래스 클래스를 지정했지만 메타 클래스 기능을 사용하지 않는 경우 메타클래스의 인스턴스가됩니다. 코드를 더 잘 구조화 할 수 있습니다.위의 예와 같이 사소한 것에 대해 메타 클래스를 사용하지 마십시오.그것은 대개 복잡한 것입니다.한 클래스에서 여러 가지 방법을 만들고 그룹화하는 기능을 갖는 코드를 쉽게 읽을 수있게하는 것이 매우 유용합니다. __new__, __init__ 및 __call__에 연결할 수 있습니다.보통 __new__에서 모든 것을 할 수 있더라도 다른 물건을 할 수 있습니다. 어떤 사람들은 __init__을 사용하여 더 편안합니다. 이들은 메타 클래스라고합니다.그것은 무언가를 의미해야합니다!

왜 메타 클래스를 사용하겠습니까?

이제 큰 질문.왜 소멸적인 오류가 발생하기 쉬운 기능을 사용합니까?

글쎄, 보통 당신은 다음을 수행하지 않습니다.

메타 클래스는 더 깊은 마술입니다 사용자의 99 %는 절대로 걱정할 필요가 없습니다. 당신이 그들을 필요로하는지 궁금해한다면, 당신은 (실제로 사람들을 만난 사람들) 그들을 확실하게 알 필요가있다 그들은 그들을 필요로하고, 필요하지 않습니다 그 이유에 대해서는 설명).

파이썬 구루 팀 피터스

메타 클래스의 주 사용 사례가 API를 생성합니다.이것의 전형적인 예는 Django orm입니다.이렇게하면 다음과 같이 정의 할 수 있습니다.

class Person(models.Model):
    name = models.CharField(max_length=30)
    age = models.IntegerField()

하지만 이렇게하면 :

person = Person(name='bob', age='35')
print(person.age)

IntegerField 객체를 반환하지 않습니다.int를 반환하고 데이터베이스에서 직접 가져갈 수도 있습니다.

이것은 모델이 __metaclass__와 정의하기 때문에 이것은 가능합니다 방금 정의한 사람을 간단한 진술로 바꿀 수있는 몇 가지 마술을 사용합니다. 데이터베이스 필드에 복잡한 후크로 연결됩니다.

Django는 단순한 API를 노출시킴으로써 복잡한 모양을 간단하게 만듭니다. 및 메타 클래스를 사용 하여이 API에서 코드를 다시 만들어 실제 작업을 수행하십시오. 무대 뒤에서.

마지막 단어

첫째, 클래스는 인스턴스를 만들 수있는 객체입니다.

실제로 수업은 자체적입니다.메타 클래스의

>>> class Foo(object): pass
>>> id(Foo)
142630324

모든 것은 파이썬의 객체이며 모든 클래스의 인스턴스 중 하나입니다. 또는 메타 클래스의 인스턴스.

유형을 제외하고.

유형은 실제로 자체 메타 클래스입니다.이것은 당신이 할 수있는 것이 아닙니다 순수한 파이썬에서 재현하고, 구현시 조금 부정함으로써 수행됩니다. 수준.

둘째, 메타 클래스가 복잡합니다.당신은 그들을 위해 사용하고 싶지 않을 수도 있습니다 매우 간단한 수업 변경.두 가지 기술을 사용하여 클래스를 변경할 수 있습니다.

원숭이 패치 클래스 데코레이터

99 %의 수업 변경이 필요한 시간, 당신은 이것들을 사용하는 것이 좋습니다.

그러나 시간의 98 %는 전혀 수업 수정이 필요하지 않습니다.



답변

메타 클래스는 클래스의 클래스입니다.클래스는 메타 클래스가 클래스가 작동하는 방식을 정의하는 동안 클래스 (즉, 객체)의 인스턴스가 작동하는 방식을 정의합니다.클래스는 메타 클래스의 인스턴스입니다.

파이썬에서는 메타 클래스 (Jerub 쇼)와 같은 임의의 호출자를 사용할 수 있지만, 더 나은 접근 방식은 실제 클래스 자체로 만드는 것입니다.유형은 파이썬의 일반적인 메타 클래스입니다.유형은 자체가 클래스이며 자체 유형입니다.당신은 파이썬에서 순수하게 타입과 같은 것을 재현 할 수 없지만 파이썬은 조금씩 속임수를 쓰지 않습니다.파이썬에서 자신의 메타클스를 만들려면 정말로 서브 클래스 유형을 원합니다.

메타 클래스는 클래스 공장으로 가장 일반적으로 사용됩니다.클래스를 호출하여 객체를 만들면 Python은 메타 클래스를 호출하여 'class'문을 실행할 때 새 클래스를 만듭니다.정상적인 __init__ 및 __new__ 메소드와 결합하여 메타 클래스는 새 레지스트리가있는 새 클래스를 등록하거나 클래스를 전적으로 전적으로 대체하는 것과 같은 클래스를 만들 때 클래스를 만들 때 '추가 사항'을 수행 할 수 있습니다.

클래스 문이 실행되면 Python은 먼저 클래스 문의 본문을 일반 코드 블록으로 실행합니다.결과 네임 스페이스 (Dict)는 클래스 - 투석의 속성을 유지합니다.메타클래스는 클래스 - 존재 (있는 경우) 또는 __metaclass__ 전역 변수의 __metaclass__ 속성에서 클래스 - 투 - 존재 (메타 클래스가 상속 된)의 바위를 조사하여 결정됩니다.메타 클래스는 클래스의 이름, 기지 및 속성을 인스턴스화하여 인스턴스화합니다.

그러나 Metaclasses는 실제로 공장이 아닌 클래스의 유형을 정의하므로 더 많은 것을 할 수 있습니다.예를 들어 메타 클래스에서 정상 메소드를 정의 할 수 있습니다.이러한 메타 클래스 - 메소드는 인스턴스가없는 클래스에서 호출 할 수있는 클래스 메테드와 같지만 클래스의 인스턴스에서 호출 할 수없는 클래스 메티드가 아닙니다.유형 .__ 하위 클래스 __ ()은 유형 메타 클래스의 메소드의 예입니다.__add__, __iter__ 및 __getattr__와 같은 일반적인 '마법'메소드를 정의하거나 클래스가 작동하는 방식을 구현하거나 변경할 수도 있습니다.

여기에는 비트와 조각의 집계 된 예가 있습니다.

def make_hook(f):
    """Decorator to turn 'foo' method into '__foo__'"""
    f.is_hook = 1
    return f

class MyType(type):
    def __new__(mcls, name, bases, attrs):

        if name.startswith('None'):
            return None

        # Go over attributes and see if they should be renamed.
        newattrs = {}
        for attrname, attrvalue in attrs.iteritems():
            if getattr(attrvalue, 'is_hook', 0):
                newattrs['__%s__' % attrname] = attrvalue
            else:
                newattrs[attrname] = attrvalue

        return super(MyType, mcls).__new__(mcls, name, bases, newattrs)

    def __init__(self, name, bases, attrs):
        super(MyType, self).__init__(name, bases, attrs)

        # classregistry.register(self, self.interfaces)
        print "Would register class %s now." % self

    def __add__(self, other):
        class AutoClass(self, other):
            pass
        return AutoClass
        # Alternatively, to autogenerate the classname as well as the class:
        # return type(self.__name__ + other.__name__, (self, other), {})

    def unregister(self):
        # classregistry.unregister(self)
        print "Would unregister class %s now." % self

class MyObject:
    __metaclass__ = MyType


class NoneSample(MyObject):
    pass

# Will print "NoneType None"
print type(NoneSample), repr(NoneSample)

class Example(MyObject):
    def __init__(self, value):
        self.value = value
    @make_hook
    def add(self, other):
        return self.__class__(self.value + other.value)

# Will unregister the class
Example.unregister()

inst = Example(10)
# Will fail with an AttributeError
#inst.unregister()

print inst + inst
class Sibling(MyObject):
    pass

ExampleSibling = Example + Sibling
# ExampleSibling is now a subclass of both Example and Sibling (with no
# content of its own) although it will believe it's called 'AutoClass'
print ExampleSibling
print ExampleSibling.__mro__


답변

이 답변은 Python 2.x가 2008 년에 작성된 것처럼 Metaclasses가 3.x에서 약간 다릅니다.

Metaclasses는 '수업'을 일하는 비밀 소스입니다.새 스타일 객체의 기본 메타클래스를 'type'이라고합니다.

class type(object)
  |  type(object) -> the object's type
  |  type(name, bases, dict) -> a new type

Metaclasses는 3 개의 args를 가져옵니다.'name', 'bases'와 'dict'

여기서 비밀이 시작되는 곳입니다.이 예제 클래스 정의에서 이름, 기지 및 Dict가 어디에서 왔는지 찾습니다.

class ThisIsTheName(Bases, Are, Here):
    All_the_code_here
    def doesIs(create, a):
        dict

'클래스 :'가 호출하는 방법을 보여주는 메타 클래스를 정의 할 수 있습니다.

def test_metaclass(name, bases, dict):
    print 'The Class Name is', name
    print 'The Class Bases are', bases
    print 'The dict has', len(dict), 'elems, the keys are', dict.keys()

    return "yellow"

class TestName(object, None, int, 1):
    __metaclass__ = test_metaclass
    foo = 1
    def baz(self, arr):
        pass

print 'TestName = ', repr(TestName)

# output => 
The Class Name is TestName
The Class Bases are (<type 'object'>, None, <type 'int'>, 1)
The dict has 4 elems, the keys are ['baz', '__module__', 'foo', '__metaclass__']
TestName =  'yellow'

그리고 이제 실제로 무언가를 의미하는 예제에서는 클래스에 설정된 "속성"목록의 변수를 자동으로 만들고 NONE으로 설정합니다.

def init_attributes(name, bases, dict):
    if 'attributes' in dict:
        for attr in dict['attributes']:
            dict[attr] = None

    return type(name, bases, dict)

class Initialised(object):
    __metaclass__ = init_attributes
    attributes = ['foo', 'bar', 'baz']

print 'foo =>', Initialised.foo
# output=>
foo => None

메타클래스 init_Attributes를 사용하여 이득을 초기화 한 마법의 동작은 초기화 된 서브 클래스에 전달되지 않습니다.

다음은 클래스가 생성 될 때 조치를 수행하는 메타클래스를 만들려면 '유형'을 하위 클래스하는 방법을 보여주는 더 많은 구체적인 예입니다.이것은 아주 까다 롭습니다.

class MetaSingleton(type):
    instance = None
    def __call__(cls, *args, **kw):
        if cls.instance is None:
            cls.instance = super(MetaSingleton, cls).__call__(*args, **kw)
        return cls.instance

class Foo(object):
    __metaclass__ = MetaSingleton

a = Foo()
b = Foo()
assert a is b


답변

다른 사람들은 Metaclasses가 작동하는 방식과 파이썬 유형 시스템에 어떻게 들어 있는지 설명했습니다.여기에 그들이 사용할 수있는 것의 예가 있습니다.내가 쓴 테스트 프레임 워크에서는, 나는 클래스가 정의 된 순서를 추적하고 싶었기 때문에 나중에이 순서로 인스턴스화 할 수 있습니다.메타 클래스를 사용 하여이 작업을 수행하는 것이 좋습니다.

class MyMeta(type):

    counter = 0

    def __init__(cls, name, bases, dic):
        type.__init__(cls, name, bases, dic)
        cls._order = MyMeta.counter
        MyMeta.counter += 1

class MyType(object):              # Python 2
    __metaclass__ = MyMeta

class MyType(metaclass=MyMeta):    # Python 3
    pass

MyType의 하위 클래스 인 것은 클래스가 정의 된 순서를 기록하는 클래스 속성 _Order를 가져옵니다.



답변

메타 클래스에 대한 하나의 사용은 자동으로 인스턴스에 새 속성과 메서드를 추가하는 것입니다.

예를 들어, Django 모델을 보면 정의가 조금 혼란스럽게 보입니다.마치 클래스 속성을 정의하는 것처럼 보입니다.

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

그러나 런타임에는 모든 종류의 유용한 메소드로 채워집니다.놀라운 Metaclassery의 소스를 참조하십시오.



답변

Metaclass 프로그래밍에 대한 onlamp 소개가 이미 작성되어 몇 년 된 몇 년이되었지만 주제에 대한 정말로 좋은 소개를 제공한다고 생각합니다.

http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html (https://web.archive.org/web/20080206005253/http://www.onlamp에서 아카이브 된)com / pub / a / python / 2003 / 04 / 17 / metaclasses.html)

짧게 : 클래스는 인스턴스를 만드는 청사진이며, 메타클래스는 클래스 생성을위한 청사진입니다.파이썬 클래스에서는이 동작을 가능하게하기 위해 Python 클래스에서도 일류 개체가 필요하다는 것을 쉽게 볼 수 있습니다.

나는 결코 나 자신을 쓴 적이 없지만 Django 프레임 워크에서는 메타클래스의 가장 좋은 용도 중 하나가 볼 수 있다고 생각합니다.모델 클래스는 새로운 모델이나 형식 클래스를 작성하는 선언적 스타일을 사용하도록 Metaclass 접근 방식을 사용합니다.메타 클래스가 클래스를 생성하는 동안 모든 회원은 클래스 자체를 사용자 정의 할 수 있습니다.

새 모델 만들기 메타 클래스를 사용할 수 있습니다

말하기 위해 남아있는 것은 다음과 같습니다. 메타 클래스가 무엇인지 모르는 경우, 필요하지 않은 확률은 99 %입니다.

출처:https://stackoverflow.com/questions/100003/what-are-metaclasses-in-python