Dans les classes python, @property est un décorateur sympa qui évite d'utiliser des fonctions setter et getter explicites. Cependant, cela coûte 2 à 5 fois les frais généraux d'une classe "classique"). Dans mon cas, c'est tout à fait correct dans le cas de la définition d'une propriété, où la surcharge est insignifiante par rapport au traitement qui doit être effectué lors de la définition.
Cependant, je n'ai besoin d'aucun traitement lors de l'obtention de la propriété. C'est toujours juste "return self.property". Existe-t-il une manière élégante d'utiliser le setter sans utiliser le getter, sans avoir besoin d'utiliser une variable interne différente?
Juste pour illustrer, la classe ci-dessous a la propriété "var" qui fait référence à la variable interne "_var". Il faut plus de temps pour appeler "var" que "_var" mais ce serait bien si les développeurs et les utilisateurs pouvaient simplement utiliser "var" sans avoir à garder une trace de "_var" aussi.
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'
Pour ceux qui sont intéressés, sur mon PC, appeler "var" prend 204 ns en moyenne tandis que appeler "_var" prend 44 ns en moyenne.
N'utilisez pas de property
dans ce cas. Un objet property
est un descripteur de données, ce qui signifie que tout accès à instance.var
Invoquera ce descripteur et Python ne cherchera jamais d'attribut sur l'instance elle-même .
Vous avez deux options: utilisez le crochet .__setattr__()
ou créez un descripteur qui implémente uniquement .__set__
.
.__setattr__()
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)
Désormais, des recherches d'attributs normales sont utilisées lors de la lecture de la lecture .var
Mais lors de l'attribution à .var
De la méthode __setattr__
est invoqué à la place, vous permettant d'intercepter value
et de l'ajuster au besoin.
Démo:
>>> mc = MyClass()
>>> mc.var
'foo'
>>> mc.var = 'bar'
Setting var!
>>> mc.var
'Set to bar'
Un descripteur de définition n'intercepterait que l'affectation 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
Notez comment nous devons attribuer à l'instance .__dict__
Attribut pour éviter d'appeler à nouveau le setter.
Démo:
>>> 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)
production:
ok
Traceback (most recent call last):
File "Untitled.py", line 15, in <module>
print c.var
AttributeError: unreadable attribute