2009-12-09 8 views
1

L'objectif principal du module suivant est de fournir une sorte de sémantique "constante" pour certains noms.L'accès par attribut surchargé ne fonctionne pas (comme prévu)

class ConstantError(Exception): 

    def __init__(self, msg): 
      self._msg = msg 


class Constant(object): 

    def __init__(self, name): 
      self._name = name 

    def __get__(self, instance, owner): 
      return instance._content[self._name] 

    def __set__(self, instance, value): 
      raise ConstantError, 'Illegal use of constant' 


class Constants(object): 

    def __init__(self, content): 
      self._content = content 
      for k in self._content: 
        setattr(self, k, Constant(k)) 

num_const = Constants({ 
    'one': 1, 
    'two': 2 
}) 

Quand il est utilisé:

>>> from const import * 
>>> dir(num_const) 
['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', '__weakref__', '_content', 'one', 'two'] 

Alors one et two sont là, mais l'accès d'attribut est diappointing:

>>> num_const.one 
<const.Constant object at 0x7faef4871710> 
>>> 

Là où je Wold attendre 1 dans ce cas. Où ai-je tort?

Répondre

3

Le protocole descripteur ne fonctionne que sur attributs de la classe, et non pas sur les attributs des instances d'une classe. Voir le How-To Guide for Descriptors

+0

Voilà donc le point. Pourriez-vous nous éclairer sur la raison d'être de ce comportement? Je veux dire, quoi d'autre pourrait mal tourner si le protocole des descripteurs fonctionnait également sur les instances de classe? –

+0

Je ne sais pas exactement pourquoi. Les problèmes de performance pour l'accès aux attributs? Ou qu'il serait difficile d'accéder à l'attribut lui-même (le descripteur) sans l'invoquer. – u0b34a0f6ae

0

Il vous manque un str() ou méthode unicode() Constantes.

Ajouter:

def __unicode__(self): 
    return self._name 
+0

Merci pour votre commentaire. Malheureusement, cela n'aide pas à atteindre le comportement attendu, c'est-à-dire que 'num_cons.one' doit rechercher' 'one'' dans 'num_const._content', et retourner sa valeur. –

0

Je pense que python empêche les classes d'accéder à la machinerie des descripteurs afin qu'ils puissent être manipulés. Sinon manipuler le descripteur pourrait devenir très compliqué sans une sorte de fonction "magique", et si vous avez remarqué que python essaie de garder beaucoup de machines de langage accessibles. Pour contourner cela, j'ai souvent généré la classe à la volée. Par exemple, vous classe Constantes pourrait être déclarée comme ceci:

class Constants(object): 
    def __new__(cls, content): 
     class _Constants(object): 
      pass 
     constants = _Constants 
     constants._content = content 
     for k in constants._content: 
      setattr(_Constants, k, Constant(k)) 
     return constants 

mais vraiment, pour vous fins que vous pourriez être mieux avec:

class Constants(object): 
    def __init__(self, content): 
     self._content = content 
    def __getattr__(self,key): 
     return self._content[key]