Online Book Reader

Home Category

Learning Python - Mark Lutz [595]

By Root 1538 0
run the rest of recur1 without a glitch. When the recur2 import resumes, the second from finds the name Y in recur1 (it’s been run completely), so no error is reported. Running a file as a script is not the same as importing it as a module; these cases are the same as running the first import or from in the script interactively. For instance, running recur1 as a script is the same as importing recur2 interactively, as recur2 is the first module imported in recur1.

Part VI, Classes and OOP

See Test Your Knowledge: Part VI Exercises in Chapter 31 for the exercises.

Inheritance. Here’s the solution code for this exercise (file adder.py), along with some interactive tests. The __add__ overload has to appear only once, in the superclass, as it invokes type-specific add methods in subclasses:class Adder:

def add(self, x, y):

print('not implemented!')

def __init__(self, start=[]):

self.data = start

def __add__(self, other): # Or in subclasses?

return self.add(self.data, other) # Or return type?

class ListAdder(Adder):

def add(self, x, y):

return x + y

class DictAdder(Adder):

def add(self, x, y):

new = {}

for k in x.keys(): new[k] = x[k]

for k in y.keys(): new[k] = y[k]

return new

% python

>>> from adder import *

>>> x = Adder()

>>> x.add(1, 2)

not implemented!

>>> x = ListAdder()

>>> x.add([1], [2])

[1, 2]

>>> x = DictAdder()

>>> x.add({1:1}, {2:2})

{1: 1, 2: 2}

>>> x = Adder([1])

>>> x + [2]

not implemented!

>>>

>>> x = ListAdder([1])

>>> x + [2]

[1, 2]

>>> [2] + x

Traceback (innermost last):

File "", line 1, in ?

TypeError: __add__ nor __radd__ defined for these operands

Notice in the last test that you get an error for expressions where a class instance appears on the right of a +; if you want to fix this, use __radd__ methods, as described in “Operator Overloading” in Chapter 29.

If you are saving a value in the instance anyhow, you might as well rewrite the add method to take just one argument, in the spirit of other examples in this part of the book:class Adder:

def __init__(self, start=[]):

self.data = start

def __add__(self, other): # Pass a single argument

return self.add(other) # The left side is in self

def add(self, y):

print('not implemented!')

class ListAdder(Adder):

def add(self, y):

return self.data + y

class DictAdder(Adder):

def add(self, y):

pass # Change to use self.data instead of x

x = ListAdder([1, 2, 3])

y = x + [4, 5, 6]

print(y) # Prints [1, 2, 3, 4, 5, 6]

Because values are attached to objects rather than passed around, this version is arguably more object-oriented. And, once you’ve gotten to this point, you’ll probably find that you can get rid of add altogether and simply define type-specific __add__ methods in the two subclasses.

Operator overloading. The solution code (file mylist.py) uses a few operator overloading methods that the text didn’t say much about, but they should be straightforward to understand. Copying the initial value in the constructor is important because it may be mutable; you don’t want to change or have a reference to an object that’s possibly shared somewhere outside the class. The __getattr__ method routes calls to the wrapped list. For hints on an easier way to code this in Python 2.2 and later, see Extending Types by Subclassing in Chapter 31:class MyList:

def __init__(self, start):

#self.wrapped = start[:] # Copy start: no side effects

self.wrapped = [] # Make sure it's a list here

for x in start: self.wrapped.append(x)

def __add__(self, other):

return MyList(self.wrapped + other)

def __mul__(self, time):

return MyList(self.wrapped * time)

def __getitem__(self, offset):

return self.wrapped[offset]

def __len__(self):

return len(self.wrapped)

def __getslice__(self, low, high):

return MyList(self.wrapped[low:high])

def append(self, node):

self.wrapped.append(node)

def __getattr__(self, name): # Other methods: sort/reverse/etc

return getattr(self.wrapped, name)

def __repr__(self):

return repr(self.wrapped)

if __name__ == '__main__':

x = MyList('spam')

print(x)

Return Main Page Previous Page Next Page

®Online Book Reader