Online Book Reader

Home Category

Learning Python - Mark Lutz [416]

By Root 1760 0
its full value display to fit on this page):

C:\misc> c:\python26\python testmixin.py

name _ListInherited__attrnames=>

name __doc__=<>

name __init__=<>

name __module__=<>

name __str__=<>

name data1=spam

name data2=eggs

name data3=42

name ham=>

name spam=>

>

In Python 3.0, more attributes are displayed because all classes are “new-style” and inherit names from the implied object superclass (more on this in Chapter 31). Because so many names are inherited from the default superclass, I’ve omitted many here; run this on your own for the full listing:

C:\misc> c:\python30\python testmixin.py

name _ListInherited__attrnames=>

name __class__=<>

name __delattr__=<>

name __dict__=<>

name __doc__=<>

name __eq__=<>

...more names omitted...

name __repr__=<>

name __setattr__=<>

name __sizeof__=<>

name __str__=<>

name __subclasshook__=<>

name __weakref__=<>

name data1=spam

name data2=eggs

name data3=42

name ham=>

name spam=>

>

One caution here—now that we’re displaying inherited methods too, we have to use __str__ instead of __repr__ to overload printing. With __repr__, this code will loop—displaying the value of a method triggers the __repr__ of the method’s class, in order to display the class. That is, if the lister’s __repr__ tries to display a method, displaying the method’s class will trigger the lister’s __repr__ again. Subtle, but true! Change __str__ to __repr__ here to see this for yourself. If you must use __repr__ in such a context, you can avoid the loops by using isinstance to compare the type of attribute values against types.MethodType in the standard library, to know which items to skip.

Listing attributes per object in class trees

Let’s code one last extension. As it is, our lister doesn’t tell us which class an inherited name comes from. As we saw in the classtree.py example near the end of Chapter 28, though, it’s straightforward to climb class inheritance trees in code. The following mix-in class makes use of this same technique to display attributes grouped by the classes they live in—it sketches the full class tree, displaying attributes attached to each object along the way. It does so by traversing the inheritance tree from an instance’s __class__ to its class, and then from the class’s __bases__ to all superclasses recursively, scanning object __dicts__s along the way:

# File lister.py, continued

class ListTree:

"""

Mix-in that returns an __str__ trace of the entire class

tree and all its objects' attrs at and above self;

run by print(), str() returns constructed string;

uses __X attr names to avoid impacting clients;

uses generator expr to recurse to superclasses;

uses str.format() to make substitutions clearer

"""

def __str__(self):

self.__visited = {}

return ''.format(

self.__class__.__name__,

id(self),

self.__attrnames(self, 0),

self.__listclass(self.__class__, 4))

def __listclass(self, aClass, indent):

dots = '.' * indent

if aClass in self.__visited:

return '\n{0}\n'.format(

dots,

aClass.__name__,

id(aClass))

else:

self.__visited[aClass] = True

genabove = (self.__listclass(c, indent+4) for c in aClass.__bases__)

return '\n{0}\n'.format(

dots,

aClass.__name__,

id(aClass),

self.__attrnames(aClass, indent),

''.join(genabove),

dots)

def __attrnames(self, obj, indent):

spaces = ' ' * (indent + 4)

result = ''

for attr in sorted(obj.__dict__):

if attr.startswith('__') and attr.endswith('__'):

result += spaces + '{0}=<>\n'.format(attr)

else:

result += spaces + '{0}={1}\n'.format(attr, getattr(obj, attr))

Return Main Page Previous Page Next Page

®Online Book Reader