2009-10-21 5 views
6

Moja klasa Pythona zawiera pewne zmienne, które wymagają pracy, aby obliczyć jej pierwszy raz. Kolejne wywołania powinny po prostu zwracać wstępnie obliczoną wartość.Pythoniczny sposób na pracę za pierwszym razem, gdy zmienna nazywa się

Nie chcę tracić czasu na wykonywanie tej pracy, chyba że są rzeczywiście potrzebne użytkownikowi. Czy istnieje zatem czysty sposób Python do wdrożenia tego przypadku użycia?

Moją pierwszą myślą było użyć właściwości(), aby wywołać funkcję po raz pierwszy, a następnie zastąpić zmienną:

class myclass(object): 
    def get_age(self): 
     self.age = 21 # raise an AttributeError here 
     return self.age 

    age = property(get_age) 

Dzięki

+2

Czy pytasz o zapamiętywanie? http://en.wikipedia.org/wiki/Memoizacja. Jest to dość powszechny wzorzec projektowania OO. –

Odpowiedz

13
class myclass(object): 
    def __init__(self): 
     self.__age=None 
    @property 
    def age(self): 
     if self.__age is None: 
      self.__age=21 #This can be a long computation 
     return self.__age 

Alex wymienionych można użyć __getattr__, to jest jak to działa

class myclass(object): 
    def __getattr__(self, attr): 
     if attr=="age": 
      self.age=21 #This can be a long computation 
     return super(myclass, self).__getattribute__(attr) 

__getattr__() jest wywoływana, gdy w tribute nie istnieje na obiekcie, tj. przy pierwszej próbie dostępu do age. Za każdym razem, potem age istnieje więc __getattr__ nie sprawdzony

+0

dzięki - __getattr __() działa najlepiej dla mnie – hoju

+1

wywołanie 'return getattr (self, attr)' spowodowałoby nieskończoną pętlę, jeśli attr nie istnieje. Zamiast tego użyj 'return super (MyClass, self) .__ getattr __ (attr)'. – nosklo

+0

Naprawiono, dziękuję nosklo –

6

property, jak ty” widziałem, nie pozwolę ci tego zmienić. Trzeba użyć nieco inne podejście, takie jak:

class myclass(object): 

    @property 
    def age(self): 
     if not hasattr(self, '_age'): 
     self._age = self._big_long_computation() 
     return self._age 

Istnieją inne metody, takie jak __getattr__ lub klasy niestandardowych deskryptora, ale ten jest prostszy -)

+1

huh, to jest błąd składniowy? – nosklo

+0

@nosklo, oops, ostatnio robiłem zbyt dużo C - naprawiono, tx –

4

Here jest dekorator z Python Cookbook! dla tego problemu:

class CachedAttribute(object): 
    ''' Computes attribute value and caches it in the instance. ''' 
    def __init__(self, method, name=None): 
     # record the unbound-method and the name 
     self.method = method 
     self.name = name or method.__name__ 
    def __get__(self, inst, cls): 
     if inst is None: 
      # instance attribute accessed on class, return self 
      return self 
     # compute, cache and return the instance's attribute value 
     result = self.method(inst) 
     setattr(inst, self.name, result) 
     return result 
Powiązane problemy