7. Функция type
>>> print type(1)
<type 'int'>
>>> print type('1')
<type 'str'>
>>> print type(Foo)
<type 'type'>
>>> print type(Foo())
<class '__main__.Foo'>
Определение типа…
8. Функция type
type(<имя класса>,
<кортеж родительских классов>,
# для наследования, может быть пустым
<словарь, содержащий атрибуты и их значения>)
…и не только
9. Функция type
class MyShinyClass(object):
pass
или же так
>>> MyShinyClass = type('MyShinyClass', (), {})
>>> print MyShinyClass
<class '__main__.MyShinyClass'>
>>> print MyShinyClass()
<__main__.MyShinyClass object at 0x109ee3290>
10. Посложнее
>>> 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
15. Все — объект
>>> 42.__class__
<type 'int'>
>>> 'Hello world'.__class__
<type 'str'>
>>> def foo(): pass
>>> foo.__class__
<type 'function'>
>>> class Bar(object): pass
>>> b = Bar()
>>> b.__class__
<class '__main__.Bar'>
16. Класс класса
>>> 42.__class__.__class__
<type 'type'>
>>> 'Hello world'.__class__.__class__
<type 'type'>
>>> foo.__class__.__class__
<type 'type'>
>>> b.__class__.__class__
<type 'type'>
17. Атрибут __metaclass__
Приоритеты атрибута __metaclass__:
1. Класс
2. Родительские классы
3. Модуль (только для классов без родителя)
4. type
class Foo(object):
__metaclass__ = something...
[...]
20. А теперь класс
class UpperAttrMetaclass(type):
def __new__(up_metacls, future_cls_name,
future_cls_parents, future_cls_attr):
attrs = {}
for name, val in future_cls_attr.items():
if not name.startswith('__'):
attrs[name.upper()] = val
else:
attrs[name] = val
return type(future_cls_name,
future_cls_parents, attrs)
21. А теперь класс
class UpperAttrMetaclass(type):
def __new__(up_metacls, future_cls_name,
future_cls_parents, future_cls_attr):
attrs = {}
for name, val in future_cls_attr.items():
if not name.startswith('__'):
attrs[name.upper()] = val
else:
attrs[name] = val
return type.__new__(up_metacls, future_cls_name,
future_cls_parents, attrs)
22. А теперь класс
class UpperAttrMetaclass(type):
def __new__(mcs, name, bases, dct):
attrs = {}
for name, val in dct.items():
if not name.startswith('__'):
attrs[name.upper()] = val
else:
attrs[name] = val
return super(UpperAttrMetaclass, mcs).
__new__(mcs, name, bases, attrs)
23. Магические методы
В обычном классе:
• __new__(cls, *args, **kwargs) — создает
инстанс объекта класса
• __init__(self, *args, **kwargs) —
инициализирует инстанс объект класса
• __call__(self, *args, **kwargs) —
вызывается при попытке вызвать инстанс класса
24. Магические методы
В метаклассе:
• __new__(mms, name, bases, dct) — создает
объект-класс
• __init__(cls, name, bases, dct) —
инициализирует объект-класс
• __call__(cls, *args, **kwargs) —
вызывается при попытке создать инстанс класса
26. Переопределение __call__
class MetaSingleton(type):
instance = None
def __call__(cls, *args, **kwargs):
if cls.instance is None:
cls.instance = super(MetaSingleton,cls).
__call__(*args, **kwargs)
return cls.instance
class Foo(object):
__metaclass__ = MetaSingleton
a = Foo()
b = Foo()
assert a is b
27. А что в python3?
1. Определить нужный метакласс
2. Подготовить пространство имен
3. Выполнить тело класса
4. Создать объект-класс
29. Подготовка пространства имен
def __prepare__(mcs, cls, bases, **kwargs):
return dict()
Возвращает dict-like объект, в который будут записаны
атрибуты класса при интерпретации его тела.
Дополнительные параметры берутся из заголовка
class MyClass(metaclass=Meta, **kwargs):
30. Выполнение тела класса
exec(body, globals(), namespace)
namespace — то, что вернула функция __prepare__.
Если её нет, используется обычный dict.
31. Создание класса
def __new__(cls, name, bases, namespace,
**kwargs):
return type(name, bases, namespace)
Вместо словаря атрибутов мы получаем тот dict-like
объект, который создали в __prepare__.
Дополнительные параметры те же, что в __prepare__.