Metaprogramming is the language feature that helps you write code that you won't be able to understand once the cocaine wears off.
— twitter.com/bos31337
Метаобектният протокол на Python
[Metaclasses] are deeper magic than 99% of the users should ever worry about. If you wonder whether you need them, you don't (the people who actually need them know with certainty that they need them, and don't need an explanation about why).
— Tim Peters
typeВ Пайтън type значи няколко неща:
type(x) връща типа на xtypetype# обекти
>>> type(42), type("42"), type(object())
(<class 'int'>, <class 'str'>, <class 'object'>)
# типове
>>> type(int), type(str), type(object)
(<class 'type'>, <class 'type'>, <class 'type'>)
# връзката
>>> issubclass(int, type)
False
>>> isinstance(int, type)
True
>>> issubclass(object, type)
False
>>> isinstance(object, type)
True
>>> issubclass(type, object)
True
>>> issubclass(object, type)
False
>>> isinstance(type, object)
True # естествено
>>> isinstance(type, type)
True # втф?!
type разбира се. Инстанции на type създавате с:
type(name, bases, dict)
Какво е инстанция на type - просто клас.
name - име на новия класbases - tuple с базовите му класовеdict - речник с полетата му (не по-различно от __dict__)
def човек_инициализирай(self, name):
self.name = name
def човек_кажи_здрасти(self):
print("Здрасти, аз съм", self.name)
Човек = type( 'Човек', (), {
'__init__' : човек_инициализирай,
'кажи_здрасти': човек_кажи_здрасти }
)
Човек('¡Испанска нинджа!').кажи_здрасти()
class Foo(A, B, C, metaclass=Bar):
pass
class Foo(A, B, C, metaclass=Bar):
x = 1
y = 2
# е захар за (почти)
Foo = Bar('Foo', (A, B, C), {'x':1, 'y':2})
class metacls(type):
def __new__(mcs, name, bases, dict):
dict['foo'] = 'metacls was here'
return type.__new__(mcs, name, bases, dict)
class R(metaclass=ReverseNames):
def forward(self):
print('forward')
>>> r = R()
>>> r.forward()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'R' object has no attribute 'forward'
>>> r.drawrof()
forward
class ReverseNames(type):
def __new__(klass, name, bases, _dict):
reversed = [(k[::-1], v) for k, v in _dict.items()]
return type.__new__(klass, name, bases, dict(reversed))
class Meta(type):
def bar(self):
print(self)
class Foo(metaclass=Meta):
pass
>>> f = Foo()
>>> f.bar()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute 'bar'
>>> Foo.bar()
<class '__main__.Foo'>
>>> Meta.bar()
# ???
class Person(metaclass=selfless):
def __init__(name):
self.name = name
def say_hi():
print("Hi, I am", self.name)
Person("忍者").say_hi()
def without_ego(func):
def wrapped(self, *args, **kwargs):
old_self = func.__globals__.get('self')
func.__globals__['self'] = self
result = func(*args, **kwargs)
func.__globals__['self'] = old_self
return result
wrapped.__name__ = func.__name__
return wrapped
class selfless(type):
def __new__(cls, name, bases, attrs):
for key, value in attrs.items():
if not hasattr(value, '__call__'): continue
attrs[key] = without_ego(value)
return type.__new__(cls, name, bases, attrs)
Не ползвайте eval().