inheritance and __dict__

Showing 1-6 of 6 messages
inheritance and __dict__ Ka-Ping Yee 6/30/96 12:00 AM

I'm trying to understand what the convention for
maintaining __dict__ is.

I was getting a little confused because after
creating a derived class, it didn't look like
the methods from the base class were remembered:

    >>> class Base:
    ...     def a(self): return 4
    ...
    >>> class Derived(Base):
    ...     def b(self): return 5
    ...
    >>> Base.__dict__
    {'a': <function a at 8053660>, '__doc__': None}
    >>> Derived.__dict__
    {'b': <function b at 8053140>, '__doc__': None}

But i can still access the methods:

    >>> Derived.a
    <unbound method Base.a>
    >>> Derived.b
    <unbound method Derived.b>

I was even more surprised when i instantiated Derived:

    >>> thing = Derived()
    >>> thing.__dict__
    {}

So how can i see what methods are available?
I can execute them with thing.a() and thing.b(),
but what if i want to get a list and check it?

I tried thing.__class__.__dict__, but that only
gives me the attributes of Derived, not Base, and
i couldn't discover any mechanism for finding out
the base classes of a given class.

I must be totally missing something important here...

Thanks in advance for any help!


Ping

inheritance and __dict__ Daniel Larsson 6/30/96 12:00 AM

Ka-Ping Yee wrote:
>
> I'm trying to understand what the convention for
> maintaining __dict__ is.
>
> I was getting a little confused because after
> creating a derived class, it didn't look like
> the methods from the base class were remembered:
>
>     >>> class Base:
>     ...     def a(self): return 4
>     ...
>     >>> class Derived(Base):
>     ...     def b(self): return 5
>     ...
>     >>> Base.__dict__
>     {'a': <function a at 8053660>, '__doc__': None}
>     >>> Derived.__dict__
>     {'b': <function b at 8053140>, '__doc__': None}
>
> ... (elided)

>
> I must be totally missing something important here...
>
> Thanks in advance for any help!
>
> Ping

What you are missing is a class's __bases__ attribute, a tuple of
all it's base classes. You have to recursively traverse that structure
to figure out the complete interface.
--
Daniel Larsson, ABB Industrial Systems AB

inheritance and __dict__ Ka-Ping Yee 7/1/96 12:00 AM

Daniel Larsson wrote:
>
> What you are missing is a class's __bases__ attribute, a tuple of
> all it's base classes. You have to recursively traverse that structure
> to figure out the complete interface.

Thank you.  That helps.  -- So is there really no easier way
to see the available methods than traversing the whole class
ancestry myself?  All i want is a list of attribute names.

Perhaps this would be a commonly-needed-enough operation to add
a routine to generate the list to one of the standard modules?

Has anyone else ever wanted to do this?


Ping

inheritance and __dict__ Eric Daniel 7/1/96 12:00 AM

>>>>> "KY" == Ka-Ping Yee <s-p...@orange.cv.tottori-u.ac.jp> writes:

 KY> Thank you.  That helps.  -- So is there really no easier way to see the
 KY> available methods than traversing the whole class ancestry myself?  All
 KY> i want is a list of attribute names.

Unless I'm mistaken, newdir.dir() will do what you want.

>>> class C:
...   a=1
...
>>> class D(C):
...   b = 1
...
>>> d=D()
>>> import newdir
>>> newdir.dir(d)
['__doc__', 'a', 'b']


To have all class attributes, not only the methods, you need to apply the
following patch to newdir.py

*** Lib/newdir.py       Mon Aug  1 06:28:43 1994
--- /usr/local/lib/python/newdir.py     Mon Oct 23 18:38:08 1995
***************
*** 4,9 ****
--- 4,12 ----
  # This should be the new dir(), except that it should still list
  # the current local name space by default
 
+ # Updated Oct. 1995 by Eric Daniel.
+ # Now all the attributes of a class instance are listed, not only the methods.
+
  def listattrs(x):
        try:
                dictkeys = x.__dict__.keys()
***************
*** 33,45 ****
        total = dictkeys + methods + members
        if the_class:
                # It's a class instace; add the class's attributes
-               # that are functions (methods)...
                class_attrs = listattrs(the_class)
!               class_methods = []
!               for name in class_attrs:
!                       if is_function(getattr(the_class, name)):
!                               class_methods.append(name)
!               total = total + class_methods
        elif bases:
                # It's a derived class; add the base class attributes
                for base in bases:
--- 36,44 ----
        total = dictkeys + methods + members
        if the_class:
                # It's a class instace; add the class's attributes
                class_attrs = listattrs(the_class)
!               total = total + class_attrs
!
        elif bases:
                # It's a derived class; add the base class attributes
                for base in bases:
***************
*** 46,52 ****
                        base_attrs = listattrs(base)
                        total = total + base_attrs
        total.sort()
-       return total
        i = 0
        while i+1 < len(total):
                if total[i] == total[i+1]:
--- 45,50 ----
***************
*** 56,67 ****
        return total
 
 
- # Helper to recognize functions
-
- def is_function(x):
-       return type(x) == type(is_function)
-
-
  # Approximation of builtin dir(); but note that this lists the user's
  # variables by default, not the current local name space.
 
--- 54,59 ----


--
Eric Daniel

inheritance and __dict__ Ka-Ping Yee 7/1/96 12:00 AM

Ka-Ping Yee wrote:
>
> Thank you.  That helps.  -- So is there really no easier way
> to see the available methods than traversing the whole class
> ancestry myself?  All i want is a list of attribute names.

I'm sorry, i lied.  I just realized that what i really need is
the ability to call a method with a constructed name.

Without inheritance, this is not hard (but a little long-winded):

    methodname = a + b + c
    instance.__class__.__dict__[methodname](instance, arguments)

Is this impossible to accomplish with a derived class?

(That is, without initiating a complete search of the
class ancestry for each attempt at a method call?)


Ping

inheritance and __dict__ Daniel Larsson 7/1/96 12:00 AM

Well, why not let Python do the searching for you?

>>> method = getattr(instance, methodname)
>>> method(arguments)

--
Daniel Larsson, ABB Industrial Systems AB