2009-10-21 12 views
6

mi clase Python tiene algunas variables que requieren trabajo para calcular la primera vez que se llaman. Las llamadas posteriores solo deben devolver el valor precalculado.Manera pitónica de trabajar solo la primera vez que se llama una variable

No quiero perder el tiempo haciendo este trabajo a menos que realmente lo necesite el usuario. Entonces, ¿hay una forma clara y ptónica para implementar este caso de uso?

Mi idea inicial era utilizar la propiedad() para llamar a una función del primer tiempo y luego anular la variable:

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

    age = property(get_age) 

Gracias

+2

¿Estás preguntando sobre la memorización? http://en.wikipedia.org/wiki/Memoization. Este es un patrón de diseño de OO bastante común. –

Respuesta

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 mencionado puede utilizar __getattr__, esto es cómo funciona

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__() se invoca cuando el al el tributo no existe en el objeto, es decir. la primera vez que intenta acceder al age. Cada vez que después, por lo que existe age__getattr__ no se consiga llamar

+0

gracias - __getattr __() funciona mejor para mí – hoju

+1

la llamada a 'return getattr (self, attr)' causaría un bucle infinito si attr no existe. Use 'return super (MyClass, self) .__ getattr __ (attr)' en su lugar. – nosklo

+0

Corregido, gracias nosklo –

6

property, como usted' visto, no te permitirá anularlo. Es necesario utilizar un enfoque ligeramente diferente, como por ejemplo:

class myclass(object): 

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

Hay otros enfoques, tales como __getattr__ o una clase de descriptor de costumbre, pero éste es más simple -)

+1

¿eh, que es un error de sintaxis? – nosklo

+0

@nosklo, oops, estado haciendo demasiadas C últimamente - arreglado, tx –

4

Here es decoradora de Python Cookbook! para este problema:

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 
Cuestiones relacionadas