2010-02-17 6 views
9

Python est livré avec la fonction pratique dir() qui répertorie le contenu d'une classe pour vous. Par exemple, pour cette classe:Comment parcourir sur les attributs d'une classe, dans l'ordre où ils ont été définis?

class C: 
    i = 1 
    a = 'b' 

dir(C) reviendriez

['__doc__', '__module__', 'a', 'i'] 

Cela tombe bien, mais remarquez comment l'ordre de 'a' et 'i' est maintenant différente, alors l'ordre dans lequel ils ont été définis dans

.

Comment est-ce que je peux itérer sur les attributs de C (en ignorant potentiellement les attributs de module doc & intégrés) dans l'ordre dans lequel ils ont été définis? Pour la classe C ci-dessus, le serait 'i' puis 'a'. - Je travaille sur un code de sérialisation/journalisation dans lequel je veux sérialiser les attributs dans l'ordre où ils ont été définis afin que la sortie soit similaire au code qui a créé la classe.

+0

Pourquoi l'ordre dans lequel ils sont définis est-il important? L'ordre n'est pas pertinent dans ce cas. Comment utiliseriez-vous cette information si vous pouviez l'obtenir? –

+0

Est-ce que vous sérialisez la classe ou les instances de la classe? Dans votre exemple, 'a' et' i' sont des attributs de classe. Si vous voulez dire que ce sont des attributs d'instance, vous devez les définir dans '__init__' en utilisant' self.a = 'b'' et 'self.i = 1'. – PaulMcG

+0

Ce sont des attributs de niveau classe, qui ne sont pas aussi utiles que les variables d'instance. Pourquoi essayez-vous de préserver l'ordre des attributs de classe? Ne vaudrait-il pas mieux préserver l'ordre des variables d'instance?Pourquoi essayez-vous de faire des trucs avec des variables de niveau classe? –

Répondre

7

Je ne pense pas que ce soit possible dans Python 2.x. Lorsque les membres de classe sont fournis à la méthode __new__, ils sont donnés en tant que dictionnaire, de sorte que l'ordre a déjà été perdu à ce stade. Par conséquent, même les métaclasses ne peuvent pas vous aider ici (à moins qu'il y ait des fonctionnalités supplémentaires que j'ai ratées).

En Python 3, vous pouvez utiliser la nouvelle méthode spéciale __prepare__ pour créer un dict ordonnée (ceci est même donné à titre d'exemple dans PEP 3115).

+0

Voici comment Django le fait (Python 2.x et plus): https://github.com/django/django/blob/stable/1.3.x/django/db/models/fields/__init__.py#L56 – tobych

+0

Je n'ai pas encore utilisé Django, mais je suppose que cela nécessite que dans chaque affectation, nous créons une nouvelle instance de 'Field'? Cela ressemble à une bonne solution. – nikow

+0

Oui, c'est ce que fait Django. – tobych

1

Cette information n'est pas accessible, car les attributs sont stockés dans un dict, qui est intrinsèquement non ordonné. Python ne stocke pas ces informations sur la commande n'importe où.

Si vous voulez que votre format de sérialisation pour stocker des choses dans un certain ordre vous préciser que commande explicitement. Vous n'utiliserez pas dir, qui contient des choses que vous ne connaissez pas ou qui ne vous intéressent pas, vous fournirez explicitement une liste (ou quoi que ce soit) décrivant quoi sérialiser.

2

Je suis nouveau en python, donc ma solution peut être pas efficace

class Q: 
def __init__(self): 
    self.a = 5 
    self.b = 10 

if __name__ == "__main__": 
    w = Q() 
    keys = w.__dict__.keys() 
    for k in keys: 
     print "Q.%s = %d"%(k,w.__dict__[k]) 

sortie est:

Q.a = 5 
Q.b = 10 
+0

Cela ne préserve pas la commande. –

2

mettre cette méthode dans votre classe

def __setattr__(self, attr, value): 
    if attr not in dir(self): 
     if attr == "__ordered_fields__": 
      super.__setattr__(self, attr, value) 
     else: 
      if not hasattr(self, "__ordered_fields__"): 
       setattr(self, "__ordered_fields__", []) 
      self.__ordered_fields__.append(attr) 
      super.__setattr__(self, attr, value) 

et obtenir les champs dans l'ordre, il suffit de faire quelque chose comme:

print(self.__ordered_fields__) 
Questions connexes