En utilisant la propriété() sur classmethods
J'ai une classe avec deux méthodes de la classe (à l'aide de la classmethod fonction ()) pour l'obtention et la configuration de ce qui est essentiellement une variable statique. J'ai essayé d'utiliser la propriété() fonction avec ceux-ci, mais il en résulte une erreur. J'ai été en mesure de reproduire l'erreur avec les éléments suivants 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 la classe, mais ils 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 propriété() fonction avec classmethod décorées fonctions?
Vous devez vous connecter pour publier un commentaire.
Une propriété est créée sur une classe, mais affecte une instance. Donc, si vous voulez un classmethod de la propriété, de créer de la propriété de la métaclasse.
Mais puisque vous êtes à l'aide d'une métaclasse de toute façon, il va lire mieux si vous venez de passer le classmethods là.
ou, à l'aide de Python 3
metaclass=...
de syntaxe et de la métaclasse définis en dehors de lafoo
corps de classe, et la métaclasse responsable pour le réglage de la valeur initiale de_var
:class Foo(metaclass=...)
de la syntaxe.La lecture de la Python version 2.2 notes, je trouve le suivre.
REMARQUE: La méthode ci-dessous ne fait pas travailler pour les setters, seulement des getters.
Par conséquent, je crois que le prescrit la solution est de créer un ClassProperty comme une sous-classe de la propriété.
Toutefois, les opérateurs n'ont pas réellement de travail:
foo._var
est inchangé, vous avez tout simplement écrasé à la propriété avec une nouvelle valeur.Vous pouvez également utiliser
ClassProperty
un décorateur:self.fget(owner)
et de supprimer la nécessité d'avoir à utiliser un@classmethod
à tous ici? (c'est ce queclassmethod
t, traduire.__get__(instance, owner)(*args, **kwargs)
àfunction(owner, *args, **kwargs)
appels, via un intermédiaire; les propriétés n'ont pas besoin de l'intermédiaire).foo.var = 3
attribution de ne fait pas passer par la propriété, et, au contraire, a tout simplement remplacé la propriété de l'objet surfoo
avec un entier. Si vous avez ajoutéassert isinstance(foo.__dict__['var'], ClassProperty)
des appels entre vos affirmations, vous verriez que l'échec aprèsfoo.var = 3
est exécutée.instance.attr
,instance.attr = value
etdel instance.attr
seront tous lier le descripteur trouvé surtype(instance)
, mais toutclassobj.attr
lie,classobj.attr = value
etdel classobj.attr
ne pas et au lieu de remplacer ou de supprimer le descripteur de l'objet lui-même). Vous avez besoin d'une métaclasse pour appuyer l'établissement et la suppression (ce qui rend la classe de l'objet de l'instance, et la métaclasse le type).J'espère que cette mort-simple en lecture seule
@classproperty
décorateur permettrait d'aider quelqu'un à la recherche pour classproperties.class D(C): x = 2; assert D.x == 2
.format
comme"{x}".format(**dict(self.__class__.__dict__, **self.__dict__))
🙁C.x = 10; assert C.x == 10
x
accès par10
. J'aime cette approche, car il est pur et simple, mais sonne comme un antipattern__set__
que soulève uneValueError
pour prévenir les remplacer.AttributeError
, et qui ne fonctionne que pour bloquerC().x = val
, pasC.x = val
Pas.
Cependant, un classmethod est tout simplement une méthode liée (une fonction partielle) sur une classe accessible à partir d'instances de cette classe.
Depuis l'instance est une fonction de la classe et vous pouvez dériver de la classe de l'instance, vous pouvez obtenir ce comportement souhaité que vous pourriez voulez à partir d'une classe-propriété avec
property
:Ce code peut être utilisé à des fins de test, il devrait passer sans déclencher d'erreur:
Et notez que nous n'avons pas besoin de metaclasses à tous - et vous n'avez pas directement accès à une métaclasse par le biais de ses classes, instances, de toute façon.
l'écriture d'un
@classproperty
décorateurVous pouvez en fait créer un
classproperty
décorateur en seulement quelques lignes de code par sous-classementproperty
(il est implémenté en C, mais vous pouvez voir l'équivalent Python ici):Ensuite traiter le décorateur comme si c'était un classmethod combiné avec la propriété:
Et ce code devrait fonctionner sans erreurs:
Mais je ne suis pas sûr de savoir comment bien informé de ce serait. Une vieille liste de diffusion l'article suggère qu'il ne devrait pas fonctionner.
Obtenir la propriété de travailler sur la classe:
L'inconvénient est que la "propriété de classe" n'est pas accessible à partir de la classe, car il serait tout simplement de remplacer le descripteur de données à partir de la classe
__dict__
.Cependant, on peut la surcharger avec une propriété définie dans la métaclasse
__dict__
. Par exemple:Puis à une classe de l'instance de la métaclasse pourrait avoir une propriété qui accède à la classe de la propriété en utilisant le principe déjà démontré dans les sections avant:
Et maintenant nous voir à la fois l'instance
et la classe
avoir accès à la propriété de classe.
Python 3!
Vieille question, beaucoup de points de vue, réellement besoin d'un vrai Python 3 voies.
Heureusement, c'est facile avec le
metaclass
kwarg:Puis,
>>> Foo.var
Foo
est une instance de sa métaclasse, et@property
peut être utilisé pour ses méthodes tout comme pour celles d'instances deFoo
.Il n'y a aucun moyen raisonnable de faire de cette "propriété de la classe" système de travail en Python.
Ici est une façon déraisonnable pour le faire fonctionner. Vous pouvez certainement le rendre plus transparent avec des quantités croissantes de métaclasse magie.
Le nœud de la question est que les propriétés sont ce que Python appelle "descripteurs". Il n'y a aucun moyen court et facile à expliquer comment ce genre de métaprogrammation, je doit point vous à la descripteur howto.
Vous n'avez besoin de comprendre ce genre de choses, si vous êtes à la mise en œuvre d'une assez avancé cadre. Comme un objet transparent persistance ou de la RPC système, ou une sorte de langue propres au domaine.
Cependant, dans un commentaire à une précédente réponse, vous dites que vous
Il me semble, ce que vous voulez vraiment est un Observateur motif de conception.
Paramètre uniquement sur la méta-classe n'est pas vous aider si vous souhaitez accéder à la propriété de classe par l'intermédiaire d'un objet instancié, dans ce cas, vous devez installer une normale de propriété sur l'objet (qui distribue à la propriété de classe). Je pense que la suite est un peu plus clair:
Une demi-solution, __set__ de la classe ne fonctionne pas, encore. La solution est une propriété personnalisée de la classe de mise en œuvre à la fois un bien et un staticmethod
Vous avez accès à au moins une instance de la classe? Je pense à une façon de le faire alors:
Donner à ceci un essai, il fait le travail, sans avoir à modifier/ajouter beaucoup de code existant.
La
property
fonction des besoins de deuxcallable
arguments. leur donner lambda wrappers (qui passe de l'instance en tant que premier argument) et tout est bien.Voici une solution qui devrait fonctionner pour les deux accès via la classe et l'accès via une instance qui utilise une métaclasse.
Cela fonctionne aussi avec un setter défini dans la métaclasse.
Après la recherche d'endroits différents, j'ai trouvé une méthode pour définir un classproperty
valide avec Python 2 et 3.
J'espère que cela peut aider quelqu'un 🙂
Voici ma suggestion. Ne pas utiliser les méthodes de la classe.
Au sérieux.
Quelle est la raison de l'utilisation des méthodes de la classe dans ce cas? Pourquoi ne pas avoir un objet ordinaire d'une classe ordinaire?
Si vous souhaitez tout simplement changer la valeur d'une propriété n'est pas vraiment très utile est-il? Il suffit de régler la valeur de l'attribut et être fait avec elle.
Une propriété doit être utilisée uniquement si il y a quelque chose à cacher, quelque chose qui pourrait changer à l'avenir la mise en œuvre.
Peut-être que votre exemple est dépouillé, et il y a quelques infernale de calcul que vous avez laissé. Mais il ne ressemble pas à la propriété ajoute une valeur significative.
La Java d'influence "vie privée" des techniques (en Python, d'attribuer les noms qui commencent par _) ne sont pas vraiment très utile. Privé de qui? Le point de private est un peu nébuleux quand vous avez la source (comme vous le faites en Python.)
La Java influencé EJB-style getters et les setters (souvent du fait que les propriétés en Python) sont là pour faciliter Java primitive de l'introspection ainsi que pour passer de rassemblement avec la statique compilateur de langage. Tous ces accesseurs et mutateurs ne sont pas aussi utiles en Python.