2010-07-18 3 views
1

J'aimerais avoir des descripteurs de données dans le cadre d'une classe. Cela signifie que je voudrais que les attributs de classe soient réellement des propriétés, dont l'accès est géré par des méthodes de classe.Implémentation des descripteurs de classes en sous-classes de la classe `type`

Il semble que Python ne supporte pas directement cela, mais qu'il peut être implémenté en sous-classant la classe type. Par conséquent, l'ajout d'une propriété à une sous-classe de type entraînera la présence de descripteurs pour ses instances dans ses instances. Ses instances sont des classes. Ainsi, descripteurs de classe.

Est-ce conseillé? Y a-t-il des pièges que je devrais surveiller?

+1

Ce fil pourrait être utile: http://stackoverflow.com/questions/128573 – Philipp

+0

En effet, c'est presque un doublon, sauf que j'ai explicitement demandé à propos de la sous-classe 'type', alors que c'est juste suggéré dans l'une des réponses pour cette question. – intuited

Répondre

1

Il est conventionnel (habituellement), pour un descripteur, d'accéder à une classe pour renvoyer l'objet descripteur lui-même. C'est ce que fait property; Si vous accédez à un objet de propriété sur une classe, vous récupérez l'objet de propriété (parce que c'est ce que la méthode __get__ choisit de faire). Mais c'est une convention. vous n'avez pas à le faire de cette façon.

Donc, si vous avez seulement besoin d'avoir un descripteur getter votre classe, et ne vous dérange pas que tenter de définir écrasera le descripteur, vous pouvez faire quelque chose comme cela sans programmation métaclasse:

def classproperty_getter_only(f): 
    class NonDataDescriptor(object): 
     def __get__(self, instance, icls): 
      return f(icls) 
    return NonDataDescriptor() 

class Foo(object): 

    @classproperty_getter_only 
    def flup(cls): 
     return 'hello from', cls 

print Foo.flup 
print Foo().flup 

pour

('hello from', <class '__main__.Foo'>) 
('hello from', <class '__main__.Foo'>) 

Si vous voulez un descripteur de données à part entière, ou si vous voulez utiliser l'objet intégré de la propriété, alors vous avez raison, vous pouvez utiliser une méta-classe et le mettre là (la réalisation que cet attribut sera totalement invisible des instances de votre classe; les métaclasses ne sont pas examinées lors de la recherche d'attribut sur une instance d'une classe).

Est-il conseillé? Je ne pense pas. Je ne ferais pas ce que vous décrivez avec désinvolture dans le code de production; Je ne considérerais cela que si j'avais une raison très convaincante de le faire (et je ne peux pas penser à un tel scénario au sommet de ma tête). Les métaclasses sont très puissantes, mais elles ne sont pas bien comprises par tous les programmeurs et sont plus difficiles à raisonner, leur utilisation rend votre code plus difficile à maintenir. Je pense que ce genre de conception serait désapprouvé par la communauté python dans son ensemble.

+0

Bonne réponse, merci. Quand vous dites * métaclasse *, faites-vous référence à ce que je décrivais, c'est-à-dire au sous-type 'type'? Cette terminologie semble ambiguë, car elle est distincte de l'utilisation de l'attribut '__metaclass__', qui, si je comprends bien, ne gouverne que la classe * creation *. Y a-t-il un moyen de distinguer ces deux concepts? Ou est-ce que le «type» de sous-classe est si rarement fait qu'il y a peu de besoin? – intuited

+1

À ma connaissance, le sous-classement 'type' n'est vraiment utile que si vous l'utilisez comme un' __metaclass__'. La relation entre une classe et sa métaclasse est complètement analogue à la relation entre une instance d'objet et sa classe. La classe d'une classe. Quand vous faites 'print MyClass', ce qui donne un' str (MyClass) 'implicite (le texte que nous imprimons), la méthode qui est réellement appelée pour produire ce texte est' type .__ str__' (ou la méthode '__str__' sur votre métaclasse personnalisée). La personnalisation de métaclasse * typiquement * fait sa chose pendant la construction de classe, mais peut être customisée d'autres manières. –

+0

D'accord, je comprends maintenant. J'appelais réellement la métaclasse comme avec un appel de 3 arguments à 'type' pour créer la classe. Je n'ai juste pas compris ce que fait '__metaclass__'. Je suppose que j'étais confus par l'affirmation de la documentation que ses effets se produisent lors de la construction de la classe. Mais alors la même chose est vraie de la déclaration de classe elle-même :) Merci encore. – intuited

1

Est-ce ce que vous entendez par "attributs de classe pour être réellement des propriétés, dont l'accès est géré par des méthodes de classe"?

Vous pouvez utiliser un décorateur property pour faire apparaître un accesseur comme membre effectif. Ensuite, vous pouvez utiliser le décorateur x.setter pour créer un paramètre pour cet attribut.

Assurez-vous d'hériter de object, ou cela ne fonctionnera pas.

class Foo(object): 
    def __init__(self): 
      self._hiddenx = 3 
    @property 
    def x(self): 
      return self._hiddenx + 10 
    @x.setter 
    def x(self, value): 
      self._hiddenx = value 

p = Foo() 

p.x #13 

p.x = 4 
p.x #14 
+0

Non, je veux être capable de faire 'Foo.x' pour invoquer' x (cls) '. – intuited

Questions connexes