-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdescriptor.py
More file actions
74 lines (63 loc) · 5.08 KB
/
descriptor.py
File metadata and controls
74 lines (63 loc) · 5.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# -*- coding: utf-8 -*-
#-------------------------------------------------------------------------------
# Copyright (c) 2015 Artur Eganyan
#
# This work is provided "AS IS", WITHOUT ANY WARRANTY, express or implied.
#-------------------------------------------------------------------------------
# Дескриптор - это атрибут класса, доступ к которому контролируется. Формально
# это любой new-style объект, у которого есть метод __get__, __set__ или
# __delete__. Когда такой объект становится атрибутом класса, при обращении
# к этому атрибуту вызываются его методы чтения/записи/удаления.
class MyDescriptor(object):
# Вызывается при чтении "instance.атрибут"
def __get__(self, instance, owner):
print u"К атрибуту", self, u"обратились через экземпляр", instance
print u"Атрибут находится в классе", owner
print u"Этот метод должен вернуть что-то в качестве атрибута"
return 123
# Вызывается при записи "instance.атрибут = value"
def __set__(self, instance, value):
print u"В атрибут", self, u"хотят записать значение", value,
print u"через экземпляр", instance
print u"Этот метод может сохранить новое значение"
# Вызывается при удалении "del instance.атрибут"
def __delete__(self, instance):
print u"Атрибут", self, u"хотят удалить через экземпляр", instance
print u"Этот метод может как-нибудь удалить атрибут. ",
print u"При этом сам дескриптор останется."
class A(object):
x = MyDescriptor() # Это будут атрибуты класса, доступ к которым
y = MyDescriptor() # контролируется методами __get__/__set__/__delete__
a = A()
print a.x # 123, вызовет MyDescriptor.__get__(x, a, A)
print A.x # 123, вызовет MyDescriptor.__get__(x, None, A)
a.x = 5 # Вызовет MyDescriptor.__set__(x, a, 5)
#A.x = 5 # Атрибут A.x станет числом 5, __set__ не будет вызван
del a.x # Вызовет MyDescriptor.__delete__(x, a), A.x не будет удален
print a.x # 123
# Замечание: Дескриптор, у которого есть метод __set__ или __del__, называется
# дескриптором данных (data descriptor). Такие дескрипторы имеют приоритет
# перед личными атрибутами объекта при чтении и записи. Например, если у
# класса есть дескриптор данных "x", а у экземпляра этого класса есть
# атрибут "x", чтение/запись "экземпляр.x" будет работать с дескриптором.
# Про чтение/запись атрибутов см. в заметке "classes".
#
# Замечание: Любая функция имеет метод __get__, который возвращает специальный
# объект-метод для этой функции. Поэтому функция - это дескриптор, и когда она
# является атрибутом класса, при обращении к ней создается метод.
#
# Замечание: Объект ведет себя как дескриптор только при обращении к нему как
# к атрибуту класса. В остальных случаях методы __get__/__set__/__delete__
# не используются. Это выглядит так, будто класс "вызывает" методы своего
# атрибута, когда к нему обращаются.
#
# Замечание: Класс, содержащий атрибут-дескриптор, может быть и old-style, но
# тогда, судя по тестам, будет вызываться только метод __get__, а __set__ и
# __delete__ - нет. Возможно это вызвано историческими причинами, когда в
# python поэтапно добавлялись новые возможности.
#
# Замечание: То, что в python называется "дескриптор", также известно как
# "свойство" (property), "акцессор" (accessor), "мутатор" (mutator method)
# или "геттер/сеттер" (getter/setter). Дескриптором нередко называют
# объект, по которому делается доступ к чему-либо (file descriptor, segment
# descriptor).