Donc, j'essaie de trouver la meilleure façon (la plus élégante avec le moins de code) de permettre de remplacer des fonctions spécifiques d'une propriété (par exemple, juste le getter, juste le setter, etc.) en python. Je suis un fan de la façon suivante de faire des propriétés, car toutes leurs méthodes sont encapsulées dans le même bloc de code en retrait (il est plus facile de voir où s'arrêtent les fonctions traitant d'une propriété et les fonctions traitant de la propriété prochain début):
@apply
def foo():
"""A foobar"""
def fget(self):
return self._foo
def fset(self, val):
self._foo = val
return property(**locals())
Cependant, si je veux hériter d'une classe qui définit les propriétés de cette manière, puis, par exemple, remplacer la fonction setter foo
, cela semble difficile. J'ai fait quelques recherches et la plupart des réponses que j'ai trouvées ont consisté à définir des fonctions distinctes dans la classe de base (par exemple getFoo
et setFoo
), à créer explicitement une définition de propriété à partir d'elles ( par exemple foo = property(lambda x: x.getFoo(), lambda x, y: x.setFoo(y), lambda x: x.delFoo())
), puis remplacez getFoo
, setFoo
et delFoo
si nécessaire.
Je n'aime pas cette solution, car cela signifie que je dois définir des lambas pour chaque propriété, puis écrire chaque appel de fonction (avant, j'aurais pu faire property(**locals())
). Je n'ai pas non plus l'encapsulation que j'avais à l'origine.
Idéalement, ce que j'aimerais pouvoir faire serait quelque chose comme ceci:
class A(object):
def __init__(self):
self.foo = 8
@apply
def foo():
"""A foobar"""
def fget(self):
return self._foo
def fset(self, val):
self._foo = val
return property(**locals())
class ATimesTwo(A):
@some_decorator
def foo():
def fset(self, val):
self._foo = val * 2
return something
Et puis la sortie ressemblerait à quelque chose comme:
>>> a = A()
>>> a.foo
8
>>> b = ATimesTwo()
>>> b.foo
16
Fondamentalement, ATimesTwo
hérite de la fonction getter de A
mais remplace la fonction setter. Quelqu'un connaît-il une façon de procéder (d'une manière qui ressemble à l'exemple ci-dessus)? À quoi ressemblerait la fonction some_decorator
Et à quoi la fonction foo
devrait-elle renvoyer?
Je suis sûr que vous avez déjà entendu cela, mais apply
est obsolète depuis huit ans , depuis Python 2.3. Ne l'utilisez pas. Votre utilisation de locals()
est également contraire au Zen de Python - explicite vaut mieux qu'implicite. Si vous avez vraiment comme l'indentation accrue, il n'est pas nécessaire de créer un objet jetable, faites simplement
if True:
@property
def foo(self):
return self._foo
@foo.setter
def foo(self, val):
self._foo = val
Ce qui n'abuse pas locals
, utilise apply
, nécessite la création d'un objet supplémentaire, ou a besoin ensuite d'une ligne avec foo = foo()
ce qui rend plus difficile de voir la fin du bloc . Cela fonctionne aussi bien pour votre ancienne façon d'utiliser property
- faites simplement foo = property(fget, fset)
comme d'habitude.
Si vous souhaitez remplacer une propriété dans une sous-classe arbitraire, vous pouvez utiliser un recette comme celle-ci .
Si la sous-classe sait où la propriété a été définie, faites simplement:
class ATimesTwo(A):
@A.foo.setter
def foo(self, val):
self._foo = val * 2
Le Python docs sur le décorateur property
suggère l'idiome suivant:
class C(object):
def __init__(self):
self._x = None
@property
def x(self):
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
Et puis les sous-classes peuvent remplacer un seul setter/getter comme ceci:
class C2(C):
@C.x.getter
def x(self):
return self._x * -1
C'est un peu verruqueux car remplacer plusieurs méthodes semble vous obliger à faire quelque chose comme:
class C3(C):
@C.x.getter
def x(self):
return self._x * -1
# C3 now has an x property with a modified getter
# so modify its setter rather than C.x's setter.
@x.setter
def x(self, value):
self._x = value * 2
Bien sûr, au moment où vous remplacez getter, setter et deleter, vous pouvez probablement simplement redéfinir la propriété pour C3.