Докладчик:
Владимир Донец (kwimba.ru)
Описание: Слышали про магию в Python? Одно из магических заклинаний называется дескрипторы. Мощная фича языка, которая позволяет определять свое поведение атрибута объекта при доступе к этому атрибуту.
Сложно звучит? А вы знали, что дескрипторами уже наверняка пользовались, если хотя бы раз писали на Python. Я расскажу о том, что такое дескрипторы и как их осознанно можно применять в собственном коде.
6. 6
» Вызываются при доступе к любому аттрибуту*
» Логика доступа и присванивания сильно
усложняется
» *К тому же __getattr__ вызывается только в случае,
если атрибут не был найден обычным способом
» Снижает скорость присвоения всех атрибутов
Минусы __get/__setattr__
7. 7
class PriceFieldDescriptor(object):
def __init__(self, name):
self.name = name
def __get__(self, instance=None, owner=None):
return instance.__dict__[self.name]
def __set__(self, instance, value):
instance.__dict__[self.name] = value
Что это за класс?
8. 8
Внимание, дескриптор!
Просто класс, в котором определены методы:
__get__, __set__, __delete__
descr.__get__(self, inst, type) ─> value
descr.__set__(self, inst, value) ─> None
descr.__delete__(self, inst) ─> None
properties, methods, static methods, class methods = дескрипторы
9. 9
class PriceField(...):
...
price = PriceFieldDescriptor(...)
...
>>> p = Product(...)
>>> p.price ─> вызовет __get__ дескриптора
>>> p.price = 100 ─> вызовет __set__ дескриптора
>>> del p.price ─> вызовет __del__ дескриптора
Решение
11. 11
__getattribute__
А вот благодаря чему:
Доступ к атрибуту экземпляра b.x превратится:
type(b).__dict__['x'].__get__(b, type(b))
Доступ к атрибуту класса B.x:
B.__dict__['x'].__get__(None, B)
12. 12
Вызов дескриптора:
Прямой вызов дескриптора:
x.__get__(a)
Вызов дескриптора из экземпляра:
type(a).__dict__['x'].__get__(a, type(a))
Вызов дескриптора из класса:
A.__dict__['x'].__get__(None, A)
И super:
super(B, obj).m() searches obj.__class__.__mro__
A.__dict__['x'].__get__(obj, obj.__class__).