1

python version 3.5.2
I tried to get parent class from a child class:

class A:
    pass
class B(A):
    pass

after a little research, I got a solution from python doc: use __base__. (a special class attribute) But I couldn't find this "__base__" in B.__dict__ or dir(B), which are my normal ways of getting attributes.

This is definitely class related information, if it's not in B.__dict__ where is it? (although I realized that "__base__" is returned by type(B).__dict__)
And why isn't dir() returning it? based on this stackoverflow question I read, dir() has some logics behind and it is supposed to return "a complete picture of all available attributes."

I initally thought this is hiding on purpose...but you can still easily manipulate a child's parent:

class C:
    pass
B.__bases__ = (C,) # voila, B got a new Dad
Community
  • 1
  • 1
watashiSHUN
  • 9,684
  • 4
  • 36
  • 44

1 Answers1

1

See the note on dir() (emphasis mine):

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.

B is a class, its metaclass is type. So if you really want the full picture, you should also look as the metaclass’ dir():

>>> B.__class__ is type
True
>>> dir(type)
['__abstractmethods__', '__base__', '__bases__', '__basicsize__', '__call__', '__class__',
 '__delattr__', '__dict__', '__dictoffset__', '__dir__', '__doc__', '__eq__', '__flags__',
 '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
 '__init_subclass__', '__instancecheck__', '__itemsize__', '__le__', '__lt__',
 '__module__', '__mro__', '__name__', '__ne__', '__new__', '__prepare__', '__qualname__',
 '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
 '__subclasscheck__', '__subclasses__', '__subclasshook__', '__text_signature__',
 '__weakrefoffset__', 'mro']

And there you have __base__ and __bases__, and also those other things that appeared in the list you linked, like mro and __subclasses__.

poke
  • 369,085
  • 72
  • 557
  • 602
  • when I read that document, I thought `type(A).__dict__` to `A.__dict__` is like class attributes to instance attributes. so I said to myself, even though `type(A).__dict__` has `__bases__` does not mean `A.__dict__` has as well. You know, like **static** var vs **instance** var....now I realized that `type(type(A)) == type(A)` they are both classes, so `A.__dict__ >= type(A).__dict__`. but thanks for the answer – watashiSHUN Mar 31 '17 at 04:42