2012-07-24 27 views
78

Tengo un objeto python con varios atributos y métodos. Quiero iterar sobre los atributos del objeto.Iterar sobre los atributos del objeto en python

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

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

Quiero generar un diccionario que contiene todos los objetos atributos y sus valores actuales, pero quiero hacerlo de una manera dinámica (por lo que si más adelante agrego otro atributo que no tengo que recordar actualizar mi función también).

En php las variables se pueden usar como claves, pero los objetos en python no se pueden usar y si uso la notación de puntos para esto se crea un nuevo atributo con el nombre de mi var, que no es mi intención.

para hacer las cosas más claras:

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 

Actualización: Con atributos me refiero únicamente las variables de este objeto, no los métodos.

+2

http://stackoverflow.com/questions/1251692/how- enumerar-un-objetos-propiedades-en-python Podría ser de alguna ayuda. – sean

+0

@sean En particular, http://stackoverflow.com/a/1251789/4203 es el camino a seguir; usarías el argumento opcional 'predicate' para pasar un invocable que filtraría (atada?) las funciones (que se deshace de los métodos). –

Respuesta

133

Asumiendo que tienen una clase como

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

llamando dir en el objeto que devuelve todos los atributos de ese objeto, incluyendo atributos especiales pitón. Aunque algunos atributos de objeto son invocables, como los métodos.

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

Siempre puede filtrar los métodos especiales mediante el uso de una lista de comprensión.

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

o si prefiere mapa/filtros.

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

Si desea filtrar los métodos, puede utilizar la orden interna callable como un cheque.

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

También puede inspeccionar la diferencia entre su clase y su principal.

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

Esta es una mala idea, ni siquiera lo sugeriría, pero si lo vas a hacer, al menos da la advertencia. – Julian

+1

@Julian Pensé que el código se explica por sí mismo. ¿Qué parte es vaga? Aunque, el objetivo de los lenguajes dinámicos es la capacidad de hacer esto, a pesar de que las personas de origen java creen que esto es un suicidio. – Meitham

+0

Esto parece sencillo. ¿Qué quieres decir con advertencia? ¿Qué puede salir mal? –

0

La respuesta correcta a esto es que no deberías. Si desea este tipo de cosas, simplemente use un dict o tendrá que agregar atributos explícitamente a algún contenedor. Puede automatizar eso aprendiendo sobre decoradores.

En particular, por cierto, el método 1 en su ejemplo es igual de bueno de un atributo.

+1

Sí, sé que no debería ... pero me ayuda a entender cómo funcionan las cosas. Vengo de un fondo php y solía hacer este tipo de cosas a diario –

+0

¡Suena como un buen momento para romper viejos hábitos :)! – Julian

+0

Me has convencido. Mantener el método to_dict() actualizado es mucho más sencillo que cualquier respuesta hasta el momento. –

2

Los objetos en python almacenan sus atributos (incluidas las funciones) en un dict llamado __dict__. Puede (pero generalmente no debería) usar esto para acceder a los atributos directamente. Si solo desea una lista, también puede llamar al dir(obj), que devuelve un iterable con todos los nombres de atributos, que luego puede pasar al getattr.

Sin embargo, la necesidad de hacer algo con los nombres de las variables suele ser un mal diseño. ¿Por qué no mantenerlos en una colección?

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

A continuación, puede iterar sobre las claves con for key in obj.special_values:

+0

¿Puede explicarme un poco más cómo usaría la colección para lograr lo que quiero? –

+1

No estoy agregando atributos al objeto dinámicamente. Las variables que tengo seguirán siendo las mismas durante mucho tiempo, sin embargo, creo que sería bueno poder hacer algo como lo que pretendo. –

1
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 

luego simplemente llamarlo como un iterable

s=someclass() 
for k,v in s: 
    print k,"=",v 
+0

Esto parece demasiado complicado. Si no tengo otra opción, preferiría quedarme con lo que estoy haciendo en este momento. –

31

en general poner un método __iter__ en su clase y iterate a través de los atributos del objeto o pon esta clase mixin en tu clase.

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

su clase:

>>> 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'} 
0

para Python 3,6

class SomeClass: 

    def attr_list1(self, should_print=False): 

     for k in self.__dict__.keys(): 
      v = self.__dict__.__getitem__(k) 
      if should_print: 
       print(f"attr: {k} value: {v}") 

    def attr_list(self, should_print=False): 

     b = [(k, v) for k, v in self.__dict__.items()] 
     if should_print: 
      [print(f"attr: {a[0]} value: {a[1]}") for a in b] 
     return b 
0

para Python 3,6

class SomeClass: 

    def attr_list(self, should_print=False): 

     items = self.__dict__.items() 
     if should_print: 
      [print(f"attribute: {k} value: {v}") for k, v in items] 

     return items