[réponse rédigée sur la base de python 3.4 ; la syntaxe des métaclasses diffère en 2 mais je pense que la technique fonctionnera toujours].
Vous pouvez le faire avec une métaclasse... en général. Celle de Dappawit fonctionne presque, mais je pense qu'elle a un défaut :
class MetaFoo(type):
@property
def thingy(cls):
return cls._thingy
class Foo(object, metaclass=MetaFoo):
_thingy = 23
Cela permet d'obtenir une classproperty sur Foo, mais il y a un problème...
print("Foo.thingy is {}".format(Foo.thingy))
# Foo.thingy is 23
# Yay, the classmethod-property is working as intended!
foo = Foo()
if hasattr(foo, "thingy"):
print("Foo().thingy is {}".format(foo.thingy))
else:
print("Foo instance has no attribute 'thingy'")
# Foo instance has no attribute 'thingy'
# Wha....?
Qu'est-ce qui se passe ici ? Pourquoi ne puis-je pas accéder à la propriété de la classe à partir d'une instance ?
Je me suis creusé la tête pendant un certain temps avant de trouver ce que je crois être la solution. Les @propriétés Python sont un sous-ensemble des descripteurs, et, d'après les documentation sur les descripteurs (souligné par moi) :
Le comportement par défaut pour l'accès aux attributs est t dans le dictionnaire d'un objet. Par exemple, a.x
h commençant par a.__dict__['x']
entonces type(a).__dict__['x']
et en continuant en passant par les classes de base de type(a)
excluant les métaclasses .
L'ordre de résolution des méthodes n'inclut donc pas les propriétés de notre classe (ni rien d'autre défini dans la métaclasse). Il n'y a pas d'ordre de résolution des méthodes. es Il est possible de créer une sous-classe du décorateur de propriété intégré qui se comporte différemment, mais (citation nécessaire) j'ai eu l'impression en googlant que les développeurs avaient une bonne raison (que je ne comprends pas) de le faire de cette façon.
Cela ne veut pas dire que nous n'avons pas de chance ; nous pouvons accéder aux propriétés de la classe elle-même sans problème... et nous pouvons obtenir la classe à partir de type(self)
dans l'instance, que nous pouvons utiliser pour créer des répartiteurs @property :
class Foo(object, metaclass=MetaFoo):
_thingy = 23
@property
def thingy(self):
return type(self).thingy
Maintenant Foo().thingy
fonctionne comme prévu pour la classe et les instances ! Il continuera également à faire ce qu'il faut si une classe dérivée remplace sa classe sous-jacente de _thingy
(ce qui est le cas d'utilisation qui m'a amené à cette chasse à l'origine).
Cela ne me satisfait pas à 100 % - le fait d'avoir à configurer à la fois la métaclasse et la classe d'objet semble violer le principe DRY. Mais ce dernier n'est qu'un dispatcher d'une ligne ; je suis plutôt d'accord avec son existence, et vous pourriez probablement le réduire à une lambda ou quelque chose comme ça si vous le vouliez vraiment.
2 votes
Je ne connais pas python... est-ce que c'est le genre de choses que vous recherchez ? python.org/download/releases/2.2/descrintro/#property
0 votes
Si je lis bien, on peut créer des méthodes pour agir comme setter et getter (comme dans d'autres langages) afin de charger paresseusement la valeur de la propriété lors du premier get... ce qui, je pense, est ce que vous vouliez ?
3 votes
@White Dragon. La fonctionnalité de propriété que vous recherchez ajoute des propriétés aux instances de classe, pas aux classes elles-mêmes. Ma question porte sur
Example.I
noe.i
.0 votes
Voici la solution pour créer une propriété de classe dans un autre sujet : stackoverflow.com/a/35640842/1113207
0 votes
Duplicata : Utilisation de property() sur les classmethods