2012-03-12 14 views
6

Czasami lubię pisać atrybuty gettera dla obiektu, tak, że po raz pierwszy są wywoływane, podnoszenie ciężkich zadań odbywa się raz, a wartość ta jest zapisywana i zwracana przy przyszłych połączeniach. W celu c użyję zmiennej ivar lub statycznej, aby utrzymać tę wartość. Coś takiego:Jaki jest właściwy wzorzec w Pythonie do implementacji leniwych pobierających?

- (id)foo 
{ 
    if (_foo == nil) 
    { 
     _foo = // hard work to figure out foo 
    } 
    return _foo 
} 

Czy ten sam wzór dobrze pasuje w Pythonie, czy też jest bardziej akceptowany sposób robienia tego? Zasadniczo mam to samo. Co mi się nie podoba w moim rozwiązania jest to, że mój przedmiot dostaje bałagan z wartościami i pobierające za tymi wartościami:

def foo(self): 
    if not hasattr(self, "mFoo": 
     self.mFoo = # heavy lifting to compute foo 
    return self.mFoo 

Odpowiedz

1

Możesz użyć dokładnie tego samego wzoru w Pythonie. Wygląda na to, że martwisz się tym, czy cały czas musisz robić my_object.get_foo() Pythonica. Na szczęście, Python daje ładny narzędzie do pracy z tutaj w formie z properties:

class my_class(object): 

    @property 
    def foo(self): 
     # calculate if needed 
     return self._foo 

To pozwala mieć coś, co jest wykorzystywane jako atrybut, nawet jeśli jest ona realizowana jako funkcja. tj. użytkownicy wykonają numer my_object.foo i nie będą obchodzić go za jego działaniem za kulisami.

Należy również zauważyć, że konwencja Pythona mówi, że prywatne atrybuty są pisane jako _foo, a nie mFoo.

+0

dzięki, @property nie pasuje do tej klasy, ale robi to? –

+0

@darren w rzeczy samej nie, to właśnie dostaję za wysłanie po złej stronie północy. :) Naprawiłem to teraz. – lvc

1

zrobiłbym coś takiego:

@property 
def foo(self): 
    return self._foo_value if hasattr(self, '_foo_value') else calculate_foo() 

def calculate_foo(self): 
    self._foo_value = # heavy foo calculation 
    return self._foo_value 

Teraz można uzyskać dostęp „foo” pogoda była już obliczone lub nie, za pomocą:

object.foo 
3

zamiast robić wyraźne „hasattr "testuj za każdym razem, pozwól, aby środowisko wykonawcze Python zrobiło to za Ciebie. Zdefiniuj __getattr__ w klasie, która jest wywoływana tylko wtedy, gdy odwołuje się niezdefiniowany atrybut.

class Sth(object): 
    @property 
    def a(self): 
     print "property a" 
     return self._a 

    def _a_compute(self): 
     # put expensive computation code here 
     print "_a_compute" 
     return 1000 

    def __getattr__(self, attr): 
     print "__getattr__" 
     if attr == '_a': 
      self._a = self._a_compute() 
      return self._a 


ss = Sth() 
print "first time" 
print ss.a 
print 
print "second time" 
print ss.a 

Drukuje następujące:

first time 
property a 
__getattr__ 
_a_compute 
1000 

second time 
property a 
1000 

Mogłeś opuścić nieruchomość i mieć __getattr__ test na „a” bezpośrednio, ale wtedy nie miałoby widoczność do „a” jako atrybut w dir dla rzeczy takich jak introspekcja lub autouzupełnianie IDE.

+0

dziękuję, początkowo byłem zdezorientowany między __getattr__ a __getattribute__. Ma to jednak sens. –

Powiązane problemy