Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find hidden attributes of Python objects? (attributes that don't appear in the dir(obj) list)

I'm using IPython.

I declared a simple class MyClass(object), and in the console, when using the name MyClass, after the dot operator, i hit Tab.

One of the first suggestions i got was mro, meaning MyClass.mro. I hit enter, and the output i get is:

> <function mro>

Now i didn't define this method, and of course it returns the method resolution order of my class.

This method doesn't appear in the list returned by dir(MyClass), and so here comes my question:

How would I find any other such hidden features of classes or other objects?

like image 639
vlad-ardelean Avatar asked Feb 10 '14 09:02

vlad-ardelean


1 Answers

The dir() does not try to provide a complete output, just a reasonable approximation that is useful in the interactive interpreter.

The reason for dir to not include __mro__ and mro in the output can be found in the source code, under Objects/object.c at line 1812:

/* Helper for PyObject_Dir of type objects: returns __dict__ and __bases__.
   We deliberately don't suck up its __class__, as methods belonging to the
   metaclass would probably be more confusing than helpful.
*/
static PyObject *
_specialized_dir_type(PyObject *obj)

And turns out that the mro method and the __mro__ attribute are actually attributes of the metaclass, i.e. of type:

>>> '__mro__' in object.__dict__
False
>>> '__mro__' in type.__dict__
True
>>> 'mro' in object.__dict__
False
>>> 'mro' in type.__dict__
True

Hence they are not shown in the output of dir. Whether this is sensible or not depends. I believe most of the time you really do not want to see what the metaclass defines, since they are internals of the metaclass.


As explained in the documentation for dir() you can customize its output defining a __dir__ method. However this applies to the instances of the class:

class A(object):
  def __dir__(self):
    return ['a', 'b', 'c']

print(dir(A()), dir(A))

Output:

(['a', 'b', 'c'], ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__'])

If you want to customize also the output of dir(A) you have to use a custom metaclass:

class MyMeta(type):
  def __dir__(self):
    return ['a', 'b', 'c']


class A(object, metaclass=MyMeta):
  # __metaclass__ = MyMeta   # in python 2

  def __dir__(self):
    return ['a', 'b', 'c', 'd']


print(dir(A()), dir(A))

Output:

(['a', 'b', 'c', 'd'], ['a', 'b', 'c'])
like image 159
Bakuriu Avatar answered Nov 02 '22 00:11

Bakuriu