2009-10-21 4 views
6

meine Python-Klasse hat einige Variablen, die Arbeit erfordern, um das erste Mal zu berechnen, sie aufgerufen werden. Nachfolgende Aufrufe sollten nur den vorausberechneten Wert zurückgeben.Pythonic Weg nur Arbeit zu tun, erstmals eine Variable heißt

Ich möchte keine Zeit mit dieser Arbeit verschwenden, es sei denn, sie werden tatsächlich vom Benutzer benötigt. Gibt es also einen sauberen pythonischen Weg, um diesen Anwendungsfall zu implementieren?

Mein erster Gedanke war Eigentum() zu verwenden, eine Funktion zum ersten Mal aufrufen und dann die Variable außer Kraft setzen:

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

    age = property(get_age) 

Dank

+2

Fragen Sie nach Memoisierung? http://en.wikipedia.org/wiki/Memoization. Dies ist ziemlich häufig OO Design-Muster. –

Antwort

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 erwähnt Sie __getattr__ verwenden können, ist dies wie es funktioniert

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__() wird aufgerufen, wenn die bei Tribut existiert nicht auf dem Objekt, dh. Wenn Sie das erste Mal versuchen, auf age zuzugreifen. Jedes Mal nach, age existiert so nicht __getattr__ nicht

+0

danke - __getattr __() funktioniert am besten für mich – hoju

+1

der Aufruf an 'return getattr (selbst, attr)' würde eine Endlosschleife verursachen, wenn attr nicht existiert. Verwenden Sie stattdessen return super (MyClass, self) .__ getattr __ (attr) '. – nosklo

+0

Korrigiert, danke nosklo –

6

property, wie Sie‘ gesehen haben, werden Sie es nicht überschreiben lassen. Sie benötigen einen etwas anderen Ansatz verwenden, wie zum Beispiel:

class myclass(object): 

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

Es gibt auch andere Ansätze, wie __getattr__ oder eine benutzerdefinierten Descriptor-Klasse, aber dies ist einfacher -)

+1

huh, das ist ein Syntaxfehler? – nosklo

+0

@nosklo, oops, habe in letzter Zeit zu viel C gemacht - behoben, tx –

4

Here ist Dekorateur aus Python Cookbook! für dieses Problem:

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