2012-03-12 9 views
6

A volte mi piace scrivere attributi getter per un oggetto tale che la prima volta che vengono chiamati, il sollevamento pesante viene eseguito una volta e tale valore viene salvato e restituito nelle chiamate future. Nell'obiettivo c userei un ivar o una variabile statica per mantenere questo valore. Qualcosa del tipo:Qual è il modello corretto in Python per implementare i gettatori pigri?

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

Questo stesso modello regge bene in Python, oppure esiste un modo più accettabile per farlo? Ho praticamente la stessa cosa finora. Quello che non mi piace di mia soluzione è che il mio oggetto si riempie con i valori e getter per quei valori:

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

risposta

1

È possibile utilizzare esattamente lo stesso modello in Python. Sembra che tu sia preoccupato di dover sempre fare my_object.get_foo() Pythonic. Fortunatamente, Python ti dà un buon strumento per lavorare con qui in forma di properties:

class my_class(object): 

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

Questo ti permette di avere qualcosa che è utilizzato come attributo, anche se viene implementato come una funzione. vale a dire, gli utenti faranno il numero my_object.foo e non si preoccuperanno del fatto che esegua una funzione dietro le quinte.

L'altra cosa da notare è che la convenzione di Python dice che gli attributi privati ​​sono scritti _foo anziché mFoo.

+0

grazie, @property non va su quella classe anche se lo fa? –

+0

@darren infatti non è così, è quello che ottengo per postare nella parte sbagliata di mezzanotte. :) L'ho risolto ora. – lvc

1

farei qualcosa di simile:

@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 

Ora è possibile accedere a "foo" wether è stato già calcolato o no, utilizzando:

object.foo 
3

Invece di fare un hasattr esplicita" "prova ogni volta, lascia che il runtime di Python lo faccia per te. Definire __getattr__ nella classe, che viene chiamato solo quando viene fatto riferimento a un attributo non definito.

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 

Stampa il seguente:

first time 
property a 
__getattr__ 
_a_compute 
1000 

second time 
property a 
1000 

Si potrebbe lasciare fuori la proprietà e hanno __getattr__ prova per 'a' direttamente, ma poi si sarebbe non hanno la visibilità a 'a' come attributo in dir per cose come l'introspezione o il completamento automatico IDE.

+0

grazie, sono stato inizialmente confuso tra __getattr__ e __getattribute__. Questo ha senso comunque. –

Problemi correlati