클래스 블록은 사전을 작성한 다음 클래스 객체를 작성하기 위해 메타 클래스를 호출하는 대략적인 구문 설탕입니다.
이 :
class Foo(object):
__metaclass__ = FooMeta
FOO = 123
def a(self):
pass
꽤 많이 당신이 작성했던 것처럼 나온다 :
d = {}
d['__metaclass__'] = FooMeta
d['FOO'] = 123
def a(self):
pass
d['a'] = a
Foo = d.get('__metaclass__', type)('Foo', (object,), d)
만 네임 스페이스 오염없이 (그리고 실제로 결정하는 모든 기반을 통해 검색도 있습니다 metaclass, 또는 metaclass 충돌이 있는지 여부는 여기에서 무시합니다).
__setattr__
당신은 그것의 인스턴스 중 하나 (클래스 객체)에 대한 속성을 설정하려고 할 때 발생하는 상황을 제어 할 수 있습니다 만, 클래스 블록 내부 가 당신이 그 일을하지 않는 메타 클래스는 '당신은에 삽입하고 사전 개체이므로 dict
클래스는 메타 클래스가 아니라 현재 진행중인 작업을 제어합니다. 그래서 너는 운이 없어.
파이썬 3.x를 사용하지 않는 한! Python 3.x에서는 metaclass 생성자에 전달되기 전에 클래스 블록 내에 설정된 속성을 누적하기 위해 사용되는 객체를 제어하는 메타 클래스에 클래스 메쏘드 (또는 staticmethod)를 정의 할 수 있습니다. 나에게주는이 실행
from collections import MutableMapping
class SingleAssignDict(MutableMapping):
def __init__(self, *args, **kwargs):
self._d = dict(*args, **kwargs)
def __getitem__(self, key):
return self._d[key]
def __setitem__(self, key, value):
if key in self._d:
raise ValueError(
'Key {!r} already exists in SingleAssignDict'.format(key)
)
else:
self._d[key] = value
def __delitem__(self, key):
del self._d[key]
def __iter__(self):
return iter(self._d)
def __len__(self):
return len(self._d)
def __contains__(self, key):
return key in self._d
def __repr__(self):
return '{}({!r})'.format(type(self).__name__, self._d)
class RedefBlocker(type):
@classmethod
def __prepare__(metacls, name, bases, **kwargs):
return SingleAssignDict()
def __new__(metacls, name, bases, sad):
return super().__new__(metacls, name, bases, dict(sad))
class Okay(metaclass=RedefBlocker):
a = 1
b = 2
class Boom(metaclass=RedefBlocker):
a = 1
b = 2
a = 3
: 기본 __prepare__
는 단순히 일반 사전을 반환하지만 당신은 키를 재정의 할 수 없습니다 사용자 정의 딕셔너리와 같은 클래스를 구축하고, 당신의 특성을 축적하는 것을 사용할 수
Traceback (most recent call last):
File "/tmp/redef.py", line 50, in <module>
class Boom(metaclass=RedefBlocker):
File "/tmp/redef.py", line 53, in Boom
a = 3
File "/tmp/redef.py", line 15, in __setitem__
'Key {!r} already exists in SingleAssignDict'.format(key)
ValueError: Key 'a' already exists in SingleAssignDict
일부 노트 :이 일하기 전에 호출되고 있기 때문에
__prepare__
는 classmethod
또는 staticmethod
수있다 e metaclass '인스턴스 (클래스)가 존재합니다. ,
type
여전히 실제 dict
로 세 번째 매개 변수를 필요, 그래서 당신은 아마 (2) 피할 것 정상적인 내가 dict
서브 클래스 수도 하나
- 에
SingleAssignDict
변환하는 __new__
방법을 가지고 있지만 난 정말 그게 싫어하는 이유는 update
과 같은 기본이 아닌 메서드가 기본 메서드의 재정의를 __setitem__
과 같이 존중하지 않기 때문입니다. 따라서 하위 클래스 인 collections.MutableMapping
을 선호하며 사전을 감싸줍니다.
type
및 type
에 의해 설정 되었기 때문에 실제 Okay.__dict__
개체는 일반적인 사전입니다. 원하는 사전에 대해 까다로운 내용입니다. 즉, 클래스 작성 후 클래스 속성을 겹쳐 쓰더라도 예외가 발생하지 않습니다. 수퍼 클래스 호출 후 __dict__
속성을 덮어 쓸 수 있습니다. __new__
클래스 개체의 사전에 의해 덮어 쓰기를 유지하려는 경우입니다.
는 안타깝게도이 기술은 파이썬 2.x에서 (내가 확인)에서 사용할 수 없습니다. __prepare__
메쏘드는 호출되지 않습니다. 이것은 Python 2.x에서처럼 메타 블록은 클래스 블록의 특별한 키워드가 아닌 __metaclass__
매직 속성에 의해 결정됩니다; 이는 메타 클래스가 알려질 때까지 클래스 블록에 대한 속성을 누적하는 데 사용되는 dict 객체가 이미 있음을 의미합니다.
파이썬 2 비교 :
class Foo(object):
__metaclass__ = FooMeta
FOO = 123
def a(self):
pass
는에 거의 동등한 것 :
class Foo(metaclass=FooMeta):
FOO = 123
def a(self):
pass
존재 : 호출 할 수있는 메타 클래스는 파이썬 3 대, 사전 결정됩니다
d = {}
d['__metaclass__'] = FooMeta
d['FOO'] = 123
def a(self):
pass
d['a'] = a
Foo = d.get('__metaclass__', type)('Foo', (object,), d)
대략 다음과 같습니다 :
d = FooMeta.__prepare__('Foo',())
d['Foo'] = 123
def a(self):
pass
d['a'] = a
Foo = FooMeta('Foo',(), d)
여기서 사용할 사전은 메타 클래스에서 결정됩니다.
이 정확한 문제는 메타 클래스 구문이 py3에서 변경된 이유입니다! – SingleNegationElimination