314 votes

À l’aide de property() sur classmethods

J’ai une classe avec deux méthodes de la classe (à l’aide de 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 il génère une erreur. J’ai été capable de reproduire l’erreur par ce qui suit dans l’interpréteur :

Est-il possible d’utiliser la fonction property() avec fonctions classmethod décoré ?

195voto

Coady Points 11374

Une propriété est créée sur une classe, mais affecte une instance. Donc si vous voulez une propriété classmethod, créez la propriété sur la métaclasse.

Mais étant donné que vous utilisez une métaclasse de toute façon, il va lire mieux si vous suffit de déplacer le classmethods là-dedans.

114voto

Denis Ryzhkov Points 331

J’espère que cet morts-simple lecture seule `` décorateur aiderait quelqu'un à la recherche de classproperties.

76voto

Jason R. Coombs Points 11130

La lecture de l' Python version 2.2 notes, je trouve le suivre.

La méthode get [de propriété] ne sera pas appelé quand la propriété est accessible en tant que classe attribut (C. x) au lieu d'une exemple d'attribut (C().x). Si vous souhaitez remplacer l' __get__ fonctionnement pour les propriétés lorsqu'il est utilisé comme une classe attribut, vous pouvez sous-classe de la propriété - il s'agit d'un nouveau type de style en lui-même à étendre son __get__ méthode, ou vous pouvez définir un type du descripteur à partir de zéro par la création d'un nouveau type de classe qui définit __get__, __set__ et __delete__ méthodes.

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é.

class ClassProperty(property):
    def __get__(self, cls, owner):
        return self.fget.__get__(None, owner)()

class foo(object):
    _var=5
    def getvar(cls):
        return cls._var
    getvar=classmethod(getvar)
    def setvar(cls,value):
        cls._var=value
    setvar=classmethod(setvar)
    var=ClassProperty(getvar,setvar)

assert foo.getvar() == 5
foo.setvar(4)
assert foo.getvar() == 4
assert foo.var == 4
foo.var = 3
assert foo.var == 3

Toutefois, les opérateurs n'ont pas réellement de travail:

foo.var = 4
assert foo.var == foo._var # raises AssertionError

foo._var est inchangé, vous avez tout simplement écrasé à la propriété avec une nouvelle valeur.

Vous pouvez également utiliser ClassProperty comme décorateur:

class Foo(object):
    _var = 5

    @ClassProperty
    @classmethod
    def var(cls):
        return cls._var

    @var.setter
    @classmethod
    def var(cls, value):
        cls._var = value

assert foo.var == 5

18voto

ddaa Points 19102

Il n'y a aucun moyen raisonnable de faire de cette "propriété de la classe" système de travail en Python.

Voici une façon déraisonnable pour le faire fonctionner. Vous pouvez certainement le rendre plus transparent avec des quantités croissantes de métaclasse de la magie.

class ClassProperty(object):
    def __init__(self, getter, setter):
        self.getter = getter
        self.setter = setter
    def __get__(self, cls, owner):
        return getattr(cls, self.getter)()
    def __set__(self, cls, value):
        getattr(cls, self.setter)(value)

class MetaFoo(type):
    var = ClassProperty('getvar', 'setvar')

class Foo(object):
    __metaclass__ = MetaFoo
    _var = 5
    @classmethod
    def getvar(cls):
        print "Getting var =", cls._var
        return cls._var
    @classmethod
    def setvar(cls, value):
        print "Setting var =", value
        cls._var = value

x = Foo.var
print "Foo.var = ", x
Foo.var = 42
x = Foo.var
print "Foo.var = ", x

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 œuvres, donc, je dois vous le descripteur de 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

besoin de modifier un attribut dans une façon qui est considérée par toutes les instances d'une classe, et dans le champ d'application de ces méthodes de la classe sont appelés n'ont pas de références à toutes les instances de la classe.

Il me semble, ce que vous voulez vraiment est un Observateur modèle de conception.

7voto

Nils Philippsen Points 51

Il mise uniquement sur la classe méta n’aide pas si vous souhaitez accéder à la propriété de la classe via un objet instancié, dans ce cas, vous devrez installer une propriété normale sur l’objet (qui distribue à la propriété de la classe). Je pense que ce qui suit est un peu plus clair :

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X