programing

Python에서의 메타클래스는 무엇입니까?

goodsources 2023. 1. 13. 19:52
반응형

Python에서의 메타클래스는 무엇입니까?

메타클라스란?그것들은 무엇에 쓰입니까?

오브젝트로서의 클래스

메타클래스를 이해하기 전에 Python에서 클래스를 마스터해야 합니다.Python은 Smalltalk 언어를 차용한 클래스가 무엇인지에 대한 매우 독특한 생각을 가지고 있습니다.

대부분의 언어에서 클래스는 객체를 생성하는 방법을 설명하는 코드 조각일 뿐입니다.Python에서도 마찬가지입니다.

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

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

하지만 Python에서는 클래스가 그 이상입니다.수업도 객체입니다.

네, 오브젝트.

" " 를 하는 class, Python은 이것을 실행하고 오브젝트를 만듭니다.지시사항

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

、 creates creates creates creates creates creates creates creates creates with with with with with with with with with with with creates creates with with라는 에 만듭니다.ObjectCreator.

오브젝트(클래스) 자체는 오브젝트(인스턴스)를 작성할 수 있기 때문에 클래스입니다.

하지만 여전히 물건이기 때문에

  • 변수에 할당할 수 있습니다.
  • 복사할 수 있습니다.
  • Atribute를 추가할 수 있습니다.
  • 함수 매개 변수로 전달할 수 있습니다.

예:

>>> 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>

동적으로 클래스 만들기

클래스는 객체이기 때문에 다른 객체처럼 즉시 만들 수 있습니다.

이 수 .class:

>>> 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>

하지만 수업 전체를 직접 작성해야 하기 때문에 그다지 역동적이지 않습니다.

클래스는 객체이기 때문에 반드시 생성되어야 합니다.

「 」를하는 class워 python python python, Python python python python python python python python python python python python python python python python python python python python.그러나 Python의 대부분의 것과 마찬가지로, Python은 수동으로 실행할 수 있는 방법을 제공합니다.

을 기억하십시오.type을 알 수 「 」 、 「 」 、 「 」 。

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

전혀 다른 능력을 가지고 있어 즉석에서 수업을 만들 수도 있습니다. type는 클래스의 설명을 파라미터로 받아들여 클래스를 반환할 수 있습니다.

