Classe Python @propriété: utiliser setter mais evader getter?

dans les classes python, la propriété @est un décorateur agréable qui évite d'utiliser explicitement les fonctions setter et getter. Cependant, il vient à un coût de 2 à 5 fois supérieur à celui d'une fonction de classe "classique". Dans mon cas, C'est tout à fait correct dans le cas de la mise en place d'une propriété, où les frais généraux sont insignifiants par rapport au traitement qui doit être fait lors de la mise en place.

cependant, je n'ai pas besoin de traitement lors de l'obtention de la propriété. Il est toujours juste "retour auto.propriété." Existe-t-il une façon élégante d'utiliser le setter mais pas le getter, sans avoir besoin d'utiliser une variable interne différente?

à titre d'exemple, la classe ci-dessous possède la propriété" var "qui se réfère à 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 pourraient utiliser "var", sans avoir à garder une trace de "_var".

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 intéressés, sur mon pc appelant " var "prend 204 ns en moyenne tandis que l'appelant" _var " prend 44 ns en moyenne.

40
demandé sur Jonas Lindeløv 2013-07-10 20:26:47

2 réponses

N'utilisez pas un 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 que Python ne cherchera jamais un attribut sur l'instance elle-même.

vous avez deux options: utilisez le .__setattr__() crochet ou construire un descripteur qui ne met en œuvre .__set__ .

utilisant le .__setattr__() crochet

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)

maintenant les recherches d'attribut normales sont utilisées lorsque lecture .var mais lors de l'affectation à .var la méthode __setattr__ est invoquée à la place, vous permettant d'intercepter value et de l'ajuster si nécessaire.

Démo:

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

Un setter descripteur

Un setter descripteur serait seulement intercepter 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 besoin d'attribuer l'attribut .__dict__ à l'instance pour éviter d'invoquer à 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'
49
répondu Martijn Pieters 2013-07-10 16:42:59

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)

sortie:

ok
Traceback (most recent call last):
  File "Untitled.py", line 15, in <module>
    print c.var
AttributeError: unreadable attribute
22
répondu WeizhongTu 2016-11-21 12:33:48