Online Book Reader

Home Category

Learning Python - Mark Lutz [396]

By Root 1327 0
you want a single display for all contexts. By defining both methods, though, you can support different displays in different contexts—for example, an end-user display with __str__, and a low-level display for programmers to use during development with __repr__. In effect, __str__ simply overrides __repr__ for user-friendly display contexts:

>>> class addboth(adder):

... def __str__(self):

... return '[Value: %s]' % self.data # User-friendly string

... def __repr__(self):

... return 'addboth(%s)' % self.data # As-code string

...

>>> x = addboth(4)

>>> x + 1

>>> x # Runs __repr__

addboth(5)

>>> print(x) # Runs __str__

[Value: 5]

>>> str(x), repr(x)

('[Value: 5]', 'addboth(5)')

I should mention two usage notes here. First, keep in mind that __str__ and __repr__ must both return strings; other result types are not converted and raise errors, so be sure to run them through a converter if needed. Second, depending on a container’s string-conversion logic, the user-friendly display of __str__ might only apply when objects appear at the top level of a print operation; objects nested in larger objects might still print with their __repr__ or its default. The following illustrates both of these points:

>>> class Printer:

... def __init__(self, val):

... self.val = val

... def __str__(self): # Used for instance itself

... return str(self.val) # Convert to a string result

...

>>> objs = [Printer(2), Printer(3)]

>>> for x in objs: print(x) # __str__ run when instance printed

... # But not when instance in a list!

2

3

>>> print(objs)

[<__main__.Printer object at 0x025D06F0>, <__main__.Printer object at ...more...

>>> objs

[<__main__.Printer object at 0x025D06F0>, <__main__.Printer object at ...more...

To ensure that a custom display is run in all contexts regardless of the container, code __repr__, not __str__; the former is run in all cases if the latter doesn’t apply:

>>> class Printer:

... def __init__(self, val):

... self.val = val

... def __repr__(self): # __repr__ used by print if no __str__

... return str(self.val) # __repr__ used if echoed or nested

...

>>> objs = [Printer(2), Printer(3)]

>>> for x in objs: print(x) # No __str__: runs __repr__

...

2

3

>>> print(objs) # Runs __repr__, not ___str__

[2, 3]

>>> objs

[2, 3]

In practice, __str__ (or its low-level relative, __repr__) seems to be the second most commonly used operator overloading method in Python scripts, behind __init__. Any time you can print an object and see a custom display, one of these two tools is probably in use.

Right-Side and In-Place Addition: __radd__ and __iadd__

Technically, the __add__ method that appeared in the prior example does not support the use of instance objects on the right side of the + operator. To implement such expressions, and hence support commutative-style operators, code the __radd__ method as well. Python calls __radd__ only when the object on the right side of the + is your class instance, but the object on the left is not an instance of your class. The __add__ method for the object on the left is called instead in all other cases:

>>> class Commuter:

... def __init__(self, val):

... self.val = val

... def __add__(self, other):

... print('add', self.val, other)

... return self.val + other

... def __radd__(self, other):

... print('radd', self.val, other)

... return other + self.val

...

>>> x = Commuter(88)

>>> y = Commuter(99)

>>> x + 1 # __add__: instance + noninstance

add 88 1

89

>>> 1 + y # __radd__: noninstance + instance

radd 99 1

100

>>> x + y # __add__: instance + instance, triggers __radd__

add 88 <__main__.Commuter object at 0x02630910>

radd 99 88

187

Notice how the order is reversed in __radd__: self is really on the right of the +, and other is on the left. Also note that x and y are instances of the same class here; when instances of different classes appear mixed in an expression, Python prefers the class of the one on the left. When we add the two instances together, Python runs __add__, which in turn triggers __radd__ by simplifying

Return Main Page Previous Page Next Page

®Online Book Reader