16
Дескрипторы. Что это? Донец Владимир twitter.com/vovk_donets vk.com/vovk.donets Магия в Python e-commerce SAAS kwimba.ru

Магия в Python: Дескрипторы. Что это?

  • Upload
    pynsk

  • View
    592

  • Download
    7

Embed Size (px)

Citation preview

Page 1: Магия в Python: Дескрипторы. Что это?

Дескрипторы. Что это?

Донец Владимир

twitter.com/vovk_donetsvk.com/vovk.donets

Магия в Python

e-commerce SAAS kwimba.ru

Page 2: Магия в Python: Дескрипторы. Что это?

2

О чем пойдет речь

➢ Что такое дескриптор➢ Как его можно применять в своём коде➢ Как устроены дескрипторы➢ Примеры кода из жизни

Page 3: Магия в Python: Дескрипторы. Что это?

3

Модифицировать поведение атрибута price класса Product таким образом, чтобы сохранить существующий API.

Задача

Есть идеи?

Page 4: Магия в Python: Дескрипторы. Что это?

4

class Product(object):

>>> p = Product(...)

>>> p.price

1 000

Немного псевдокода

Есть идеи?

Page 5: Магия в Python: Дескрипторы. Что это?

5

Переопределить

__getattr__

__setattr__

__getattribute__

Например, можно...

Это решение или новая проблема?

Page 6: Магия в Python: Дескрипторы. Что это?

6

» Вызываются при доступе к любому аттрибуту*

» Логика доступа и присванивания сильно усложняется

» *К тому же __getattr__ вызывается только в случае, если атрибут не был найден обычным способом

» Снижает скорость присвоения всех атрибутов

Минусы __get/__setattr__

Page 7: Магия в Python: Дескрипторы. Что это?

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

Что это за класс?

Page 8: Магия в Python: Дескрипторы. Что это?

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 = дескрипторы

Page 9: Магия в Python: Дескрипторы. Что это?

9

class PriceField(...):

...

price = PriceFieldDescriptor(...)

...

>>> p = Product(...)

>>> p.price ─> вызовет __get__ дескриптора

>>> p.price = 100 ─> вызовет __set__ дескриптора

>>> del p.price ─> вызовет __del__ дескриптора

Решение

Page 10: Магия в Python: Дескрипторы. Что это?

10

Почему это работает?

Page 11: Магия в Python: Дескрипторы. Что это?

11

__getattribute__

А вот благодаря чему:

Доступ к атрибуту экземпляра b.x превратится:

type(b).__dict__['x'].__get__(b, type(b))

Доступ к атрибуту класса B.x:

B.__dict__['x'].__get__(None, B)

Page 12: Магия в Python: Дескрипторы. Что это?

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__).

Page 13: Магия в Python: Дескрипторы. Что это?

13

class PriceField(PositiveDecimalField):

def __init__(self, *args, **kwargs):

super(PriceField, self).__init__(*args, **kwargs)

def contribute_to_class(self, cls, name):

super(PriceField, self).contribute_to_class(cls, name)

setattr(cls, name, PriceFieldDescriptor(name))

Решение

Page 14: Магия в Python: Дескрипторы. Что это?

14

def readonly(value):

return property(lambda self: value)

class ReadOnlyClass(object):

a = readonly(1)

b = readonly('text')

Пример из жизни №2

Page 15: Магия в Python: Дескрипторы. Что это?

15

class Property(object):

"Emulate PyProperty_Type() in Objects/descrobject.c"

def __init__(self, fget=None, fset=None, fdel=None, doc=None):

self.fget = fget

self.fset = fset

self.fdel = fdel

self.__doc__ = doc

def __get__(self, obj, objtype=None):

if obj is None:

return self

if self.fget is None:

raise AttributeError, "unreadable attribute"

return self.fget(obj)

Пример из жизни №3

def __set__(self, obj, value):

if self.fset is None:

raise AttributeError, "can't set attribute"

self.fset(obj, value)

def __delete__(self, obj):

if self.fdel is None:

raise AttributeError, "can't delete

attribute"

self.fdel(obj)

Page 16: Магия в Python: Дескрипторы. Что это?

16

Ресурсы

● http://users.rcn.com/python/download/Descriptor.htm#invoking-descriptors

● https://www.python.org/download/releases/2.2.3/descrintro/#cooperation

● http://martyalchin.com/2007/nov/23/python-descriptors-part-1-of-2/

● http://blog.kevinastone.com/django-model-descriptors.html

● http://pyvideo.org/video/3123/descriptors-attribute-access-redefined-by-fraser

● http://www.catharinegeek.com/the-magic-of-django-model/

● http://habrahabr.ru/post/137415/