어떤 메타클래스에서는 파이썬?
-
01-07-2019 - |
문제
어떤 메타클래스고 우리는 무엇을 사용하는가?
해결책
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__
특성 Bar
가 type()
(지 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
다른 사람들 수 있는 방법을 설명 메타클래스 작품과 그들의 방법에 맞는 파이썬 유형 시스템입니다.여기에는 예의 그들은 무엇을 사용할 수 있습니다.에서 테스트 프레임워크를 썼다고 싶었을 추적하는 순서는 클래스를 정의할 수 있도록,나중에 인스턴스화에서 그들이 순서입니다.나는 그것을 발견 할 수있는 가장 쉬운 방법이 사용하 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)
간단한 예제:
말 당신이 원하는 몇 가지 간단한 유효성 검사 코드에서 실행 특성--같은 항상 있어야 합는 int
나 str
.없이 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.
을 관찰하는 코드는 위의하지 않는 실제로는 아무것도보다 더 많은 로그하는 작업입니다.각 메서드 대리자가 실제 작업하는 부모의 구현,따라서 유지하는 기본 동작입니다.이 type
가 Meta_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'