property decorators and python class properties timing

decorators - Python class @property: usa setter pero evade getter?



python property decorator (2)

En las clases de python, @property es un lindo decorador que evita el uso de funciones explícitas de setter y getter. Sin embargo, tiene un costo de una sobrecarga de 2-5 veces la de una función de clase "clásica". En mi caso, esto está bastante bien en el caso de establecer una propiedad, donde la sobrecarga es insignificante en comparación con el procesamiento que se debe realizar al configurar.

Sin embargo, no necesito procesamiento al obtener la propiedad. Siempre es solo "return self.property". ¿Existe una forma elegante de usar el colocador pero sin utilizar el captador, sin la necesidad de utilizar una variable interna diferente?

Solo para ilustrar, la clase siguiente tiene la propiedad "var" que se refiere a la variable interna "_var". Se necesita más tiempo para llamar a "var" que a "_var", pero sería bueno si los desarrolladores y los usuarios pudieran simplemente usar "var" sin tener que hacer un seguimiento de "_var" también.

class MyClass(object): def __init__(self): self._var = None # the property "var". First the getter, then the setter @property def var(self): return self._var @var.setter def var(self, newValue): self._var = newValue #... and a lot of other stuff here # Use "var" a lot! How to avoid the overhead of the getter and not to call self._var! def useAttribute(self): for i in xrange(100000): self.var == ''something''

Para aquellos interesados, en mi PC llamar a "var" toma 204 ns en promedio mientras que llamar a "_var" toma 44 ns en promedio.


No use una property en este caso. Un objeto de property es un descriptor de datos, lo que significa que cualquier acceso a instance.var invocará ese descriptor y Python nunca buscará un atributo en la instancia en sí.

Tiene dos opciones: use el .__setattr__() gancho o .__setattr__() un descriptor que solo implemente .__set__ .

Usando el .__setattr__() gancho

class MyClass(object): var = ''foo'' def __setattr__(self, name, value): if name == ''var'': print "Setting var!" # do something with `value` here, like you would in a # setter. value = ''Set to '' + value super(MyClass, self).__setattr__(name, value)

Ahora las búsquedas normales de atributos se usan cuando se lee .var pero cuando se asigna a .var se invoca el método __setattr__ , lo que le permite interceptar el value y ajustarlo según sea necesario.

Manifestación:

>>> mc = MyClass() >>> mc.var ''foo'' >>> mc.var = ''bar'' Setting var! >>> mc.var ''Set to bar''

Un descriptor setter

Un descriptor setter solo interceptaría la asignación de variable:

class SetterProperty(object): def __init__(self, func, doc=None): self.func = func self.__doc__ = doc if doc is not None else func.__doc__ def __set__(self, obj, value): return self.func(obj, value) class Foo(object): @SetterProperty def var(self, value): print ''Setting var!'' self.__dict__[''var''] = value

Tenga en cuenta cómo tenemos que asignar el atributo instancia .__dict__ para evitar invocar al colocador de nuevo.

Manifestación:

>>> f = Foo() >>> f.var = ''spam'' Setting var! >>> f.var = ''ham'' Setting var! >>> f.var ''ham'' >>> f.var = ''biggles'' Setting var! >>> f.var ''biggles''


property python docs: https://docs.python.org/2/howto/descriptor.html#properties

class MyClass(object): def __init__(self): self._var = None # only setter def var(self, newValue): self._var = newValue var = property(None, var) c = MyClass() c.var = 3 print (''ok'') print (c.var)

salida:

ok Traceback (most recent call last): File "Untitled.py", line 15, in <module> print c.var AttributeError: unreadable attribute