J'ai une classe avec deux méthodes de classe (en utilisant la fonction classmethod ()) pour obtenir et définir ce qui est essentiellement une variable statique. J'ai essayé d'utiliser la fonction property () avec ceux-ci, mais cela entraîne une erreur. J'ai pu reproduire l'erreur avec ce qui suit dans l'interpréteur:
class Foo(object):
_var = 5
@classmethod
def getvar(cls):
return cls._var
@classmethod
def setvar(cls, value):
cls._var = value
var = property(getvar, setvar)
Je peux démontrer les méthodes de classe, mais elles ne fonctionnent pas comme des propriétés:
>>> f = Foo()
>>> f.getvar()
5
>>> f.setvar(4)
>>> f.getvar()
4
>>> f.var
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable
>>> f.var=5
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable
Est-il possible d'utiliser la fonction property () avec des fonctions décorées par classmethod?
class Foo(metaclass=...)
syntaxe.En lisant les notes de publication de Python 2.2 , je trouve ce qui suit.
REMARQUE: la méthode ci-dessous ne fonctionne pas réellement pour les setters, uniquement les getters.
Par conséquent, je crois que la solution prescrite est de créer un ClassProperty en tant que sous-classe de propriété.
Cependant, les setters ne fonctionnent pas réellement:
foo._var
est inchangé, vous avez simplement remplacé la propriété par une nouvelle valeur.Vous pouvez également utiliser
ClassProperty
comme décorateur:la source
self.fget(owner)
et de supprimer le besoin d'utiliser un@classmethod
du tout ici? (c'est ceclassmethod
qui se traduit.__get__(instance, owner)(*args, **kwargs)
par desfunction(owner, *args, **kwargs)
appels, via un intermédiaire; les propriétés n'ont pas besoin de l'intermédiaire).foo.var = 3
affectation ne passe pas réellement par la propriété , et a simplement remplacé l'objet de propriétéfoo
par un entier. Si vous avez ajouté desassert isinstance(foo.__dict__['var'], ClassProperty)
appels entre vos assertions, vous verrez que l'échec après l'foo.var = 3
exécution.instance.attr
,instance.attr = value
etdel instance.attr
se lient tous le descripteur trouvé surtype(instance)
, mais alors queclassobj.attr
se fixe,classobj.attr = value
etdel classobj.attr
ne pas et au lieu ou supprimer l'objet descripteur lui - même). Vous avez besoin d'une métaclasse pour prendre en charge la définition et la suppression (faisant de l'objet de classe l'instance et de la métaclasse le type).J'espère que ce
@classproperty
décorateur en lecture seule extrêmement simple aiderait quelqu'un à rechercher des propriétés de classe.la source
class D(C): x = 2; assert D.x == 2
.format
comme"{x}".format(**dict(self.__class__.__dict__, **self.__dict__))
:(x
accès par10
. J'aime cette approche parce qu'elle est nette et simple mais sonne comme un antipatron__set__
qui lève unValueError
pour éviter le remplacement.Non.
Cependant, une méthode de classe est simplement une méthode liée (une fonction partielle) sur une classe accessible à partir des instances de cette classe.
Puisque l'instance est une fonction de la classe et que vous pouvez dériver la classe de l'instance, vous pouvez obtenir le comportement souhaité d'une propriété de classe avec
property
:Ce code peut être utilisé pour tester - il devrait réussir sans générer d'erreurs:
Et notez que nous n'avons pas du tout besoin de métaclasses - et que vous n'accédez pas directement à une métaclasse via les instances de ses classes de toute façon.
écrire un
@classproperty
décorateurVous pouvez en fait créer un
classproperty
décorateur en seulement quelques lignes de code en sous-classantproperty
(il est implémenté en C, mais vous pouvez voir l'équivalent Python ici ):Traitez ensuite le décorateur comme s'il s'agissait d'une méthode de classe combinée à une propriété:
Et ce code devrait fonctionner sans erreur:
Mais je ne sais pas à quel point cela serait bien avisé. Un ancien article de liste de diffusion suggère que cela ne devrait pas fonctionner.
Faire fonctionner la propriété sur la classe:
L'inconvénient de ce qui précède est que la "propriété de classe" n'est pas accessible depuis la classe, car elle écraserait simplement le descripteur de données de la classe
__dict__
.Cependant, nous pouvons remplacer cela avec une propriété définie dans la métaclasse
__dict__
. Par exemple:Et puis une instance de classe de la métaclasse pourrait avoir une propriété qui accède à la propriété de la classe en utilisant le principe déjà démontré dans les sections précédentes:
Et maintenant nous voyons à la fois l'instance
et la classe
avoir accès à la propriété de classe.
la source
Python 3!
Ancienne question, beaucoup de points de vue, qui ont cruellement besoin d'une seule vraie méthode Python 3.
Heureusement, c'est facile avec le
metaclass
kwarg:Ensuite,
>>> Foo.var
la source
Foo
est une instance de sa métaclasse, et@property
peut être utilisée pour ses méthodes tout comme elle le peut pour celles des instances deFoo
.Foo.__new__
. Bien qu'à ce stade, cela puisse valoir la peine d'utiliser getattribute à la place, ou de se demander si prétendre qu'une fonctionnalité de langage existe est vraiment l'approche que vous voulez adopter.Il n'y a aucun moyen raisonnable de faire fonctionner ce système de «propriété de classe» en Python.
Voici une façon déraisonnable de le faire fonctionner. Vous pouvez certainement le rendre plus transparent avec des quantités croissantes de magie de métaclasse.
Le nœud du problème est que les propriétés sont ce que Python appelle des «descripteurs». Il n'y a pas de moyen court et facile d'expliquer comment ce type de métaprogrammation fonctionne, je dois donc vous indiquer le descripteur howto .
Vous n'avez besoin de comprendre ce genre de choses que si vous implémentez un cadre assez avancé. Comme une persistance d'objet transparente ou un système RPC, ou une sorte de langage spécifique à un domaine.
Cependant, dans un commentaire à une réponse précédente, vous dites que vous
Il me semble que vous voulez vraiment un modèle de conception Observer .
la source
Le définir uniquement sur la méta-classe n'aide pas si vous souhaitez accéder à la propriété de classe via un objet instancié, dans ce cas, vous devez également installer une propriété normale sur l'objet (qui se distribue à la propriété de classe). Je pense que ce qui suit est un peu plus clair:
la source
Une demi-solution, __set__ sur la classe ne fonctionne toujours pas. La solution est une classe de propriété personnalisée implémentant à la fois une propriété et une méthode statique
la source
Avez-vous accès à au moins une instance de la classe? Je peux penser à un moyen de le faire alors:
la source
Essayez ceci, cela fait le travail sans avoir à changer / ajouter beaucoup de code existant.
La
property
fonction a besoin de deuxcallable
arguments. donnez-leur des wrappers lambda (dont il passe l'instance comme premier argument) et tout va bien.la source
Voici une solution qui devrait fonctionner à la fois pour l'accès via la classe et l'accès via une instance qui utilise une métaclasse.
Cela fonctionne également avec un setter défini dans la métaclasse.
la source
Après avoir recherché différents endroits, j'ai trouvé une méthode pour définir une propriété de classe valide avec Python 2 et 3.
J'espère que cela peut aider quelqu'un :)
la source
Voici ma suggestion. N'utilisez pas de méthodes de classe.
Sérieusement.
Quelle est la raison d'utiliser des méthodes de classe dans ce cas? Pourquoi ne pas avoir un objet ordinaire d'une classe ordinaire?
Si vous souhaitez simplement modifier la valeur, une propriété n'est pas vraiment très utile, n'est-ce pas? Définissez simplement la valeur de l'attribut et en avez terminé.
Une propriété ne doit être utilisée que s'il y a quelque chose à cacher - quelque chose qui pourrait changer dans une implémentation future.
Peut-être que votre exemple est bien dépouillé et qu'il y a un calcul infernal que vous avez laissé de côté. Mais il ne semble pas que la propriété ajoute une valeur significative.
Les techniques de "confidentialité" influencées par Java (en Python, les noms d'attributs commençant par _) ne sont pas vraiment très utiles. Privé de qui? Le point de privé est un peu nébuleux lorsque vous avez la source (comme vous le faites en Python.)
Les getters et setters de style EJB influencés par Java (souvent réalisés en tant que propriétés en Python) sont là pour faciliter l'introspection primitive de Java ainsi que pour passer le rassemblement avec le compilateur de langage statique. Tous ces getters et setters ne sont pas aussi utiles en Python.
la source