17

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?

William Pursell
  • 204,365
  • 48
  • 270
  • 300

3 Answers3

22

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.

srgerg
  • 18,719
  • 4
  • 57
  • 39
  • 2
    I get `TypeError: vars() argument must have __dict__ attribute` when trying this on some other objects – wim Jan 20 '12 at 01:13
  • 3
    Yes, the `vars()` function can only be used on objects that have a `__dict__`. So, for example, if `__slots__` is defined on your class then you won't be able to use the `vars()` function. – srgerg Jan 20 '12 at 01:17
  • 2
    Also note that this won't get anything that's a property, so it's not just things with `__slots__` that won't work. – Joe Kington Jan 20 '12 at 01:22
19

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.

Tadeck
  • 132,510
  • 28
  • 152
  • 198
2

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".

wim
  • 338,267
  • 99
  • 616
  • 750