Odd behaviour of dir(object) with metaclasses.

Dirk Gerrits dirk at gerrits.homeip.net
Wed Apr 9 15:54:19 EDT 2003


Hi,

I am a bit puzzled by the behaviour of the dir builtin. I'll illustrate 
this with the following Python shell session:

 >>> class MetaBase(type):
	def mb(self):
		print self
 >>> class MetaDerived(MetaBase):
	def md(self):
		print self
 >>> class Base(object):
	__metaclass__ = MetaBase
	def b(self):
		print self
 >>> class Derived(Base):
	__metaclass__ = MetaDerived
	def d(self):
		print self
 >>> b = Base()
 >>> d = Derived()
 >>> def not_magic(str):
	return not (str.startswith("_") or str.endswith("_"))
 >>> filter(not_magic, dir(b))
['b']
 >>> filter(not_magic, dir(d))
['b', 'd']

Nothing out of the ordinary here, just as I would expect. But lets take 
a look at the classes now:

 >>> filter(not_magic, dir(Base))
['b']
 >>> filter(not_magic, dir(Derived))
['b', 'd']

Perhaps its just me, but I think this is really odd. The way I would 
expect it, dir should list the accessable attributes of the object. And 
that would mean:
(1) its own attributes
(2) its class's attributes and recursively of its class's bases
(3) (if it's a class object) recursively the attributes of its bases

For b and d, the dir listings are clearly correct. But Base's and 
Derived's the dir listings are incomplete, they don't seem to take (2) 
into account:

 >>> Base.mb() # No AttributeError
<class '__main__.Base'>
 >>> Derived.mb() # Idem
<class '__main__.Derived'>
 >>> Derived.md() # Dito
<class '__main__.Derived'>

Perhaps I just don't fully understand what dir does. The first bit in 
the docs says:

     Return an alphabetized list of names comprising (some of) the
     attributes of the given object, and of attributes reachable from it:

This would seem to correspond with my feeling of what its supposed to 
do, but doesn't. However, reading further, we see that the current 
behaviour is indeed as it is documented:

     No argument:  the names in the current scope.
     Module object:  the module attributes.
     Type or class object:  its attributes, and recursively the
         attributes of its bases.
     Otherwise:  its attributes, its class's attributes, and recursively
         the attributes of its class's base classes.

Why is there an unnatural (IMHO) distinction between type/class objects 
and other non-module objects? I assume that a class's class is not 
considered become dir comes from the pre-metaclass era? Shouldn't the 
docs really read

     Return an alphabetized list of names comprising (some of) the
     attributes of the given object, and of attributes reachable from it:

     No argument:  the names in the current scope.
     Module object:  the module attributes.
     Otherwise:  its attributes, its class's attributes, and recursively
         the attributes of its class's base classes. And if it's a class
         object, also the attributes of its own base classes recursively.

?
(Or something with the same meaning but in a less confusing wording. ;))

I hope you'll be able to clarify these things for me a bit.

Cheers,
Dirk Gerrits







More information about the Python-list mailing list