2013-02-25 1 views
1

В процессе кодирования я столкнулся с необходимостью изменить поведение свойства объекта (но не свойство класса). И я обнаружил, что уже инициализированный объект не может быть обработан дескриптором. Так почему?Почему дескрипторы (в Python) не могут быть вставлены (помещены) в УЖЕ инициализированный объект?

примеры кода

class A(object): 
    pass 

class D(object): 
    def __init__(self, fget=None, fset=None, fdel=None, doc=None): 
     pass 
    def __get__(self, obj, objtype=None): 
     return 5 

A.x = D() 
A.x 
Out[12]: 5 # work! 
a = A() 
a.y = D() 
a.y 
Out[14]: <__main__.D at 0x13a8d90> # not work! 
+0

Дескрипторы предназначены для классов, а 'a' не является классом. Как насчет использования 'a.y = 5'? –

ответ

2

От the documentation.

Для объектов, машины в object.__getattribute__(), который трансформирует b.x в type(b).__dict__['x'].__get__(b, type(b)).

То есть, поиск атрибута на экземпляра (b) преобразуется в дескриптор вызова на класса (type(b)). Дескрипторы работают на уровне класса.

Что касается причин, почему это правда, это объясняется тем, что дескрипторы в основном являются способом работы с методом (например, вызовом метода) при поиске атрибутов. И методы - это, по сути, поведение на уровне классов: вы обычно определяете методы, которые вы хотите для класса, и не добавляете дополнительные методы для отдельных экземпляров. Выполнение поиска дескриптора в экземпляре будет похоже на определение метода в экземпляре.

Теперь можно назначить новые методы экземплярам, ​​а также можно получить дескрипторы для работы с экземплярами определенного класса. Вам просто нужно сделать дополнительную работу. Поскольку документация выше цитата говорит, машины в object.__getattribute__, так что вы можете переопределить его путем определения пользовательских __getattribute__ на классе:

class Foo(object): 
    def __getattribute__(self, attr): 
     myDict = object.__getattribute__(self, '__dict__') 
     if attr in myDict and hasattr(myDict[attr], '__get__'): 
      return myDict[attr].__get__(self, type(self)) 
     else: 
      return super(Foo, self).__getattribute__(attr) 

class D(object): 
    def __init__(self, fget=None, fset=None, fdel=None, doc=None): 
     pass 
    def __get__(self, obj, objtype=None): 
     return 5 

А потом:

>>> f = Foo() 
>>> f.x = D() 
>>> f.x 
5 

Так что, если вы чувствуете потребность для этого вы можете это сделать. Это просто не поведение по умолчанию, просто потому, что это не то, что дескрипторы были предназначены для работы.

 Смежные вопросы

  • Нет связанных вопросов^_^