2012-03-12 10 views
6

A veces me gusta escribir atributos getter para un objeto de manera que la primera vez que se invocan, el trabajo pesado se realiza una vez, y ese valor se guarda y se devuelve en futuras llamadas. En objetivo-c usaría una variable ivar o estática para mantener este valor. Algo como:¿Cuál es el patrón apropiado en Python para implementar getters perezosos?

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

¿Este mismo patrón se sostiene bien en Python, o hay una forma más aceptada de hacerlo? Tengo básicamente lo mismo hasta ahora. Lo que no me gusta de mi solución es que mi objetivo se desordena con valores y captadores de esos valores:

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

Respuesta

1

Puede usar exactamente el mismo patrón en Python. Parece preocupado por si tener que hacer my_object.get_foo() todo el tiempo es Pythonic. Afortunadamente, Python le da una buena herramienta para trabajar aquí en forma de properties:

class my_class(object): 

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

Esto le permite tener algo que es utilizado como un atributo, incluso si se implementa como una función. es decir, los usuarios harán my_object.foo, y no les importa que esté ejecutando una función detrás de escena.

La otra cosa a tener en cuenta es que la convención de Python dice que los atributos privados se deletrean _foo en lugar de mFoo.

+0

gracias, @property no va en esa clase, ¿verdad? –

+0

@darren de hecho no es así, eso es lo que recibo por publicar en el lado equivocado de la medianoche. :) Lo he arreglado ahora. – lvc

1

me gustaría hacer algo como esto:

@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 

Ahora puede acceder a "foo" carnero que ya se ha calculado o no, usando:

object.foo 
3

En vez de hacer un hasattr explícito" "prueba cada vez, deja que el tiempo de ejecución de Python haga eso por ti. Defina __getattr__ en su clase, que solo se invoca cuando se hace referencia a un atributo indefinido.

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 

imprime el siguiente:

first time 
property a 
__getattr__ 
_a_compute 
1000 

second time 
property a 
1000 

Se podría dejar de lado la propiedad y tienen __getattr__ prueba para 'a' directamente, pero entonces usted no tiene la visibilidad a 'a' como un atributo en dir para cosas como introspección o autocompletar IDE.

+0

gracias, al principio me confundí entre __getattr__ y __getattribute__. Esto tiene sentido sin embargo. –

Cuestiones relacionadas