245 votes

Itération sur les attributs des objets en python

J'ai un objet python avec plusieurs attributs et méthodes. Je veux itérer sur les attributs de l'objet.

class my_python_obj(object):
    attr1='a'
    attr2='b'
    attr3='c'

    def method1(self, etc, etc):
        #Statements

Je veux générer un dictionnaire contenant tous les attributs des objets et leurs valeurs actuelles, mais je veux le faire de manière dynamique (ainsi, si plus tard j'ajoute un autre attribut, je ne dois pas me souvenir de mettre à jour ma fonction également).

En php, les variables peuvent être utilisées comme clés, mais les objets en python sont insuscriptibles et si j'utilise la notation par points pour cela, cela crée un nouvel attribut avec le nom de ma var, ce qui n'est pas mon intention.

Pour que les choses soient plus claires :

def to_dict(self):
    '''this is what I already have'''
    d={}
    d["attr1"]= self.attr1
    d["attr2"]= self.attr2
    d["attr3"]= self.attr3
    return d

-

def to_dict(self):
    '''this is what I want to do'''
    d={}
    for v in my_python_obj.attributes:
        d[v] = self.v
    return d

Mise à jour : Avec les attributs, je veux dire seulement les variables de cet objet, pas les méthodes.

338voto

Meitham Points 1872

En supposant que vous ayez une classe telle que

>>> class Cls(object):
...     foo = 1
...     bar = 'hello'
...     def func(self):
...         return 'call me'
...
>>> obj = Cls()

en appelant dir sur l'objet vous rend tous les attributs de cet objet, y compris les attributs spéciaux de python. Bien que certains attributs d'objets soient appelables, comme les méthodes.

>>> dir(obj)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'bar', 'foo', 'func']

Vous pouvez toujours filtrer les méthodes spéciales en utilisant une liste de compréhension.

>>> [a for a in dir(obj) if not a.startswith('__')]
['bar', 'foo', 'func']

ou si vous préférez carte/filtres.

>>> filter(lambda a: not a.startswith('__'), dir(obj))
['bar', 'foo', 'func']

Si vous voulez filtrer les méthodes, vous pouvez utiliser la fonction intégrée callable comme un chèque.

>>> [a for a in dir(obj) if not a.startswith('__') and not callable(getattr(obj, a))]
['bar', 'foo']

Vous pouvez également inspecter la différence entre votre classe et son objet d'instance en utilisant.

>>> set(dir(Cls)) - set(dir(object))
set(['__module__', 'bar', 'func', '__dict__', 'foo', '__weakref__'])

79voto

SmartElectron Points 111

En général mettre un __iter__ dans votre classe et itérer à travers les attributs de l'objet ou mettre cette classe mixin dans votre classe.

class IterMixin(object):
    def __iter__(self):
        for attr, value in self.__dict__.iteritems():
            yield attr, value

Votre classe :

>>> class YourClass(IterMixin): pass
...
>>> yc = YourClass()
>>> yc.one = range(15)
>>> yc.two = 'test'
>>> dict(yc)
{'one': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], 'two': 'test'}

71voto

Nathan Points 1050

Comme mentionné dans certaines réponses/commentaires déjà, les objets Python stockent déjà un dictionnaire de leurs attributs (les méthodes ne sont pas incluses). On peut y accéder par __dict__ mais la meilleure solution est d'utiliser vars (le résultat est le même, cependant). Notez que la modification de ce dictionnaire modifiera les attributs de l'instance ! Cela peut être utile, mais cela signifie également que vous devez faire attention à la façon dont vous utilisez ce dictionnaire. Voici un exemple rapide :

class A():
    def __init__(self, x=3, y=2, z=5):
        self.x = x
        self._y = y
        self.__z__ = z

    def f(self):
        pass

a = A()
print(vars(a))
# {'x': 3, '_y': 2, '__z__': 5}
# all of the attributes of `a` but no methods!

# note how the dictionary is always up-to-date
a.x = 10
print(vars(a))
# {'x': 10, '_y': 2, '__z__': 5}

# modifying the dictionary modifies the instance attribute
vars(a)["_y"] = 20
print(vars(a))
# {'x': 10, '_y': 20, '__z__': 5}

Utilisation de dir(a) est une approche étrange, voire carrément mauvaise, de ce problème. C'est une bonne chose si vous avez vraiment besoin d'itérer sur tous les attributs. et méthodes de la classe (y compris les méthodes spéciales comme __init__ ). Cependant, cela ne semble pas être ce que vous voulez, et même la fonction réponse acceptée s'y prend mal en appliquant un filtrage fragile pour essayer de supprimer les méthodes et ne laisser que les attributs ; vous pouvez voir comment cela échouerait pour la classe A définis ci-dessus.

(en utilisant __dict__ a été fait dans quelques réponses, mais elles définissent toutes des méthodes inutiles au lieu de l'utiliser directement. Seul un commentaire) suggère d'utiliser vars ).

4voto

Daenyth Points 11297

Les objets en python stockent leurs attributs (y compris les fonctions) dans un dict appelé __dict__ . Vous pouvez (mais ne devriez généralement pas) l'utiliser pour accéder directement aux attributs. Si vous voulez juste une liste, vous pouvez aussi appeler dir(obj) qui renvoie un itérable contenant tous les noms d'attributs, que vous pouvez ensuite passer à la fonction getattr .

Cependant, le fait de devoir faire quoi que ce soit avec les noms des variables est généralement mal conçu. Pourquoi ne pas les conserver dans une collection ?

class Foo(object):
    def __init__(self, **values):
        self.special_values = values

Vous pouvez ensuite itérer sur les clés avec for key in obj.special_values:

2voto

Joran Beasley Points 28451
class SomeClass:
    x = 1
    y = 2
    z = 3

    def __init__(self):
        self.current_idx = 0
        self.items = ["x", "y", "z"]

    def next(self):
        if self.current_idx < len(self.items):
            self.current_idx += 1
            k = self.items[self.current_idx-1]
            return (k, getattr(self, k))
        else:
            raise StopIteration

    def __iter__(self):
        return self

alors il suffit de l'appeler comme un itérable

s = SomeClass()
for k, v in s:
    print k, "=", v

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