Online Book Reader

Home Category

Learning Python - Mark Lutz [414]

By Root 1672 0
following class, coded in the file lister.py, defines a mix-in called ListInstance that overloads the __str__ method for all classes that include it in their header lines. Because this is coded as a class, ListInstance is a generic tool whose formatting logic can be used for instances of any subclass:

# File lister.py

class ListInstance:

"""

Mix-in class that provides a formatted print() or str() of

instances via inheritance of __str__, coded here; displays

instance attrs only; self is the instance of lowest class;

uses __X names to avoid clashing with client's attrs

"""

def __str__(self):

return '' % (

self.__class__.__name__, # My class's name

id(self), # My address

self.__attrnames()) # name=value list

def __attrnames(self):

result = ''

for attr in sorted(self.__dict__): # Instance attr dict

result += '\tname %s=%s\n' % (attr, self.__dict__ [attr])

return result

ListInstance uses some previously explored tricks to extract the instance’s class name and attributes:

Each instance has a built-in __class__ attribute that references the class from which it was created, and each class has a __name__ attribute that references the name in the header, so the expression self.__class__.__name__ fetches the name of an instance’s class.

This class does most of its work by simply scanning the instance’s attribute dictionary (remember, it’s exported in __dict__) to build up a string showing the names and values of all instance attributes. The dictionary’s keys are sorted to finesse any ordering differences across Python releases.

In these respects, ListInstance is similar to Chapter 27’s attribute display; in fact, it’s largely just a variation on a theme. Our class here uses two additional techniques, though:

It displays the instance’s memory address by calling the id built-function, which returns any object’s address (by definition, a unique object identifier, which will be useful in later mutations of this code).

It uses the pseudoprivate naming pattern for its worker method: __attrnames. As we learned earlier in his chapter, Python automatically localizes any such name to its enclosing class by expanding the attribute name to include the class name (in this case, it becomes _ListInstance__attrnames). This holds true for both class attributes (like methods) and instance attributes attached to self. This behavior is useful in a general tool like this, as it ensures that its names don’t clash with any names used in its client subclasses.

Because ListInstance defines a __str__ operator overloading method, instances derived from this class display their attributes automatically when printed, giving a bit more information than a simple address. Here is the class in action, in single-inheritance mode (this code works the same in both Python 3.0 and 2.6):

>>> from lister import ListInstance

>>> class Spam(ListInstance): # Inherit a __str__ method

... def __init__(self):

... self.data1 = 'food'

...

>>> x = Spam()

>>> print(x) # print() and str() run __str__

name data1=food

>

You can also fetch the listing output as a string without printing it with str, and interactive echoes still use the default format:

>>> str(x)

''

>>> x # The __repr__ still is a default

<__main__.Spam object at 0x026606F0>

The ListInstance class is useful for any classes you write—even classes that already have one or more superclasses. This is where multiple inheritance comes in handy: by adding ListInstance to the list of superclasses in a class header (i.e., mixing it in), you get its __str__ “for free” while still inheriting from the existing superclass(es). The file testmixin.py demonstrates:

# File testmixin.py

from lister import * # Get lister tool classes

class Super:

def __init__(self): # Superclass __init__

self.data1 = 'spam' # Create instance attrs

def ham(self):

pass

class Sub(Super, ListInstance): # Mix in ham and a __str__

def __init__(self): # listers have

Return Main Page Previous Page Next Page

®Online Book Reader