2015-01-29 2 views
2

Я хотел бы прояснить некоторые вещи о дескрипторах Python. Я хочу добавить свойство к моему классу с помощью некоторой сложной механики set/get и кэшировать эти вычисленные значения внутри объекта дескриптора. Упрощенный пример выглядит следующим образом:Python: значения кэша дескрипторов

class Pro(object): 
    """My descriptor class""" 

    def __init__(self): 
     self.value = None 

    def __get__(self, instance, owner): 
     return self.value 

    def __set__(self, instance, value): 
     self.value = value 


class Something(object): 
    """My simple class""" 
    pro = Pro() 

a = Something() 
a.pro = 1 

b = Something() 
b.pro = 2 

print(a.pro, b.pro) # At first, I've expected them to be 1 and 2 

Я думал, что-то pro атрибут будет уникальным экземпляром Pro для каждого экземпляра Something, очевидно, что я был неправ. Похоже, я должен использовать что-то вроде instance._value вместо self.value внутри __set__ и __get__, но я действительно надеялся спрятать все внутри Pro класс. Возможно ли это? Благодаря!

+0

Have вы посмотрели [это] (https://pypi.python.org/pypi/cached-property/0.1.5)? – Lemming

+0

@ Lemming, выглядит довольно аккуратно, спасибо, но я надеялся решить эту проблему только стандартной библиотекой :) –

+0

Достаточно честный. Btw, поскольку большинство пакетов python это открытый исходный код. [Фактический код] (https://github.com/pydanny/cached-property/blob/master/cached_property.py) довольно мал, а для версии без потоковой передачи не требуются дополнительные пакеты. – Lemming

ответ

3

Проблема с вашим кодом заключается в том, что вы устанавливаете атрибут экземпляра Pro, который будет использоваться всеми экземплярами Something. Чтобы исправить это, вы должны установить атрибут на индивидуальном экземпляре Something, один из способов сделать это является использование метакласса:

class Meta(type): 
    def __new__(cls, name, bases, dct): 
     for k, v in dct.items(): 
      if isinstance(v, Pro): 
       # add an _ in front of the name 
       v.name = '_' + k 
     return super(Meta, cls).__new__(cls, name, bases, dct) 


class Pro(object): 

    def __get__(self, ins, typ): 
     return getattr(ins, self.name) 

    def __set__(self, ins, val): 
      setattr(ins, self.name, val) 

class Something(object): 
    """My simple class""" 
    __metaclass__ = Meta 
    pro = Pro() 

a = Something() 
a.pro = 1 

b = Something() 
b.pro = 2 

Демо:

>>> a.pro, b.pro 
(1, 2) 
>>> a.__dict__ 
{'_pro': 1} 
>>> b.__dict__ 
{'_pro': 2} 
>>> a.pro = 100 
>>> a.__dict__ 
{'_pro': 100} 

Так нет никакого способа сделать скрытые атрибуты в Кое-что экземпляров, правильно?

Нет, есть. Вы можете хранить словарь в экземпляре Pro, который хранит все значения, относящиеся к каждому экземпляру Something. Например, если экземпляры Something являются хешируемыми, вы можете сделать что-то вроде этого, используя weakref.WeakKeyDictionary. WeakKeyDictionary убедитесь, что этот экземпляр один раз в Something «s имеет никаких ссылок не осталось, то оно мусора сразу, не возможно с нормальным dict:

from weakref import WeakKeyDictionary 

class Pro(object): 

    def __init__(self): 
     self.instances = WeakKeyDictionary() 

    def __get__(self, ins, typ): 
     return self.instances[ins] 

    def __set__(self, ins, val): 
     self.instances[ins] = val 

p = Pro() 

class Something(object): 
    """My simple class""" 
    pro = p 

a = Something() 
a.pro = 1 

b = Something() 
b.pro = 2 

print a.pro, b.pro 

print p.instances.items() 
del a 
print p.instances.items() 

Выход:

1 2 
[(<__main__.Something object at 0x7fb80d0d5310>, 1), (<__main__.Something object at 0x7fb80d0d5350>, 2)] 
[(<__main__.Something object at 0x7fb80d0d5350>, 2)] 
+0

Таким образом, нет возможности создавать скрытые атрибуты в экземплярах «Что-то», верно? –

+0

Если вы хотите «кэшировать» значение для экземпляра, то это значение должно быть связано с экземпляром. Атрибуты Python в основном делают это, используя словарь __dict__ объекта. Вы можете изменить его, указав словарь в описании с экземпляром в качестве ключа, но основная проблема остается в том, что вам нужно сопоставить экземпляр значения или наоборот –

+0

@ АнтонМельников. Определенно, что это возможно, см. Обновление. –

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

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