2012-03-20 16 views
10

El siguiente ejemplo es de un controlador de base de datos REST en Python 2.7.¿Por qué getattr() es mucho más lento que self .__ dict __. Get()?

En el método __setattr__ a continuación, si uso el comentado getattr() línea, se reduce el rendimiento de instancias de objetos a partir de 600 rps a 230.

¿Por qué es tan getattr() mucho más lento que self.__dict__.get() en este caso?

class Element(object): 

    def __init__(self, client): 
     self._client = client 
     self._data = {} 
     self._initialized = True 

    def __setattr__(self, key, value): 
     #_initialized = getattr(self, "_initialized", False) 
     _initialized = self.__dict__.get("_initialized", False) 
     if key in self.__dict__ or _initialized is False: 
      # set the attribute normally 
      object.__setattr__(self, key, value) 
     else: 
      # set the attribute as a data property 
      self._data[key] = value 
+1

Como nota al margen, si tiene una diferencia en el rendimiento, haga una caché 'self .__ dict__' en una variable local, incluso para solo dos accesos. ('dict_ = self .__ dict__' al comienzo de' __setattr__') – jsbueno

Respuesta

12

En resumen: porque getattr(foo,bar)does the same thing as foo.bar, que no es lo mismo que acaba de acceder a la propiedad __dict__ (para empezar, getattr tiene que seleccionar el derecho __dict__, pero hay mucho más en juego).

Detalles contenidos en, o vinculados a aquí: http://docs.python.org/reference/datamodel.html (busque "getattr").

+2

@bereal: necesita volver a leer las cosas. Las operaciones necesarias para foo .__ dict __. Get() son un subconjunto propio de getattr(). – bukzor

+2

@bereal Tenga en cuenta que los bytecodes de python no se corresponden con operaciones primitivas. Puede tener una cantidad muy pequeña de bytecode para llamar a una función muy compleja, mientras que una expresión simple puede generar mucho más bytecode. Además, lo que Bukzor dijo es correcto y relevante. – Marcin

+0

@bereal De ninguna manera esto desmiente que 'foo .__ dict__' haga lo mismo que' getattr (foo, '__dict __') ', porque es posible llamar a' getattr (foo, '__ dict __') 'para ser más eficiente que eliminar la referencia de un atributo arbitrario. – Marcin

Cuestiones relacionadas