2012-01-20 12 views
11

Recientemente, me encuentro escribiendo de un objeto como éste:Iterar sobre el código "público" atributos

 
for name in dir(object): 
    if name.startswith('__') : continue 
    ... 

¿Hay una manera más Pythonic acceder a espacio de nombres "público" del objeto?

+2

¿Qué problema está resolviendo en primer lugar que este constructo es útil? – SingleNegationElimination

+0

¿Qué pasa con 'for name in filter (lambda x: not x.startswith ('_'), dir (obj)):'? Tenga en cuenta que en Python, incluso un solo guión bajo ('_') está destinado a indicar un atributo *" privado "*. –

+2

@NiklasR 'para el nombre en (x para x en dir (obj) si no x.startswith ('_')):' no necesita filtro –

Respuesta

15

lista de "público" Usted puede preparar atributos (como lista o como generador) antes:

>>> public_props = (name for name in dir(object) if not name.startswith('_')) 
>>> for name in public_props: 
    print name 

Pero, por favor leer una nota sobre dir() función en la documentación:

Note Because dir() is supplied primarily as a convenience for use at an interactive prompt, it tries to supply an interesting set of names more than it tries to supply a rigorously or consistently defined set of names, and its detailed behavior may change across releases. For example, metaclass attributes are not in the result list when the argument is a class.

Debe También tenga en cuenta que cualquier clase puede implementar el método __dir__() que puede devolver una lista de nombres que no corresponden necesariamente con los nombres de los atributos. En otras palabras, dir(something) no garantiza que el resultado arrojará atributos de something.

+1

¿Hay alguna razón para preferir 'dir (objeto)' a 'objeto .__ dict__'? – Dave

+1

objeto .__ dict__ no devuelve necesariamente los atributos que desea, al menos según los resultados de mi prueba. –

15

En su lugar, puede usar el vars function.

Por ejemplo:

>>> class C(object): 
... def __init__(self): 
...  self.__foo = 'foo' 
... 
>>> c = C() 
>>> dir(c) 
['_C__foo', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', 
'__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__',  
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__',  
'__weakref__'] 
>>> vars(c) 
{'_C__foo': 'foo'} 

Tenga en cuenta que, cuando Niklas R ha señalado, las variables con un solo subrayado también se consideran privados. Sin embargo, la función vars() tiene la ventaja de eliminar todas las variables de instancia excepto las variables de instancia.

+2

Obtengo 'TypeError: el argumento vars() debe tener el atributo __dict__' cuando se intenta esto en otros objetos – wim

+2

Sí, la función' vars() 'solo se puede usar en objetos que tienen un' __dict__'. Entonces, por ejemplo, si '__slots__' está definido en su clase, entonces no podrá usar la función' vars() '. – srgerg

+1

También tenga en cuenta que esto no obtendrá nada que sea una propiedad, por lo que no son solo las cosas con '__slots__' que no funcionarán. –

1

Creo que repetir la lista es un poco más pitónico que usar la palabra clave continue, pero podría ser solo cuestión de gustos. Es cierto que no es mucho más elegante que lo que ya tienes.

for attr in (a for a in dir(object) if not a.startswith('_')): 
    pass 

Nota: de subrayado también atributos no son "públicos".