문제

어떤 메타클래스고 우리는 무엇을 사용하는가?

도움이 되었습니까?

해결책

A metaclass 은 클래스의 클래스입니다.클래스를 정의하는 방법 클래스의 인스턴스(즉체)동작하는 동안 metaclass 을 정의하는 방법 동작하는 클래스.클래스의 인스턴스 metaclass.

는 파이썬에서 사용할 수 있는 임의의 callables 에 대한 메타클래스(아 Jerub 쇼),더 나은 방법은 실제 수업 자체입니다. type 일반적인 metaclass in Python. type 자체 클래스고,그것은 그것의 자신의 유형입니다.할 수 없을 다시 뭔가 type 순전히 파이썬지만,파이썬은 조금 있습니다.당신의 자신을 만들 metaclass Python 에서 당신은 정말 단순하고 싶 서브 클래스 type.

A metaclass 가장 일반적으로 사용되는 클래스를 공장이 있습니다.를 만들 때는 객체를 호출하여 클래스 파일을 새로 만듭니다 클래스(할 때 그것을 실행하는'클래스의 성명)호출하여 metaclass.과 결합상 __init____new__ 방법,메타클래스에 따라서 할 수 있는'추가'사물을 만들 때 클래스를 등록하는 새로운 클래스와 일부 레지스트리 또는 교체 등으로 완전히 다른 뭔가.

class 문을 실행,Python 먼저를 실행합체의 class 문으로 정상적인 블록의 코드입니다.그 결과 네임스페이스(dict)보유 특성을 클래스-to-be.이 metaclass 에 의해 결정되고 baseclasses 의 클래스-to-be(메타클래스에는 상속),에 __metaclass__ 의 특성을 클래스-to-be(있을 경우)또는 __metaclass__ 글로벌 변수입니다.이 metaclass 는 다음이라는 이름으로 기초와 특성을 클래스의 인스턴스화하다.

그러나,메타클래스는 실제로 정의 유형 의 클래스,다만,공장에 대한 그것은,그래서 당신은 더 많은 작업을 수행 할 수 있습니다 그들과 함께.당신이 할 수있는,예를 들어,정의하는 일반적인 방법에 metaclass.이러한 metaclass-방법은 다음과 같 classmethods 할 수 있다는 점에서 호출에스지 않고 인스턴스,하지만 그들은 또한 다음과 같 classmethods 에서 사용할 수 없습니다 인스턴스에서 호출합니다. type.__subclasses__() 의 예는 방법에 대 type metaclass.을 정의할 수도 있습니다면 정상적인'매직'방법 __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.파이썬은 매우 독특한 아이디어의 클래스가 무엇인지,에서 빌린 Smalltalk 언어입니다.

대부분에서 언어의 클래스는 단지 조각의 코드를 설명하는 방법을 생산하는 개체입니다.는 일종의 사실에서는 파이썬다:

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

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

그러나 클래스는 그 이상에서 Python.클래스는 개체무.

Yes,개체입니다.

로 사용할 키워드 class, 파이썬 실행하고 만듭니다 체.명령

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

성 메모리에 있는 객체 이름을 가진"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>

클래스를 만들어가 동적으로

이 클래스는 개체를 만들 수 있습니다 즉,모든 개체입니다.

첫째,당신은 클래스를 만들 수 있습 함수에서 사용하는 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 만듭니다 이 물체를 자동으로.지 대부분의 것들과 라이브러리는 모두 지원되며,그것은 당신이 제공하는 방법을 할 수 있습니다.

기억 기능 type?좋은 오래된 기능을 할 수 있는 알 형식 개체:

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

론, type 는 완전히 다른 능력,그것은 또한 클래스를 만듭니다. type 을 취할 수 있습에 대한 설명 클래스를 매개 변수 을 반환하는 클래스입니다.

(나는 알고,그것은 바보 같은 기능을 수 있는 두 개의 완전히 다른 사용한 매개변수에 따라 전달합니다.그것은 문제 때문에 거꾸로 호환성에서는 Python)

type 이 방법:

type(name of the class,
     tuple of the parent class (for inheritance, can be empty),
     dictionary containing attributes names and values)

예를 들어:

>>> 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,클래스는 개체를 만들 수 있습니다 클래스에서,비행됩니다.

이것은 무슨 파이썬은 사용할 때 키워드 class, 며,그것은 그렇게 사용하여 metaclass.

어떤 메타클래스(마지막으로)

메타클래스는'물건'을 만드는 클래스입니다.

당신은 클래스를 정의하기 위해서는 개체를 만들죠?

그러나 우리는 것을 배웠고 사용자 데이터베이스는 객체입니다.

론,메타클래스가 무엇을 만드는 이러한 객체입니다.그들은 이 클래스'클래스 할 수 있는 사진들은 이 방법:

MyClass = MetaClass()
my_object = MyClass()

당신이 볼 수있는 type 할 수 있습 다음과 같은 것이 가능합니다.

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

기 때문에 그것이 기능 type 사실 metaclass. type 가 metaclass Python 을 만들기 위해 사용하는 모든 클래스고 있습니다.

이제 당신은 왜 지옥을 쓰는 소문자,고지 Type?

만,나는 그것이 문제의 일관성과 str, 클래스를 만드는 문자열체고 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'>

그래서,metaclass 은 물건을 만드는 클래스 개체입니다.

당신을 호출 할 수 있습 a'클래스의 공장'원하는 경우.

type 가 내장 metaclass Python 사용하지만,물론 당신은 만들 수 있습니다 자신의 metaclass.

__metaclass__ 특성

Python2 을 추가할 수 있습니다 __metaclass__ 특성 때 당신은 클래스를 작성(다음 섹션 참조 Python3 구):

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

이렇게 하는 경우,Python 사용합니다 metaclass 클래스를 만들려면 Foo.

조심해요 까다롭습니다.

당신이 쓰 class Foo(object) 첫째,하지만 개체 클래스 Foo 이 만들어지지 않습 메모리에서 아직입니다.

Python 보이는 것입 __metaclass__ 클래스에서 정의합니다.그것을 발견하는 경우, 그것이 그것을 사용하는 개체를 만드는 클래스 Foo.지 않는 경우,사용 type 래스를 만듭니다.

을 읽는다.

수행할 때:

class Foo(Bar):
    pass

Python 는 다음과 같은 작업을 수행합니다.

__metaclass__ 특성 Foo?

그렇다면,메모리에서 생성 클래스를 개체(나는 말했다 클래스의 개체,stay with me here),이름 Foo 무엇을 사용하여서 __metaclass__.

면 Python 을 찾을 수 없 __metaclass__,그것을 찾을 것입 __metaclass__ 모듈 수준에서,그리고는 동일한 작업을 수행하기 위해 노력(에 대해서만 클래스를 상속하지 않도,기본적으로 이전 스타일의 클래스).

는 경우 다음 그것을 찾을 수 없 __metaclass__ 에서 모두,그것을 사용합니다 Bar's(첫 번째 부모)자신의 metaclass(할 수있는 기본 type 는)클래스를 만들 개체입니다.

여기서 조심하는 __metaclass__ 특성이 되지 않을 상속 metaclass 의 부모(Bar.__class__)이 될 것입니다.는 경우 Bar__metaclass__ 특성 Bartype() (지 type.__new__()다),서브 클래스를 상속 받지 않는 동작입니다.

이제 큰 문제는 무엇을 할 수 있에 넣 __metaclass__ ?

대답:는 무언가를 만들 수 있습니다.

무엇을 만들 수 있습니다. type, 또는 아무것도 하위 클래스 또는 이를 사용합니다.

메타클래스에서는 Python3

구문을 설정하 metaclass 에서 변경되었습니 Python3:

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

즉이 __metaclass__ 특성은 더 이상 사용하지 않,찬성의 키워드를 인수 목록에서의 기본 클래스입니다.

의 행동에 메타클래스 그러나 유지 크게 동.

한 가지 추가 메타클래스에서는 python3 는 전달할 수도 있습 특성으로 키워드 인수로 metaclass 다음과 같이:

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

아래 부분을 읽는 방법에 대한 파이썬 핸들이다.

사용자 지정 메타클래스

의 주요 목적 metaclass 은 클래스를 변경하는 자동으로, 때 만들어집니다.

당신은 일반적으로 이 Api 에 대해 당신이 원하는 클래스를 만들과 일치하는 현재 문맥.

상상해보를 들어,당신이 결정하는 모든 클래스에서 당신의 모듈 이 있어야 그들의 특성이 대문자로 쓰여집니다.여러 가지 방법이 있을 이렇게,하지만 한 가지 방법을 설정하는 것입 __metaclass__ 에서 모듈을 수준입니다.

이 방법의 모든 클래스 이 모듈을 사용하여 만든 이 metaclass, 그리고 우리는 말해야합 metaclass 모든 속성을 대문자로 표시됩니다.

다행히도, __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_attr):
    """
      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_attr = {}
    for name, val in future_class_attr.items():
        if not name.startswith('__'):
            uppercase_attr[name.upper()] = val
        else:
            uppercase_attr[name] = val

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

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

print(hasattr(Foo, 'bar'))
# Out: False
print(hasattr(Foo, 'BAR'))
# Out: True

f = Foo()
print(f.BAR)
# Out: 'bip'

지금하자,정확히 동일한 작업을 수행하고,그러나 사용하여 실제 수준에 대한 metaclass:

# 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_attr):

        uppercase_attr = {}
        for name, val in future_class_attr.items():
            if not name.startswith('__'):
                uppercase_attr[name.upper()] = val
            else:
                uppercase_attr[name] = val

        return type(future_class_name, future_class_parents, uppercase_attr)

그러나 이것은 정말 OOP.우리는 전화 type 바로 우리는 사용하지 않 override 부모 또는 전화 __new__.Let's do it:

class UpperAttrMetaclass(type):

    def __new__(upperattr_metaclass, future_class_name,
                future_class_parents, future_class_attr):

        uppercase_attr = {}
        for name, val in future_class_attr.items():
            if not name.startswith('__'):
                uppercase_attr[name.upper()] = val
            else:
                uppercase_attr[name] = val

        # reuse the type.__new__ method
        # this is basic OOP, nothing magic in there
        return type.__new__(upperattr_metaclass, future_class_name,
                            future_class_parents, uppercase_attr)

당신은 발견 할 수 있습니다 추가 인수 upperattr_metaclass.가 아무것도 특별한 이 __new__ 항상을 받은 클래스에 정의된 대로,첫 번째 매개 변수입니다.처럼 당신 self 에 대한 일반적인 방법을 받 인스턴스로 첫 번째 매개 변수하거나,정의 클래스 클래스에 대한 방법이 있습니다.

물론,이름을 내가 사용하는 여기에 오래에 대해 쉽게 파악할 수 있도록 하기 위해,지 대 self, 모든 인수 기존의 이름입니다.그래서 진짜 생산 metaclass 다음과 같이 보일 것입니다.

class UpperAttrMetaclass(type):

    def __new__(cls, clsname, bases, dct):

        uppercase_attr = {}
        for name, val in dct.items():
            if not name.startswith('__'):
                uppercase_attr[name.upper()] = val
            else:
                uppercase_attr[name] = val

        return type.__new__(cls, clsname, bases, uppercase_attr)

우리는 그것을 만들 수 있도를 사용하여 청소기 super, 는 것이다 용이 상속(기 때문에 그렇다,당신은 있을 수 있는 메타클래스를 상속받 메타클래스를 상속받는 유형):

class UpperAttrMetaclass(type):

    def __new__(cls, clsname, bases, dct):

        uppercase_attr = {}
        for name, val in dct.items():
            if not name.startswith('__'):
                uppercase_attr[name.upper()] = val
            else:
                uppercase_attr[name] = val

        return super(UpperAttrMetaclass, cls).__new__(cls, clsname, bases, uppercase_attr)

아,그리고 python3 할 경우 이 호출을 키워드로 인수,이:

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

변환하이에서 metaclass 사용하려면 다음과 같이 하십시오.

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

그것입니다.가 정말로 아무것도에 대해 더 많은 메타클래스.

이 뒤에 이유는 복잡성의 코드를 사용하여 메타클래스지 않기 때문에 의 메타클래스,기 때문에 그것이 당신이 일반적으로 사용하는 메타클래스 할 물건을 트위스트 에 의존하고 내성,조작 상속,var 등 __dict__, 니다,등등.

실제로,메타클래스에 특히 유용하지 마라 복잡한 물건입니다.하지만 자신에 의해,그들은 간단하다:

  • 차단 클래스 생성
  • 수정 클래스
  • 반환된 클래스

왜 당신이 사용하는 메타클래스 클래스 대신 기능은 무엇입니까?

__metaclass__ 허용할 수 있습니다 호출 가능,을 사용하는 이유는 무엇일 클래스 이후 그것은 분명히 더 복잡해?

거기에 여러 가지 이유로 그렇게 하려면 다음과 같이 합니다.

  • 의도 분명하다.을 읽을 때 UpperAttrMetaclass(type), 에,당신은 알 무슨 일을 따라하
  • 당신이 사용할 수 있습 OOP.Metaclass 에서 상속할 수 있습 metaclass,재정의 부모는 방법이 있습니다.메타클래스를 사용할 수 있습 메타클래스.
  • 서브 클래스의 클래스의 인스턴스의 metaclass 지정한 경우 metaclass 스,하지만 metaclass-기능입니다.
  • 할 수 있는 구조물의 코드를 더합니다.당신이 사용하지 않는 메타클래스에 대한 무언가 사소한으로 위의 예입니다.그것은 일반적으로 무언가를 위해 복잡합니다.가 는 기능을 여러 가지 방법 및 그룹들을 하나의 클래스에서 매우 유용 코드를 쉽게 읽을 수 있습니다.
  • 후에 __new__, __init____call__.는 것이 허용 당신이 다른 물건입니다.는 경우에도 일반적으로 당신은에서 모든 작업을 수행 할 수 있습니다 __new__, 어떤 사람들은 더 편안한 사용 __init__.
  • 이러한 호출되는 메타클래스,길!그것은 무언가를 의미해야한다!

왜 당신이 사용하는 메타클래스?

지금 큰 문제입니다.을 사용하는 이유는 무엇일부호 오류가 발생하기 쉬운 기능이?

만,일반적으로 당신은하지 않:

메타클래스는 깊은 마술 99%의 사용자가에 대해 걱정하지 마.을 궁금해하는 경우 필요가 있는지,그들을 당신이하지 않는(실행한 사람들 그들이 필요는 확실히 알고 있는 그들이 필요한지 그리고 필요 없는 는 이유에 대한 설명).

Python 전문가 팀 Peters

주요 사례에 대한 metaclass 을 만드는 API 입니다.의 전형적인 예이 Django ORM.

그것은을 정의할 수 있습 무언가 이것을 좋아한다:

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

하지만 이렇게 하면:

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

에 대한 지식을 향상시킬 수 있는 IntegerField 체입니다.그것을 반환합니다. int, 고 걸릴 수 있습니다 그것은 데이터베이스에서 직접.

이 때문에 가능 models.Model 정의 __metaclass__ 고 그것은 일부 사용법입니다 Person 당신은 단지 정의된 간단한 구문 으로 복잡한 걸이를 데이터베이스 분야이다.

장고 무언가를 만든 복잡한 보는 간단한 노출에 의해 간단한 API 고 사용하는 메타클래스를 재현,코드에서 이 API 을 실제 작업 니다.

마지막 낱말

첫째,당신이 알고 있는 클래스는 개체를 만들 수 있는 인스턴스가 있습니다.

만,사실 클래스는 자신 인스턴스가 있습니다.의 메타클래스.

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

모든 것은 객체에서 Python,그리고 그들은 모두 하나의 클래스의 인스턴스 또는 메타클래스의 인스턴스.

을 제외한 type.

type 실제로 그것의 자신의 metaclass.이것은 무언가를 당신 을 재현한,고 부정 행위에 의해 조금 구현 수준입니다.

둘째,메타클래스는 복잡하다.하지 않을 수도 있습 사용 매우 간단한 클래스를 변경했다.변경할 수 있습니다 클래스를 사용하여 두 가지 다른 기술을:

99%할 필요가 시간의 클래스,변경,당신은 더 나은 사용한다.

하지만 시간의 98%를,당신은 당신이 필요하지 않 클래스에서 변경을 모든.

이 대답은 Python2.x 으로 그것이 2008 년에 작성,메타클래스는 약간 다르에서 3.x.

메타클래스는 비밀스는'클래스'일이다.기본 metaclass 에 대한 새로운 스타일체라는'유형'.

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

메타클래스 3args.'이름', ''및'dict'

여기에는 비결이 시작됩니다.보는 이름,기초과 dict 에서 온 이 예제에서는 클래스 정의합니다.

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

할 수 있을 정의 metaclass 는 것을 입증하는 방법'클래스:'를 호출합니다.

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

참고는 행동하는'Initalised'이익함으로써 metaclass init_attributes 이 전달되지 않에 하위 클래스의 Initalised.

다음은 더욱 구체적인 예를 보여할 수 있는 방법 서브 클래스는'형'을 만들 metaclass 작업을 수행하는 클래스가 만들어집니다.이것은 매우 까다롭습니다:

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

중 하나를 사용에 대한 메타클래스가 추가하는 새로운 특성을과 방법을 인스턴스를 자동으로 합니다.

예를 들어,당신 Django 모델, 그들의 정의에 보이는 혼란스럽습니다.그것은 경우에만 정의를 클래스 속성:

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

그러나 사람은 개체는 모든 종류의 가득한 유용한 방법이 있습니다.보 에 대한 몇 가지 놀라운 metaclassery.

다른 사람들 수 있는 방법을 설명 메타클래스 작품과 그들의 방법에 맞는 파이썬 유형 시스템입니다.여기에는 예의 그들은 무엇을 사용할 수 있습니다.에서 테스트 프레임워크를 썼다고 싶었을 추적하는 순서는 클래스를 정의할 수 있도록,나중에 인스턴스화에서 그들이 순서입니다.나는 그것을 발견 할 수있는 가장 쉬운 방법이 사용하 metaclass.

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 기록하는 순서는 클래스 정의됩니다.

나는 생각 ONLamp 소개 metaclass 프로그램을 작성하고 제공하는 정말 좋은 주제에 대한 소개입에도 불구하고 몇 년의 역사를 자랑한다.

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)

에서 짧은:클래스를 위한 청사진 창조의 인스턴스 metaclass 의 청사진 창조의 클래스입니다.그것은 쉽게 볼 수 있는 파이썬에서 클래스가 될 필요가 첫 번째 클래스의 개체도를 사용하는 이 동작을 수행할 수 없습니다.

나는 결코 하나를 작성,자신만 생각 하나의 좋은 사용하는 메타클래스에서 볼 수 있습니다 장고 프레임워크.모델 클래스를 사용하 metaclass 접근하도록 선언하는 스타일의 쓰기 새로운 모델이나 형태의 클래스입니다.동 metaclass 은 클래스를 만드,모든 구성원이 사용자 정의 할 수있는 가능성을 클래스 자체.

는 것을 말입니다:는 경우에 당신은 무엇인지 모르 메타클래스는 확률신 지 않을 것이다 그들을 필요로 99%.

어떤 메타클래스?당신은 무엇을 사용하는가?

TLDR:A metaclass 인스턴스화하고 동작을 정의합한 클래스 같은 클래스의 인스턴스화하고 동작을 정의합을 위해 인스턴스입니다.

의사 코드:

>>> Class(...)
instance

위야 잘 알고 있습니다.이 아니라,어디가 Class 에서 오는가?그의 인스턴스 metaclass(는 또한 의사):

>>> Metaclass(...)
Class

에서 실제 코드,우리가 전달할 수 있는 기본 metaclass, type, 에,우리가 필요한 모든 것 인스턴스화하는 클래스고 우리는 클래스:

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

퍼팅 그것을 다르게

  • 클래스를 인스턴스로 metaclass 은 클래스입니다.

    때 우리는 개체를 인스턴스화,우리는 인스턴스:

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

    마찬가지로 우리는 클래스를 정의하여 명시적으로 기본 metaclass, type, 우리는 인스턴스화:

    >>> type('Object', (object,), {})     # instantiation of metaclass
    <class '__main__.Object'>             # instance
    
  • 다른 방법을 넣어 클래스의 인스턴스 metaclass:

    >>> isinstance(object, type)
    True
    
  • 를 넣어 번째 방법으로,metaclass 은 클래스의 클래스입니다.

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

을 작성할 때 클래스 정의하고 Python 실행하는 그것은,그것을 사용하 metaclass 인스턴스화 등 물체(는 것에 사용되도록 고안된 것 인스턴스화하려면 해당 클래스의 인스턴스).

그냥 우리가 사용할 수 있습니다 클래스 정의 방법을 변경하려면 사용자 정의 객체를 인스턴스에 행동하고,우리가 사용할 수 있습니다 metaclass 클래스 정의의 방식을 변경하는 등 개체합니다.

무엇을 위해 사용될 수있다?서 문서:

잠재적 사용에 대한 메타클래스는 무한하다.몇몇 아이디어를 탐험 포함 로깅,인터페이스를 확인,자동적인 위임,자동적인 속성 작성,프록시,프레임워크 및 자 잠금/동기화합니다.

그럼에도 불구하고,그것은 일반적으로 장려하는 사용자를 위해 피를 사용하여 메타클래스지 않으면 절대적으로 필요합니다.

를 사용하 metaclass 을 만들 때마다 클래스:

을 작성할 때 클래스 정의,예를 들어,다음과 같이,

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

metaclass 의 개체를 우리가 만들어서,두 경우 모두,가 type.

(측면에서 노트의 내용 클래스 __dict__: __module__ 이 있기 때문에 클래스 알고 있어야 합니다 그들은 정의 __dict____weakref__ 이 있지 않기 때문에 우리는 정의 __slots__ -는 경우리 정의 __slots__ 우리는 조금 저장 공간의 인스턴스에서,우리가 할 수있는 허용 __dict____weakref__ 제외하여.예를 들어:

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

...그러나 나는 탈선한다.)

을 확대할 수 있습니다 type 그냥 다른 클래스 정의:

여기에 기본 __repr__ 클래스:

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

가장 귀중한 우리가 할 수 있는 일본에서 쓰이는 개체를 제공하는 것 그것으로 좋 __repr__.때 우리는 전화 help(repr) 우리는 거기에 좋은에 대한 테스트 __repr__ 도 필요한 테스트를 위한 평등- obj == eval(repr(obj)).다음의 간단한 구현 __repr____eq__ 클래스의 인스턴스가 우리의 클래스 형식으로 우리를 제공합 시범을 향상시킬 수 있습니다 기본 __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__)

그래서 지금 우리가 만들 때는 객체를 가진 이 metaclass,the __repr__ 에코 명령행에 제공하는 훨씬 적은 추한 시력보다 기본값:

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

__repr__ 에 대해 정의된 클래스의 인스턴스,우리는 더 강력한 디버그 할 수있는 기능을 우리의 코드입니다.그러나,많은 더 확인 eval(repr(Class)) 가능성(으로 기능한 것은 오히려 불가능을 평가에서 자신의 기본 __repr__'s).

예상 사용: __prepare__ 네임스페이스

는 경우,예를 들어,우리는 무엇을 알고 싶기 위해 클래스의 메소드에서 만든,우리는 우리를 제공할 수 있는 주문 dict 로의 네임스페이스 클래스입니다.우리는 이것을 할 것으로 __prepare__반 네임스페이스 dict 클래스의 경우 구현에서는 Python3:

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

이 예제에서 적응 문서 -새로운 enum 표준 라이브러리 이 작업을 수행합니다.

그래서 우리는 무엇이었을 인스턴스화 metaclass 을 만들어 클래스입니다.우리는 또한 치료 metaclass 으로 우리는 다른 클래스입니다.그것은 방법이 해상도 순서는:

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

그것은 약에 올바른 repr (할 수 있는 더 이상 eval 지 않으면 우리는할 수 있는 방법을 찾을 수 있는 기능입니다.):

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

Python3 업데이트

이 있다(이 시점에서)두 가지 주요 방법에 metaclass:

  • __prepare__, 고
  • __new__

__prepare__ 제공할 수 있는 사용자 지정 매핑(등 OrderedDict)로 사용할 수 있는 네임스페이스는 클래스가 만들어지고 있습니다.당신은 반환해야 합니다 인스턴스가 무엇이든의 네임스페이스를 당신이 선택합니다.지 않는 경우 구현 __prepare__ 일반 dict 사용됩니다.

__new__ 에 대한 책임은 실제의 생성/수정의 최종 클래스입니다.

Bare-bones 지 아무것도 추가 metaclass 고 싶:

class Meta(type):

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

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

간단한 예제:

말 당신이 원하는 몇 가지 간단한 유효성 검사 코드에서 실행 특성--같은 항상 있어야 합는 intstr.없이 metaclass,당신의 클래스는 다음과 같습니다.

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

당신이 볼 수 있듯,당신은 이름을 반복하의 특성에 두 번.이것은 오타와 함께 가능한 자극한다.

간단한 metaclass 결할 수 있는 문제점:

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

이것은 어떤 metaclass 것처럼 보이지 않는(사용 __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')

참고:이 예제는 단순히 그것은 또한 수 있었다 달성 클래스를 장식하지만,아마도 실제 metaclass 하는 것이 훨씬 더 있습니다.

는'ValidateType'클래스에 참조용:

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

의 역할을 metaclass' __call__() 방법을 만들 때 클래스의 인스턴스

에 해당하는 경우,프로그래밍 파이썬은 대 이상이 몇 개월 동안 당신은 결국 우연히 코드는 다음과 같습니다.

# 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__() 메소드가 호출될 때 클래스의 인스턴스로 사용 가능.그러나 우리는 본에서 이전의 대답은 클래스의 인스턴스 metaclass 때,그래서 우리가 사용하는 클래스로 호출 가능(i.e때 우리는 우리의 인스턴스를 만들고)우리가 실제로를 호출하 metaclass' __call__() 방법입니다.이 시점에서 대부분의 파이썬 프로그래머는 약간의 혼란 때문에 그들은 그 말을 들었을 때 인스턴스를 만들처럼 이 instance = SomeClass() 당신은 그것의 __init__() 방법입니다.일부 사람들을 발굴했 조금 더 깊이 알기 전에 __init__()__new__().오늘의 또 다른 레이어를 진실은 밝혀지기 전에, __new__() 가 metaclass' __call__().

자 연구 메소드 호출이 사슬에서 특별히 관점의 인스턴스를 만들어의 클래스입니다.

이 metaclass 는 로그를 순간을 정확하게하기 전에 인스턴스를 만들고 그 순간을 반환합니다.

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

이 클래스는 사용하는 metaclass

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 기본 부모 metaclass)및 고려 주문 순서 출력을 위에,우리는 이제 단서를 어떻게 될지 의사의 구현 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

우리는 것을 볼 수 있습 metaclass' __call__() 방법은 것 하나라는 처음이다.그런 다음 대표는 창조의 인스턴스 클래스 __new__() 방법과 초기화하의 인스턴스 __init__().그것은 또한 이는 궁극적으로 반환합니다 인스턴스입니다.

에서 그 위에 줄기는 metaclass' __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()

type 실제로 metaclass --클래스를 생성하는 다른 클래스입니다.가 metaclass 은 서브 클래스 type.이 metaclass 수신 new 클래스로 첫 번째 인수에 대한 액세스를 제공합니다 클래스의 객체와 함께 상세정보는 아래와 같:

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

Tl;dr 버전

type(obj) 기능을 가져오는 당신의 유형입니다.

type() 의 클래스가 해당 metaclass.

를 사용하 metaclass:

class Foo(object):
    __metaclass__ = MyMetaClass

Python 클래스는 자신의 개체-으로 인스턴스에서의 그들의 메타-클래스입니다.

기본 metaclass 에 적용되는 때 결정할 때 클래스:

class foo:
    ...

메타 클래스 사용을 일부를 적용 규칙을 설정의 클래스입니다.예를 들어,당신은 건물 ORM 데이터베이스에 액세스할 수 있도록,당신은 기록에서 각각 테이블의 클래스에 매핑되는 테이블(필드를 기반으로,비즈니스 규칙,etc.,),가능한 사용의 metaclass 은 예를 들어,connection pool 논리,은 공유에 의해 모든 클래스에서 레코드의 모든 테이블이 있습니다.다른 사이에 논리를 지원하는 외국 열쇠를 포함하는 여러 개의 클래스의 기록이다.

를 정의할 때 metaclass,당신은 서브 클래스 종류와 수 있습 overrided 다음과 같은 마술 방법을 삽입하고 논리입니다.

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

어쨌든,그 두 사람은 가장 일반적으로 사용되는 후크가 있습니다.metaclassing 는 강력한 위도와의 완전한 목록을 사용한 metaclassing.

형()함수를 반환할 수 있는 유형의 객체를 만들거나 새로운 형식

예를 들어,우리가 만들 수 있는 안전 클래스 종류()함수를 사용하지 않는 이 방법으로 클래스 하이(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

를 사용하는 것 외에도 입력()클래스를 만들 동적으로 제어할 수 있습니다 만들기 동작의 클래스고 사용 metaclass.

에 따라 Python 객체 모델,클래스의 개체,그래서는 클래스의 인스턴스의 또 다른 특정 클래스입니다.기본적으로,Python 클래스의 인스턴스를 입력 클래스입니다.는 유형입니다 metaclass 의 대부분의 내장에서 클래스고 metaclass 의 사용자 정의됩니다.

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

마법의 적용됩니다면 우리가 전달된 키워드를 인수에 metaclass,그것을 나타내는 파이썬을 만들 CustomList 을 통해 ListMetaclass. (),이 시점에서,우리는 수정할 수 있습니다 클래스 정의,예를 들면,추가하는 새로운 방법이며,다음 반환된 정의합니다.

이외에 출판 답변이라고 말할 수 있습 a metaclass 정의 행동에 대해 클래스입니다.그래서,명시적으로 설정할 수 있습의 metaclass.때마다 Python 얻는 키워드 class 다음 검색을 시작하는 대 metaclass.는 경우 그것은 발견되지 않는 기본 metaclass 형식을 만드는 데 사용되는 클래스의 객체입니다.를 사용하는 __metaclass__ 특성,설정할 수 있습니다 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'
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top