Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterate over an object's "public" attributes [duplicate]

Tags:

python

Recently, I find myself writing code like this:

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

Is there a more pythonic way to access the object's "public" namespace?

like image 215
William Pursell Avatar asked Jan 20 '12 00:01

William Pursell


3 Answers

You could use the vars function instead.

For example:

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

Note that, as Niklas R has pointed out, variables with a single underscore are also considered private. However the vars() function has the advantage of eliminating all but the instance variables.

like image 152
srgerg Avatar answered Oct 13 '22 23:10

srgerg


You can prepare list of "public" attributes (as list or as generator) before:

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

But please read a note about dir() function in the documentation:

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.

You should also be aware, that any class can implement __dir__() method that may return a list of names that do not necessarily correspond to the names of the attributes. In other words, dir(something) does not guarantee that the result will return attributes of something.

like image 30
Tadeck Avatar answered Oct 13 '22 22:10

Tadeck


Rather than an exclusion branch using the continue keyword, iterating over a comprehension of public names directly seems more Pythonic. But it could just be a matter of taste, it's admittedly not much better than what you already have.

public_names = (n for n in dir(object) if not n.startswith('_'))
for attr in public_names:
    ...

Note: Single underscore attributes are also not "public".

like image 45
wim Avatar answered Oct 13 '22 23:10

wim