(알아요. 같은 기능이 전달되는 파라미터에 따라 완전히 다른 두 가지 용도를 가질 수 있다는 것은 어리석은 일입니다.Python의 하위 호환성으로 인해 문제가 발생하였습니다.

type뭇매를 맞다

type(name, bases, attrs)

장소:

  • name: 클래스 이름
  • : 부모 클래스의 태플bases(상속의 경우 비워둘 수 있음)
  • attrs: Attribute의 이름과 값을 포함하는 딕셔너리

예:

>>> 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클래스 이름 및 클래스 참조를 보유할 변수로 지정합니다.서로 다를 수 있지만 복잡하게 만들 이유는 없습니다.

type아트리뷰트 ★★★★★★★★★★★★★★★★:

>>> 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

Python에서는 클래스는 오브젝트이며 동적으로 클래스를 만들 수 있습니다.

은 Python이 키워드 Python을 사용할 때 입니다.class메타클래스를 사용하여 이를 수행합니다.

메타클라스란 무엇인가(최종)

메타클래스는 클래스를 만드는 물질이다.

오브젝트를 작성하기 위해 클래스를 정의합니다.

하지만 Python 클래스는 객체라는 것을 알게 되었습니다.

메타클라스가 이런 물체를 만들어 냅니다.이러한 클래스는 클래스의 클래스이며, 다음과 같이 생각할 수 있습니다.

MyClass = MetaClass()
my_object = MyClass()

도 봤잖아type할 수 요.

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

이 함수는 이 함수에 .type사실 메타클래스입니다. typePython이 백그라운드에서 모든 클래스를 만들기 위해 사용하는 메타클래스입니다.

왜 ?'라고 생각하실 .Type

요.str객체를 및 string " " " " " " " " " "int정수 개체를 만드는 클래스입니다. type클래스 오브젝트를 만드는 클래스입니다.

부분은 '아까운가 보다'를 알 수 있습니다.__class__여하하다

Python에서는 모든 것, 즉 모든 것이 객체입니다.여기에는 정수, 문자열, 함수 및 클래스가 포함됩니다.모두 물건입니다.모두 클래스에서 작성되었습니다.

>>> 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'>

메타클래스는 클래스 오브젝트를 만드는 재료입니다.

원하신다면 '클래스 공장'이라고 부르셔도 됩니다.

type는 Python이 사용하는 내장 메타클래스입니다만, 물론 독자적인 메타클래스를 작성할 수도 있습니다.

아트리뷰트

에서는 Python 2를 할 수 .__metaclass__Python 3 の 음음음음 음음 음음 음음 음음 음음 :

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

"Python"을 .Foo.

조심해, 그건 까다로워.

은 '아주머니'라고 씁니다.class Foo(object) 번째,단 클래스 오브젝트 " " " " " " " " " " "Foo아직 메모리에 생성되지 않았습니다.

은 Python을 .__metaclass__이치노시 클래스 됩니다.Foo않은 , 이는 "예", "예", "예"를 사용합니다type클래스를 만듭니다.

그걸 여러 번 읽으세요.

실행 시:

class Foo(Bar):
    pass

Python은 다음을 수행합니다.

__metaclass__에 귀속시키다.Foo

[Yes]라는의 인메모리 오브젝트를.Foo 되어 있는 __metaclass__.

이 Python을 수 없는 __metaclass__ 「」, 「」, 「 」__metaclass__동일한 작업을 시도합니다(단, 아무것도 상속되지 않은 클래스, 기본적으로 이전 스타일의 클래스만 해당).

만약 수 __metaclass__ 명령어는 아예 '''를 사용합니다.Bar 번째 부모)의 메타클래스(「」)일 수 )type를 만듭니다)의

하세요.__metaclass__되지 않습니다.(Attribute는 상속되지 .Bar.__class__가 됩니다아아아아아아아아아아아아아아아아아아아아아아아아아아!Bar를 사용하였습니다.__metaclass__를 작성한 Bartype() 아니다)type.__new__()이 .

, 큰 ,, 요, 신, 신, 신, 신, 신, 신, 신, 신, 신, 신, 신, 신, 신, now, now, now, now, now, now, now, now, now, , now, now, now__metaclass__

정답은 클래스를 만들 수 있는 것입니다.

그리고 무엇이 클래스를 만들 수 있을까요? type또는 서브클래스를 분류하거나 사용하는 모든 것.

Python 3의 메타클래스

메타클래스를 설정하기 위한 구문은 Python 3에서 변경되었습니다.

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

§,__metaclass__기본 클래스 목록에서 키워드 인수를 선호하기 위해 Atribute는 더 이상 사용되지 않습니다.

그러나 메타클래스의 동작은 대체로 동일하다.

Python 3의 메타클래스에 추가된 것 중 하나는 다음과 같이 속성을 키워드 인수로 메타클래스에 전달할 수도 있다는 것입니다.

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

Python이 이것을 처리하는 방법에 대해서는, 다음의 섹션을 참조해 주세요.

커스텀 메타클래스

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

보통 API에 대해 이 작업을 수행합니다.이 경우 현재 컨텍스트와 일치하는 클래스를 만들 수 있습니다.

모듈의 모든 클래스에서 속성을 대문자로 써야 한다고 결정하는 바보 같은 예를 상상해 보십시오.은 여러 , 한 가지 은 '이렇게 하다'를 설정하는 것입니다.__metaclass__모듈 레벨로 설정합니다.

이렇게 하면 이 모듈의 모든 클래스가 이 메타클래스를 사용하여 작성되므로 메타클래스에 모든 속성을 대문자로 변환하도록 지시해야 합니다.

좋게도 행행 luckily luckily.__metaclass__실제로 콜 가능, 정식 클래스일 필요는 없습니다(알아요, 이름에 '클래스'가 있는 것은 클래스일 필요는 없습니다.도움이 됩니다.)

간단한 예를 들어 함수를 사용해 보겠습니다.

# 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__는 항상 정의된 클래스를 첫 번째 파라미터로 수신합니다.이 있는 self인스턴스를 첫 번째 매개 변수로 수신하는 일반 메서드의 경우 또는 클래스 메서드의 정의 클래스를 지정합니다.

OOP하다를 드리다type것이 .__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)

하면 더 수 있어요.super상속이 용이해집니다(그렇기 때문에 메타클라스에서 상속하고 유형에서 상속하는 메타클래스를 가질 수 있습니다).

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__ 등등.

실제로 메타클래스는 흑마술을 부리는데 특히 유용하며, 따라서 복잡한 것들을 할 수 있습니다.하지만 그것만으로는 간단합니다.

  • 학급 창설을 방해하다
  • 클래스를 수정하다
  • 수정된 클래스를 반환하다

함수 대신 메타클래스 클래스를 사용하는 이유는 무엇입니까?

★★__metaclass__어떤 호출도 받아들일 수 있는데, 분명 더 복잡한데 왜 수업을 쓰겠어요?

여기에는 몇 가지 이유가 있습니다.

  • 도는분분 분분분다다을을 때UpperAttrMetaclass(type)으로 일이 일어날지 알
  • OOP를 사용할 수 있습니다.메타클래스는 메타클래스에서 상속할 수 있으며 상위 메서드를 재정의할 수 있습니다.메타클라스는 메타클라스를 사용할 수도 있습니다.
  • 메타클래스 클래스를 지정한 경우 클래스의 서브클래스는 메타클래스 함수가 아닌 메타클래스의 인스턴스가 됩니다.
  • 코드를 더 잘 구성할 수 있습니다.위의 예와 같은 사소한 일에는 메타클래스를 사용하지 않습니다.보통은 복잡한 걸 위한 거야여러 개의 메서드를 만들어 하나의 클래스로 그룹화할 수 있는 기능은 코드를 읽기 쉽게 만드는 데 매우 유용합니다.
  • 할 수 .__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데이터베이스에서 직접 가져올 수도 있습니다.

은, 「 」가 있기 때문에 합니다.models.Model 정의하다__metaclass__ '마법'을 Person단순한 문장으로 데이터베이스 필드에 대한 복잡한 후크로 정의했습니다.

Django는 간단한 API를 공개하고 메타클래스를 사용하여 이 API에서 코드를 재작성하여 배후에서 실제 작업을 수행함으로써 복잡한 것을 단순하게 보이게 합니다.

마지막 말

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

음, 사실 수업 자체가 하나의 사례입니다.메타클라스.

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

Python에서는 모든 것이 객체이며 모두 클래스의 인스턴스 또는 메타클래스의 인스턴스입니다.

type.

type이치노이것은 순수 Python에서는 재현할 수 없는 것으로, 실장 레벨에서 조금 부정행위를 하는 것으로 실현됩니다.

둘째, 메타클래스는 복잡합니다.간단한 클래스 변경에는 사용하지 않을 수도 있습니다.클래스를 변경하려면 다음 두 가지 방법을 사용합니다.

99%는 클래스 변경이 필요할 때 사용하는 것이 좋습니다.

하지만 98%의 경우 수업 변경이 전혀 필요하지 않습니다.

메타클래스는 클래스의 클래스입니다.클래스는 클래스의 인스턴스(즉, 객체)가 어떻게 동작하는지를 정의하는 반면 메타클래스는 클래스의 동작을 정의합니다.클래스는 메타클래스의 인스턴스입니다.

Python에서는 메타클래스에 임의의 콜러블을 사용할 수 있지만(Jerub 쇼 등), 실제 클래스 자체를 만드는 것이 더 좋은 방법입니다. typePython ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★. type그 자체가 클래스이고, 그 자체의 타입입니다.type파이썬 Python을 서브클래스하고 입니다.type.

메타클래스는 클래스 팩토리로 가장 일반적으로 사용됩니다.클래스를 호출하여 개체를 만들면 Python은 메타클래스를 호출하여 새 클래스를 만듭니다('class' 문을 실행할 때). normal준 the the the the the the __init__ ★★★★★★★★★★★★★★★★★」__new__메서드, 메타클래스에서는 클래스를 만들 때 새 클래스를 일부 레지스트리에 등록하거나 클래스를 완전히 다른 것으로 대체할 수 있습니다.

?class합니다. 파이썬class일반적인 코드 블록으로서 스테이트먼트를 설정합니다.결과 네임스페이스(dict)에는 다음 클래스의 속성이 저장됩니다.됩니다.__metaclass__) "Class-to-be"(존재하는 경우)의 어트리뷰트__metaclass__그런 다음 메타클래스를 클래스의 이름, 기본 및 속성과 함께 호출하여 인스턴스화합니다.

그러나 메타클래스는 실제로 클래스 유형을 정의하며, 단순한 공장이 아닙니다. 따라서 메타클래스로 훨씬 더 많은 작업을 수행할 수 있습니다.예를 들어 메타클래스에 일반 메서드를 정의할 수 있습니다.이러한 메타클래스 메서드는 인스턴스 없이 클래스에서 호출할 수 있다는 점에서 클래스 메서드와 비슷하지만 클래스의 인스턴스에서는 호출할 수 없다는 점에서 클래스 메서드와는 다릅니다. type.__subclasses__(), 에 를 나타냅니다.type또한 '마법이라는 일반적'마법'도 정의.__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__

참고로 이 답변은 2008년에 작성된 Python 2.x에 대한 것입니다. 메타클래스는 3.x에서 약간 다릅니다.

메타클래스는 '클래스'를 작동시키는 비밀 소스이다.새 스타일 객체의 기본 메타클래스를 'type'이라고 합니다.

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

메타클래스는 3알이 필요합니다.'name', 'filename', 'filename'

여기서부터 비밀이 시작된다.이 클래스 정의 예에서 이름, 기본 및 dict의 출처를 찾습니다.

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

'class:'가 어떻게 호출하는지를 보여주는 메타클래스를 정의합니다.

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'

여기서 실제로 의미가 있는 예에서는 목록에 있는 변수가 자동으로 클래스에 설정된 "속성"이 되고 "없음"으로 설정됩니다.

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

「」의 마술 에 .Initialised메타클래스()를 수 .init_attributes is is of of of of of of의 하위 Initialised.

보다 구체적인 예를 들어 'type'을 하위 분류하여 클래스를 만들 때 작업을 수행하는 메타클래스를 만드는 방법을 보여 줍니다.이것은 꽤 까다롭습니다.

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

다른 사람들은 메타클래스가 어떻게 작동하며 파이썬 타입 시스템에 어떻게 장착되는지 설명했습니다.다음은 사용 가능한 용도의 예입니다.제가 작성한 테스트 프레임워크에서는 클래스가 정의된 순서를 추적하여 나중에 이 순서로 인스턴스화할 수 있도록 하고 싶었습니다.메타클래스를 사용하는 것이 가장 쉬웠습니다.

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이치노

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

를 들어, 장고 모델을 보면, 그 정의는 약간 혼란스러워 보여요.클래스 속성만 정의하고 있는 것처럼 보입니다.

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

그러나 실행 시 Person 객체는 유용한 모든 종류의 메서드로 채워집니다.놀라운 메타클래시리를 보려면 소스를 참조하십시오.

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) 에서 입수 가능)

즉, 클래스는 인스턴스 작성용 Blueprint이고 메타클래스는 클래스 작성용 Blueprint입니다.Python 클래스는 이 동작을 활성화하기 위해 퍼스트 클래스 오브젝트여야 한다는 것을 쉽게 알 수 있습니다.

제가 직접 쓴 적은 없지만 메타클래스의 가장 좋은 사용법 중 하나는 장고 틀에서 볼 수 있을 것 같아요.모델 클래스는 메타클래스 방식을 사용하여 새 모델을 작성하거나 클래스를 형성하는 선언적 스타일을 활성화합니다.메타클래스가 클래스를 만드는 동안 모든 구성원은 클래스 자체를 사용자 정의할 수 있습니다.

남은 말은 다음과 같습니다.메타클라스가 무엇인지 모를 경우 메타클라스가 필요하지 않을 확률은 99%입니다.

메타클라스란?그것들은 어디에 쓰나요?

TLDR: 메타클래스는 클래스가 인스턴스의 동작을 인스턴스화하고 정의하는 것과 마찬가지로 클래스의 동작을 인스턴스화하고 정의합니다.

유사 코드:

>>> Class(...)
instance

위의 내용은 익숙한 내용이어야 합니다. 그럼 ''는요?Class★★★★★★★★★★★★★★★★★?이것은 메타클래스 인스턴스(의사코드이기도 합니다)입니다.

>>> Metaclass(...)
Class

코드에서는 메타클래스인 "를 할 수 .type수업을 인스턴스화하고 수업을 받는 데 필요한 모든 것:

>>> type('Foo', (object,), {}) # requires a name, bases, and a namespace
<class '__main__.Foo'>

다르게 말하면

  • 클래스는 인스턴스와 메타클래스와 클래스와 같습니다.

    개체를 인스턴스화하면 다음과 같은 인스턴스가 생성됩니다.

    >>> object()                          # instantiation of class
    <object object at 0x7f9069b4e0b0>     # instance
    

    으로 클래스를 하면, 「」가 됩니다.type★★★★★★★★★★★★★★★★★★:

    >>> type('Object', (object,), {})     # instantiation of metaclass
    <class '__main__.Object'>             # instance
    
  • 바꿔 말하면 클래스는 메타클래스의 인스턴스입니다.

    >>> isinstance(object, type)
    True
    
  • 세 번째 방법으로 메타클래스는 클래스의 클래스입니다.

    >>> type(object) == type
    True
    >>> object.__class__
    <class 'type'>
    

클래스 정의를 작성하고 Python이 실행하면 메타클래스를 사용하여 클래스 개체를 인스턴스화합니다(이 개체는 해당 클래스의 인스턴스를 인스턴스화하는 데 사용됩니다).

클래스 정의를 사용하여 커스텀오브젝트 인스턴스의 동작을 변경할 수 있듯이 메타클래스 클래스 정의를 사용하여 클래스 오브젝트의 동작 방법을 변경할 수 있습니다.

그것들은 무엇에 사용될 수 있나요?문서에서:

메타클래스의 잠재적인 용도는 무궁무진합니다.지금까지 살펴본 아이디어로는 로깅, 인터페이스 검사, 자동 위임, 자동 속성 생성, 프록시, 프레임워크 및 자동 리소스 잠금/동기화가 있습니다.

단, 반드시 필요한 경우가 아니면 메타클래스를 사용하지 않는 것이 좋습니다.

클래스를 만들 때마다 메타클래스를 사용합니다.

예를 들어, 클래스 정의를 작성할 때,

class Foo(object): 
    'demo'

클래스 개체를 인스턴스화합니다.

>>> Foo
<class '__main__.Foo'>
>>> isinstance(Foo, type), isinstance(Foo, object)
(True, True)

은 기능적으로 '부르다'라고 부르는 것과 .type적절한 인수를 지정하고 결과를 해당 이름의 변수에 할당합니다.

name = 'Foo'
bases = (object,)
namespace = {'__doc__': 'demo'}
Foo = type(name, bases, namespace)

어떤 .__dict__「 」 「 」 、 「 」

>>> Foo.__dict__
dict_proxy({'__dict__': <attribute '__dict__' of 'Foo' objects>, 
'__module__': '__main__', '__weakref__': <attribute '__weakref__' 
of 'Foo' objects>, '__doc__': 'demo'})

두 경우 모두 작성한 객체의 메타클래스는 다음과 같습니다.type

(부기))__dict____module__되어 있는 를 알아야 하기 에 존재하는 또, 「클래스는 정의되어 않습니다.__dict__ ★★★★★★★★★★★★★★★★★」__weakref__에 존재하는 입니다.__slots__- 정의하면 instance에서 공간을 조금 절약할 수 있습니다.__dict__ ★★★★★★★★★★★★★★★★★」__weakref__외함함제예를 들어 다음과 같습니다.

>>> Baz = type('Bar', (object,), {'__doc__': 'demo', '__slots__': ()})
>>> Baz.__dict__
mappingproxy({'__doc__': 'demo', '__slots__': (), '__module__': '__main__'})

...하지만 난 딴 데로 돌린다.)

연장할 수 요.type다른 클래스 정의와 마찬가지로 다음과 같습니다.

설정입니다.__repr__★★★★★★★★★★★★★★★★★★:

>>> Foo
<class '__main__.Foo'>

를 작성할 때 으로 할 수 가장 중 Python 객체를 입니다.__repr__ 「 」를 했을 때help(repr).__repr__합니다. - 동등성 테스트입니다.obj == eval(repr(obj)) 구현.__repr__ ★★★★★★★★★★★★★★★★★」__eq__는, 의 「Default」를 할 수 합니다.__repr__★★★★★★★★★★★★★★★★★★:

class Type(type):
    def __repr__(cls):
        """
        >>> Baz
        Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None})
        >>> eval(repr(Baz))
        Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None})
        """
        metaname = type(cls).__name__
        name = cls.__name__
        parents = ', '.join(b.__name__ for b in cls.__bases__)
        if parents:
            parents += ','
        namespace = ', '.join(': '.join(
          (repr(k), repr(v) if not isinstance(v, type) else v.__name__))
               for k, v in cls.__dict__.items())
        return '{0}(\'{1}\', ({2}), {{{3}}})'.format(metaname, name, parents, namespace)
    def __eq__(cls, other):
        """
        >>> Baz == eval(repr(Baz))
        True            
        """
        return (cls.__name__, cls.__bases__, cls.__dict__) == (
                other.__name__, other.__bases__, other.__dict__)

메타클래스를하면, 「 」는 「 」로 됩니다.__repr__명령줄에 에코된 화면은 기본값보다 훨씬 덜 흉측합니다.

>>> class Bar(object): pass
>>> Baz = Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None})
>>> Baz
Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None})

★★★★★★★★★★★★★★★.__repr__클래스 인스턴스용으로 정의되어 있기 때문에 코드를 디버깅할 수 있는 기능이 강화되어 있습니다. 지지 with with에서 더 자세히 하겠습니다.eval(repr(Class))이 디폴트(기본값)에서는 거의 없습니다.__repr__의 경우)

다음 중 하나:__prepare__

예를 들어 클래스의 메서드가 어떤 순서로 작성되었는지 알고 싶다면 클래스의 네임스페이스로 순서가 매겨진 dict를 제공할 수 있습니다.이렇게 하면__prepare__Python 3에 구현되어 있는 경우 클래스의 이름 공간 dict를 반환합니다.

from collections import OrderedDict

class OrderedType(Type):
    @classmethod
    def __prepare__(metacls, name, bases, **kwargs):
        return OrderedDict()
    def __new__(cls, name, bases, namespace, **kwargs):
        result = Type.__new__(cls, name, bases, dict(namespace))
        result.members = tuple(namespace)
        return result

용도:

class OrderedMethodsObject(object, metaclass=OrderedType):
    def method1(self): pass
    def method2(self): pass
    def method3(self): pass
    def method4(self): pass

다음으로 다음 메서드(및 기타 클래스 속성)가 작성된 순서에 대한 기록이 있습니다.

>>> OrderedMethodsObject.members
('__module__', '__qualname__', 'method1', 'method2', 'method3', 'method4')

이 예는 매뉴얼에서 수정한 것입니다.표준 라이브러리의 새로운 열거형이 이를 수행합니다.

그래서 우리는 클래스를 만들어서 메타클래스를 인스턴스화했습니다.메타클래스도 다른 클래스처럼 취급할 수 있습니다.방법 해결 순서가 있습니다.

>>> inspect.getmro(OrderedType)
(<class '__main__.OrderedType'>, <class '__main__.Type'>, <class 'type'>, <class 'object'>)

거의 말이 있어요.repr어느쪽이든 상관없다).

>>> OrderedMethodsObject
OrderedType('OrderedMethodsObject', (object,), {'method1': <function OrderedMethodsObject.method1 at 0x0000000002DB01E0>, 'members': ('__module__', '__qualname__', 'method1', 'method2', 'method3', 'method4'), 'method3': <function OrderedMet
hodsObject.method3 at 0x0000000002DB02F0>, 'method2': <function OrderedMethodsObject.method2 at 0x0000000002DB0268>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'OrderedMethodsObject' objects>, '__doc__': None, '__d
ict__': <attribute '__dict__' of 'OrderedMethodsObject' objects>, 'method4': <function OrderedMethodsObject.method4 at 0x0000000002DB0378>})

Python 3 업데이트

메타클래스에는 (이 시점에서) 다음 두 가지 주요 방법이 있습니다.

  • __prepare__ , 그리고.
  • __new__

__prepare__맵핑(「」등을할 수 .OrderedDict클래스 작성 중에 네임스페이스로 사용됩니다.선택한 네임스페이스의 인스턴스를 반환해야 합니다.「 를 실장하지 않는 __prepare__ 사람dict용됩니니다다

__new__최종 클래스의 실제 작성/변경을 담당합니다.

아무것도 하지 않는 베어본 메타클래스는 다음과 같은 특징이 있습니다.

class Meta(type):

    def __prepare__(metaclass, cls, bases):
        return dict()

    def __new__(metacls, cls, bases, clsdict):
        return super().__new__(metacls, cls, bases, clsdict)

간단한 예:

속성에서 실행할 간단한 검증 코드를 원한다고 가정해 보겠습니다.확인 코드 확인 코드 확인 코드 확인.int ★★★str메타클래스가 없으면 클래스는 다음과 같습니다.

class Person:
    weight = ValidateType('weight', int)
    age = ValidateType('age', int)
    name = ValidateType('name', str)

보시는 바와 같이 Atribute의 이름을 2회 반복해야 합니다.이것은 오타를 자극적인 버그와 함께 가능하게 합니다.

단순한 메타클래스로 이 문제를 해결할 수 있습니다.

class Person(metaclass=Validator):
    weight = ValidateType(int)
    age = ValidateType(int)
    name = ValidateType(str)

예요.__prepare__('이러한마디로)

class Validator(type):
    def __new__(metacls, cls, bases, clsdict):
        # search clsdict looking for ValidateType descriptors
        for name, attr in clsdict.items():
            if isinstance(attr, ValidateType):
                attr.name = name
                attr.attr = '_' + name
        # create final class and return it
        return super().__new__(metacls, cls, bases, clsdict)

다음 샘플 실행:

p = Person()
p.weight = 9
print(p.weight)
p.weight = '9'

생산:

9
Traceback (most recent call last):
  File "simple_meta.py", line 36, in <module>
    p.weight = '9'
  File "simple_meta.py", line 24, in __set__
    (self.name, self.type, value))
TypeError: weight must be of type(s) <class 'int'> (got '9')

주의: 이 예는 클래스 데코레이터로도 충분히 간단하지만 실제 메타클래스는 훨씬 더 많은 작업을 수행할 수 있습니다.

'검증'참조할 Type' 클래스:

class ValidateType:
    def __init__(self, type):
        self.name = None  # will be set by metaclass
        self.attr = None  # will be set by metaclass
        self.type = type
    def __get__(self, inst, cls):
        if inst is None:
            return self
        else:
            return inst.__dict__[self.attr]
    def __set__(self, inst, value):
        if not isinstance(value, self.type):
            raise TypeError('%s must be of type(s) %s (got %r)' %
                    (self.name, self.type, value))
        else:
            inst.__dict__[self.attr] = value

__call__()

Python 프로그래밍을 몇 달 이상 실행했다면 다음과 같은 코드를 발견할 수 있을 것입니다.

# define a class
class SomeClass(object):
    # ...
    # some definition here ...
    # ...

# create an instance of it
instance = SomeClass()

# then call the object as if it's a function
result = instance('foo', 'bar')

는 '어느 정도', '어느 정도', '어느 정도'를 할 때 합니다.__call__()수업의 마술 방법.

class SomeClass(object):
    # ...
    # some definition here ...
    # ...

    def __call__(self, foo, bar):
        return bar + foo

__call__()method는 클래스의 인스턴스가 콜 가능으로 사용될 때 호출됩니다. 이전 수 를 콜으로 사용할 때(즉, 실제로 메타클래스를 합니다.__call__() 에서 대부분의 이와 같은 인스턴스Python을 생성한다는 약간 .왜냐하면 그들은 이런 인스턴스를 만들 때instance = SomeClass()그것을 '오빠'라고 .__init__()조금 전에 알고 거예요.__init__()__new__()은 또 의 층이 그 전에.__new__()__call__().

메서드 콜 체인에 대해 구체적으로 클래스의 인스턴스를 만드는 관점에서 살펴보겠습니다.

이것은 인스턴스가 생성되기 전 및 인스턴스가 반환되기 직전까지 정확하게 기록되는 메타클래스입니다.

class Meta_1(type):
    def __call__(cls):
        print "Meta_1.__call__() before creating an instance of ", cls
        instance = super(Meta_1, cls).__call__()
        print "Meta_1.__call__() about to return instance."
        return instance

이것은 메타클래스를 사용하는 클래스입니다.

class Class_1(object):

    __metaclass__ = Meta_1

    def __new__(cls):
        print "Class_1.__new__() before creating an instance."
        instance = super(Class_1, cls).__new__(cls)
        print "Class_1.__new__() about to return instance."
        return instance

    def __init__(self):
        print "entering Class_1.__init__() for instance initialization."
        super(Class_1,self).__init__()
        print "exiting Class_1.__init__()."

에는 ''의 Class_1

instance = Class_1()
# Meta_1.__call__() before creating an instance of <class '__main__.Class_1'>.
# Class_1.__new__() before creating an instance.
# Class_1.__new__() about to return instance.
# entering Class_1.__init__() for instance initialization.
# exiting Class_1.__init__().
# Meta_1.__call__() about to return instance.

위의 코드는 실제로 작업을 기록하는 것 이상을 수행하지 않습니다.각 메서드는 실제 작업을 부모 구현에 위임하여 기본 동작을 유지합니다.★★typeMeta_1클래스type 메타클래스)및했을 때, 「」의 의사 실장이 알수.type.__call__():

class type:
    def __call__(cls, *args, **kwarg):

        # ... maybe a few things done to cls here

        # then we call __new__() on the class to create an instance
        instance = cls.__new__(cls, *args, **kwargs)

        # ... maybe a few things done to the instance here

        # then we initialize the instance with its __init__() method
        instance.__init__(*args, **kwargs)

        # ... maybe a few more things done to instance here

        # then we return it
        return instance

의 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★」__call__()이치노음음음음음 음음음음 음 the음 the the the the the the the the the the에 합니다.__new__()__init__()또한 최종적으로 인스턴스를 반환하는 것이기도 합니다.

위에서 보면 메타클래스는__call__()에는, 「 」, 「 」, 「 」, 「 」에의 콜의 유무도 .Class_1.__new__() ★★★★★★★★★★★★★★★★★」Class_1.__init__()결국 만들어질 것이다.실행 과정에서 실제로 이러한 방법 중 어느 것도 건드리지 않은 개체를 반환할 수 있습니다.싱글톤 패턴에 대해서, 다음의 어프로치를 채용합니다.

class Meta_2(type):
    singletons = {}

    def __call__(cls, *args, **kwargs):
        if cls in Meta_2.singletons:
            # we return the only instance and skip a call to __new__()
            # and __init__()
            print ("{} singleton returning from Meta_2.__call__(), "
                   "skipping creation of new instance.".format(cls))
            return Meta_2.singletons[cls]

        # else if the singleton isn't present we proceed as usual
        print "Meta_2.__call__() before creating an instance."
        instance = super(Meta_2, cls).__call__(*args, **kwargs)
        Meta_2.singletons[cls] = instance
        print "Meta_2.__call__() returning new instance."
        return instance

class Class_2(object):

    __metaclass__ = Meta_2

    def __new__(cls, *args, **kwargs):
        print "Class_2.__new__() before creating instance."
        instance = super(Class_2, cls).__new__(cls)
        print "Class_2.__new__() returning instance."
        return instance

    def __init__(self, *args, **kwargs):
        print "entering Class_2.__init__() for initialization."
        super(Class_2, self).__init__()
        print "exiting Class_2.__init__()."

이렇게 으로 '만들다'의 할 때 해 보겠습니다Class_2

a = Class_2()
# Meta_2.__call__() before creating an instance.
# Class_2.__new__() before creating instance.
# Class_2.__new__() returning instance.
# entering Class_2.__init__() for initialization.
# exiting Class_2.__init__().
# Meta_2.__call__() returning new instance.

b = Class_2()
# <class '__main__.Class_2'> singleton returning from Meta_2.__call__(), skipping creation of new instance.

c = Class_2()
# <class '__main__.Class_2'> singleton returning from Meta_2.__call__(), skipping creation of new instance.

a is b is c # True

A metaclass는 (일부) 다른 클래스를 만드는 방법을 알려주는 클래스입니다.

은 가 본 입니다.metaclass으로서: 는 다른 할 수 매우 문제를 , 을 「다음에」를해결하기로 했다.metaclass복잡하기 때문에 모듈 내의 코멘트가 코드 작성량을 초과하는 몇 안 되는 모듈 중 하나입니다.기기있있있있다다

#!/usr/bin/env python

# Copyright (C) 2013-2014 Craig Phillips.  All rights reserved.

# This requires some explaining.  The point of this metaclass excercise is to
# create a static abstract class that is in one way or another, dormant until
# queried.  I experimented with creating a singlton on import, but that did
# not quite behave how I wanted it to.  See now here, we are creating a class
# called GsyncOptions, that on import, will do nothing except state that its
# class creator is GsyncOptionsType.  This means, docopt doesn't parse any
# of the help document, nor does it start processing command line options.
# So importing this module becomes really efficient.  The complicated bit
# comes from requiring the GsyncOptions class to be static.  By that, I mean
# any property on it, may or may not exist, since they are not statically
# defined; so I can't simply just define the class with a whole bunch of
# properties that are @property @staticmethods.
#
# So here's how it works:
#
# Executing 'from libgsync.options import GsyncOptions' does nothing more
# than load up this module, define the Type and the Class and import them
# into the callers namespace.  Simple.
#
# Invoking 'GsyncOptions.debug' for the first time, or any other property
# causes the __metaclass__ __getattr__ method to be called, since the class
# is not instantiated as a class instance yet.  The __getattr__ method on
# the type then initialises the class (GsyncOptions) via the __initialiseClass
# method.  This is the first and only time the class will actually have its
# dictionary statically populated.  The docopt module is invoked to parse the
# usage document and generate command line options from it.  These are then
# paired with their defaults and what's in sys.argv.  After all that, we
# setup some dynamic properties that could not be defined by their name in
# the usage, before everything is then transplanted onto the actual class
# object (or static class GsyncOptions).
#
# Another piece of magic, is to allow command line options to be set in
# in their native form and be translated into argparse style properties.
#
# Finally, the GsyncListOptions class is actually where the options are
# stored.  This only acts as a mechanism for storing options as lists, to
# allow aggregation of duplicate options or options that can be specified
# multiple times.  The __getattr__ call hides this by default, returning the
# last item in a property's list.  However, if the entire list is required,
# calling the 'list()' method on the GsyncOptions class, returns a reference
# to the GsyncListOptions class, which contains all of the same properties
# but as lists and without the duplication of having them as both lists and
# static singlton values.
#
# So this actually means that GsyncOptions is actually a static proxy class...
#
# ...And all this is neatly hidden within a closure for safe keeping.
def GetGsyncOptionsType():
    class GsyncListOptions(object):
        __initialised = False

    class GsyncOptionsType(type):
        def __initialiseClass(cls):
            if GsyncListOptions._GsyncListOptions__initialised: return

            from docopt import docopt
            from libgsync.options import doc
            from libgsync import __version__

            options = docopt(
                doc.__doc__ % __version__,
                version = __version__,
                options_first = True
            )

            paths = options.pop('<path>', None)
            setattr(cls, "destination_path", paths.pop() if paths else None)
            setattr(cls, "source_paths", paths)
            setattr(cls, "options", options)

            for k, v in options.iteritems():
                setattr(cls, k, v)

            GsyncListOptions._GsyncListOptions__initialised = True

        def list(cls):
            return GsyncListOptions

        def __getattr__(cls, name):
            cls.__initialiseClass()
            return getattr(GsyncListOptions, name)[-1]

        def __setattr__(cls, name, value):
            # Substitut option names: --an-option-name for an_option_name
            import re
            name = re.sub(r'^__', "", re.sub(r'-', "_", name))
            listvalue = []

            # Ensure value is converted to a list type for GsyncListOptions
            if isinstance(value, list):
                if value:
                    listvalue = [] + value
                else:
                    listvalue = [ None ]
            else:
                listvalue = [ value ]

            type.__setattr__(GsyncListOptions, name, listvalue)

    # Cleanup this module to prevent tinkering.
    import sys
    module = sys.modules[__name__]
    del module.__dict__['GetGsyncOptionsType']

    return GsyncOptionsType

# Our singlton abstract proxy class.
class GsyncOptions(object):
    __metaclass__ = GetGsyncOptionsType()

tl;dr 버전

type(obj)함수는 객체의 유형을 가져옵니다.

type()메타클래스입니다.

메타클래스를 사용하려면:

class Foo(object):
    __metaclass__ = MyMetaClass

type자체 메타클래스입니다.이치노클래스의 본문은 클래스를 구축하는 데 사용되는 메타클래스에 전달되는 인수입니다.

여기서 메타클래스를 사용하여 클래스 구성을 사용자 정의하는 방법을 읽을 수 있습니다.

type는 '아예'입니다.metaclass.--- 다른 클래스를 만듭니다. 많이요.metaclass입니다.type . 。metaclass을 받다new첫합니다.class 를 、 첫째 、 class 、 음음 、 class 、 class 음음 class class class class 。

>>> class MetaClass(type):
...     def __init__(cls, name, bases, attrs):
...         print ('class name: %s' %name )
...         print ('Defining class %s' %cls)
...         print('Bases %s: ' %bases)
...         print('Attributes')
...         for (name, value) in attrs.items():
...             print ('%s :%r' %(name, value))
... 

>>> class NewClass(object, metaclass=MetaClass):
...    get_choch='dairy'
... 
class name: NewClass
Bases <class 'object'>: 
Defining class <class 'NewClass'>
get_choch :'dairy'
__module__ :'builtins'
__qualname__ :'NewClass'

Note:

, 「」의 됩니다.클래스를 만드는 간단한 동작에 의해, 의 실행이 트리거 됩니다.metaclass.

Python 클래스는 메타 클래스의 개체입니다(예:

클래스를 다음과 같이 결정할 때 적용되는 기본 메타 클래스입니다.

class foo:
    ...

meta 클래스는 일부 규칙을 클래스 전체에 적용하기 위해 사용됩니다.예를 들어 데이터베이스에 액세스하기 위해 ORM을 구축하고 각 테이블의 레코드를 해당 테이블에 매핑하는 클래스(필드, 비즈니스 규칙 등)로 할 경우 메타클래스를 사용할 수 있습니다.예를 들어 접속 풀 로직은 모든 테이블의 모든 레코드 클래스에서 공유됩니다.또 다른 용도는 여러 클래스의 레코드가 포함된 외부 키를 지원하는 로직입니다.

메타클래스를 정의할 때 하위 클래스 유형으로, 다음 매직 메서드를 재정의하여 논리를 삽입할 수 있습니다.

class somemeta(type):
    __new__(mcs, name, bases, clsdict):
      """
  mcs: is the base metaclass, in this case type.
  name: name of the new class, as provided by the user.
  bases: tuple of base classes 
  clsdict: a dictionary containing all methods and attributes defined on class

  you must return a class object by invoking the __new__ constructor on the base metaclass. 
 ie: 
    return type.__call__(mcs, name, bases, clsdict).

  in the following case:

  class foo(baseclass):
        __metaclass__ = somemeta

  an_attr = 12

  def bar(self):
      ...

  @classmethod
  def foo(cls):
      ...

      arguments would be : ( somemeta, "foo", (baseclass, baseofbase,..., object), {"an_attr":12, "bar": <function>, "foo": <bound class method>}

      you can modify any of these values before passing on to type
      """
      return type.__call__(mcs, name, bases, clsdict)


    def __init__(self, name, bases, clsdict):
      """ 
      called after type has been created. unlike in standard classes, __init__ method cannot modify the instance (cls) - and should be used for class validaton.
      """
      pass


    def __prepare__():
        """
        returns a dict or something that can be used as a namespace.
        the type will then attach methods and attributes from class definition to it.

        call order :

        somemeta.__new__ ->  type.__new__ -> type.__init__ -> somemeta.__init__ 
        """
        return dict()

    def mymethod(cls):
        """ works like a classmethod, but for class objects. Also, my method will not be visible to instances of cls.
        """
        pass

어쨌든, 이 두 가지는 가장 일반적으로 사용되는 후크입니다. 메타클래싱은 강력하며, 위는 메타클래싱에 대한 전혀 가깝지 않고 포괄적인 사용 목록입니다.

type() 함수는 오브젝트의 유형을 반환하거나 새로운 유형을 작성할 수 있습니다.

예를 들어 type() 함수를 사용하여 Hi 클래스를 만들 수 있습니다.클래스 Hi(object)에서는 이 방법을 사용할 필요가 없습니다.

def func(self, name='mike'):
    print('Hi, %s.' % name)

Hi = type('Hi', (object,), dict(hi=func))
h = Hi()
h.hi()
Hi, mike.

type(Hi)
type

type(h)
__main__.Hi

type()을 사용하여 동적으로 클래스를 만드는 것 외에 클래스의 작성 동작을 제어하고 메타클래스를 사용할 수 있습니다.

Python 객체 모델에 따르면 클래스는 객체이므로 클래스는 다른 특정 클래스의 인스턴스여야 합니다.기본적으로 Python 클래스는 유형 클래스의 인스턴스입니다.즉, type은 대부분의 기본 제공 클래스의 메타클래스 및 사용자 정의 클래스의 메타클래스입니다.

class ListMetaclass(type):
    def __new__(cls, name, bases, attrs):
        attrs['add'] = lambda self, value: self.append(value)
        return type.__new__(cls, name, bases, attrs)

class CustomList(list, metaclass=ListMetaclass):
    pass

lst = CustomList()
lst.add('custom_list_1')
lst.add('custom_list_2')

lst
['custom_list_1', 'custom_list_2']

Magic은 메타클래스에서 키워드 인수를 전달하면 유효합니다.Python 인터프리터가 ListMetaclass를 통해 CustomList를 작성하도록 지시합니다.new()는 예를 들어 이 시점에서 클래스 정의를 수정하고 새 메서드를 추가한 다음 수정된 정의를 반환합니다.

공개된 에도 '아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 네.metaclass는 클래스의 동작을 정의합니다.따라서 메타클래스를 명시적으로 설정할 수 있습니다. Python을 class for, 색, 색, 색,metaclass 찾을 수 없는 경우 기본 메타클래스 유형을 사용하여 클래스의 개체를 만듭니다.「 」의 __metaclass__ Atribute, Attribute를 설정할 수 .metaclass★★★★★★★★★★★★★★★★★★:

class MyClass:
   __metaclass__ = type
   # write here other method
   # write here one more method

print(MyClass.__metaclass__)

다음과 같은 출력이 생성됩니다.

class 'type'

물론.metaclass클래스를 사용하여 생성된 모든 클래스의 동작을 정의합니다.

위해 디폴트 " " " " 입니다.metaclass는 메인 .metaclass:

class MyMetaClass(type):
   __metaclass__ = type
   # you can write here any behaviour you want

class MyTestClass:
   __metaclass__ = MyMetaClass

Obj = MyTestClass()
print(Obj.__metaclass__)
print(MyMetaClass.__metaclass__)

출력은 다음과 같습니다.

class '__main__.MyMetaClass'
class 'type'

3. 메서드 python 3.6에 주의해 .__init_subclass__(cls, **kwargs)는 메타클래스의 많은 일반적인 사용 사례를 대체하기 위해 도입되었습니다.정의 클래스의 서브 클래스가 생성되면 호출됩니다.python 문서를 참조하십시오.

다음은 사용 가능한 용도의 다른 예입니다.

  • .metaclass인스턴스(클래스)의 기능을 변경합니다.
class MetaMemberControl(type):
    __slots__ = ()

    @classmethod
    def __prepare__(mcs, f_cls_name, f_cls_parents,  # f_cls means: future class
                    meta_args=None, meta_options=None):  # meta_args and meta_options is not necessarily needed, just so you know.
        f_cls_attr = dict()
        if not "do something or if you want to define your cool stuff of dict...":
            return dict(make_your_special_dict=None)
        else:
            return f_cls_attr

    def __new__(mcs, f_cls_name, f_cls_parents, f_cls_attr,
                meta_args=None, meta_options=None):

        original_getattr = f_cls_attr.get('__getattribute__')
        original_setattr = f_cls_attr.get('__setattr__')

        def init_getattr(self, item):
            if not item.startswith('_'):  # you can set break points at here
                alias_name = '_' + item
                if alias_name in f_cls_attr['__slots__']:
                    item = alias_name
            if original_getattr is not None:
                return original_getattr(self, item)
            else:
                return super(eval(f_cls_name), self).__getattribute__(item)

        def init_setattr(self, key, value):
            if not key.startswith('_') and ('_' + key) in f_cls_attr['__slots__']:
                raise AttributeError(f"you can't modify private members:_{key}")
            if original_setattr is not None:
                original_setattr(self, key, value)
            else:
                super(eval(f_cls_name), self).__setattr__(key, value)

        f_cls_attr['__getattribute__'] = init_getattr
        f_cls_attr['__setattr__'] = init_setattr

        cls = super().__new__(mcs, f_cls_name, f_cls_parents, f_cls_attr)
        return cls


class Human(metaclass=MetaMemberControl):
    __slots__ = ('_age', '_name')

    def __init__(self, name, age):
        self._name = name
        self._age = age

    def __getattribute__(self, item):
        """
        is just for IDE recognize.
        """
        return super().__getattribute__(item)

    """ with MetaMemberControl then you don't have to write as following
    @property
    def name(self):
        return self._name

    @property
    def age(self):
        return self._age
    """


def test_demo():
    human = Human('Carson', 27)
    # human.age = 18  # you can't modify private members:_age  <-- this is defined by yourself.
    # human.k = 18  # 'Human' object has no attribute 'k'  <-- system error.
    age1 = human._age  # It's OK, although the IDE will show some warnings. (Access to a protected member _age of a class)

    age2 = human.age  # It's OK! see below:
    """
    if you do not define `__getattribute__` at the class of Human,
    the IDE will show you: Unresolved attribute reference 'age' for class 'Human'
    but it's ok on running since the MetaMemberControl will help you.
    """


if __name__ == '__main__':
    test_demo()

metaclass강력합니다.여러분이 할 수 있는 일이 많습니다(원숭이 마법 등).하지만 이것은 여러분만이 알 수 있는 일이니 주의해 주세요.

객체 지향 프로그래밍에서 메타클래스는 인스턴스가 클래스인 클래스입니다.일반 클래스가 특정 객체의 동작을 정의하듯이 메타클래스는 특정 객체의 동작을 정의하며 메타클래스라는 용어는 단순히 클래스를 만드는 데 사용되는 무언가를 의미합니다.다른 말로 하면, 그것은 클래스의 클래스입니다.오브젝트가 클래스의 인스턴스인 것처럼 클래스는 메타클래스의 인스턴스인 것처럼 클래스를 만드는 데 사용됩니다.python 클래스에서도 객체로 간주됩니다.

위의 답은 정답입니다.

하지만 독자들은 비슷한 이름의 내적 계층에 대한 답을 찾아 이곳에 올지도 모른다.에 있다.Django ★★★★★★★★★★★★★★★★★」WTForms.

David W가 이 답변 아래의 코멘트에서 지적했듯이, 이것들은 라이브러리 고유의 기능으로 유사한 이름의 고급 Python 언어 기능과 혼동해서는 안 됩니다.

오히려, 이것들은 클래스의 딕트 안에 있는 네임스페이스입니다.가독성을 위해 내부 클래스를 사용하여 제작되었습니다.

특수 예에서는, 「」를 참조해 주세요.abstract작성자 모델의 필드와는 눈에 띄게 분리되어 있습니다.

from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=50)
    email = models.EmailField()

    class Meta:
        abstract = True

하나의 는 '보다 낫다'라는 볼 수 있습니다.WTForms:

from wtforms.form import Form
from wtforms.csrf.session import SessionCSRF
from wtforms.fields import StringField

class MyBaseForm(Form):
    class Meta:
        csrf = True
        csrf_class = SessionCSRF

    name = StringField("name")

이 구문은 python 프로그래밍 언어에서는 특별한 취급을 받지 않습니다. Meta는 여기서 키워드가 아니며 메타클래스 동작을 트리거하지 않습니다.: 신, 、 음음 、 음음 like like code code code code rather code)Django ★★★★★★★★★★★★★★★★★」WTForms는 특정 클래스의 컨스트럭터 등에서 이 속성을 읽습니다.

이러한 선언이 존재하면 이러한 선언을 가진 클래스의 동작이 변경됩니다.를 들어, 「」라고 하는 것은,WTFormsself.Meta.csrfcsrfsyslog.syslog.syslog.

Python에서 클래스는 객체이며 다른 객체와 마찬가지로 "something"의 인스턴스입니다.이 "뭔가"는 메타클래스라고 불립니다.이 메타클래스는 다른 클래스의 개체를 만드는 특수한 유형의 클래스입니다.따라서 메타클래스는 새로운 클래스를 만드는 역할을 합니다.이를 통해 프로그래머는 클래스 생성 방법을 사용자 정의할 수 있습니다.

메타클래스를 작성하려면 보통 new() 메서드와 init() 메서드를 덮어씁니다.new() 메서드는 오브젝트 작성 방법을 변경하기 위해 덮어씁니다.init()은 오브젝트 초기화 방법을 변경하기 위해 덮어씁니다.메타클래스는 여러 가지 방법으로 만들 수 있습니다.방법 중 하나는 type() 함수를 사용하는 것입니다.type() 함수는 3개의 파라미터를 사용하여 호출하면 메타클래스를 만듭니다.파라미터는 다음과 같습니다.

  1. 클래스명
  2. 클래스로 상속되는 기본 클래스가 있는 튜플
  3. 모든 클래스 메서드 및 클래스 변수를 포함하는 사전

메타클래스를 작성하는 또 다른 방법은 'metaclass' 키워드로 구성됩니다.메타클래스를 단순 클래스로 정의합니다.상속된 클래스의 매개 변수에서 metaclass=metaclass_name을 전달합니다.

메타클래스는 특히 다음과 같은 상황에서 사용할 수 있습니다.

  1. 특정 효과가 모든 하위 클래스에 적용되어야 할 때
  2. (생성 시) 클래스 자동 변경 필요
  3. API 개발자별

메타클래스의 흥미로운 사용 사례를 보았습니다.classutilities. 형식대해 함)인지 모든 클래스 변수가 대문자 형식인지(설정 클래스에 통합 로직을 사용하는 것이 편리함) 및 클래스에 인스턴스 수준 메서드가 없는지 확인합니다.메타클라아제에 대한 또 다른 흥미로운 예는 복잡한 조건에 기초한 단일 테스트의 비활성화였다(복수의 환경 변수 값 확인).

메타프로그래밍이란?

간단히 말해서 메타프로그래밍은 코드를 조작하는 코드라고 할 수 있습니다.Python은 메타클래스라고 하는 클래스를 위한 메타프로그래밍 형식을 지원합니다.

사용 시기:

보통 복잡한 용도로 사용되지만 메타클래스를 사용하는 경우는 다음과 같습니다.

  • 메타클래스는 상속 계층으로 전파됩니다.모든 서브클래스에도 영향을 줍니다.그런 상황이라면 메타클래스를 사용해야 합니다.
  • 클래스를 자동으로 변경하려면 클래스를 만들 때 메타클래스를 사용합니다.
  • API 개발에는 메타클래스를 사용할 수 있습니다.
  • 작성 중 : 로깅 및 프로파일링, 인터페이스 체크, 작성 시 클래스 등록, 새로운 메서드 자동 속성 생성, 프록시, 자동 자원, 잠금/동기화.

신입사원용 다이어그램: 메타클래스

클래스 팩토리:

메타클래스는 주로 클래스 공장으로 사용됩니다.클래스를 호출하여 개체를 만들면 Python은 메타클래스를 호출하여 새 클래스를 만듭니다.

> 표준과 조합__init__ ★★★★★★★★★★★★★★★★★」__new__메서드, 메타클래스를 사용하면 클래스를 만들 때 새 클래스를 일부 레지스트리에 등록하거나 클래스를 완전히 다른 것으로 바꿀 수 있습니다.

1-이전에 호출된 방식입니다.__init__() 합니다. 오브젝트를 생성하여 반환합니다.이 메서드를 덮어쓰고 오브젝트 작성 방법을 제어할 수 있습니다.

2- 이 메서드는 매개 변수로 전달된 생성된 개체를 초기화합니다.

메타클래스를 정의하는 방법:

1- 방법 1:

class MyMeta1(type):
    def __new__(cls, name, bases, dict):
        pass

2- 방법 2:

class MyMeta2(type):
    def __init__(self, name, bases, dict):
        pass

Python에서 메타클래스는 서브클래스의 동작을 결정하는 서브클래스의 서브클래스입니다.클래스는 다른 메타클래스의 인스턴스입니다.Python에서 클래스는 클래스의 인스턴스가 작동하는 방식을 지정합니다.

메타클래스는 클래스 생성을 담당하기 때문에 커스텀 메타클래스를 작성하여 추가 액션을 수행하거나 코드를 삽입하여 클래스 작성 방법을 변경할 수 있습니다.커스텀 메타클래스가 항상 중요한 것은 아니지만, 중요할 수도 있습니다.

이것 좀 봐.

Python 3.10.0rc2 (tags/v3.10.0rc2:839d789, Sep  7 2021, 18:51:45) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> class Object:
...     pass
... 
>>> class Meta(type):
...     test = 'Worked!!!'
...     def __repr__(self):
...             return 'This is "Meta" metaclass'
... 
>>> class ObjectWithMetaClass(metaclass=Meta):
...     pass
... 
>>> Object or type(Object())
<class '__main__.Object'>
>>> ObjectWithMetaClass or type(ObjectWithMetaClass())
This is "Meta" metaclass
>>> Object.test
AttributeError: ...
>>> ObjectWithMetaClass.test
'Worked!!!'
>>> type(Object)
<class 'type'>
>>> type(ObjectWithMetaClass)
<class '__main__.Meta'>
>>> type(type(ObjectWithMetaClass))
<class 'type'>
>>> Object.__bases__
(<class 'object'>,)
>>> ObjectWithMetaClass.__bases__
(<class 'object'>,)
>>> type(ObjectWithMetaClass).__bases__
(<class 'type'>,)
>>> Object.__mro__
(<class '__main__.Object'>, <class 'object'>)
>>> ObjectWithMetaClass.__mro__
(This is "Meta" metaclass, <class 'object'>)
>>> 

즉, 오브젝트(오브젝트 유형)가 생성되지 않은 경우 MetaClass가 검색됩니다.

메타는 '뒤' 또는 '뒤'를 뜻하는 그리스어이다.일반적으로 메타는 자기 자신을 지칭합니다.Meta는 추가 정보를 나타냅니다.메타클래스는 슈퍼클래스 또는 부모클래스에 대해 언급해야 하는 추가 정보 또는 추가 정보를 명시적으로 알려주는 도우미 클래스입니다.python에서는 클래스를 정의하면 자동으로 type=metaclass로 간주되며, 이 클래스 기능(flass-metaclass, properties-self 정보)은 생성 시 다른 자식 클래스에 적용할 수 있습니다.

다음은 메타 클래스란 무엇이며 어떻게 작동하는지에 대한 자세한 설명과 코딩 예를 제시합니다.

언급URL : https://stackoverflow.com/questions/100003/what-are-metaclasses-in-python

반응형