Beginning Python - From Novice to Professional

Beginning Python - From Novice to Professional Beginning Python - From Novice to Professional

16.01.2014 Views

CHAPTER 7 ■ MORE ABSTRACTION 151 >>> f = FoodExpert() >>> f.init() >>> map(f.addGoodFood, ['SPAM', 'Eggs', 'Bacon', 'Rat', 'Spring Surprise']) [None, None, None, None, None] The first two lines instantiate FoodExpert and initialize the instance, which is assigned to f. The map call simply uses the method addGoodFood with its self parameter bound to f. Because this method doesn’t return anything, the result is a list filled with None. However, a side effect is that f has been updated: >>> f.goodFood ['SPAM', 'Eggs', 'Bacon', 'Rat', 'Spring Surprise'] Let’s use this expert to give us a list of recommendations: >>> menu = ['Filet Mignon', 'Pasta', 'Pizza', 'Eggs', 'Bacon', 'Tomato', 'SPAM'] >>> rec = filter(f.likes, menu) >>> rec ['Eggs', 'Bacon', 'SPAM'] What I did here was simply apply f.likes as a filter to a menu; the dishes the expert didn’t like were simply discarded. But what if you want to find out which of these dishes the expert would prefer? I once again turn to the trusty (if rarely used) reduce: >>> reduce(f.prefers, rec) 'SPAM' This basically works just like the example using reduce with max in Chapter 6 (in the section “reduce”). If I had used a different expert, initialized with different preferences, of course, I’d get completely different results, even though the method definitions would be exactly the same. This is the primary difference between standard functional programming and this quasi-functional programming using bound methods; the methods have access to a state that can be used to “customize” them. ■Note You can pass state along with a function like this by using nested scopes as well, as discussed in the previous chapter. The Class Namespace The following two statements are (more or less) equivalent: def foo(x): return x*x foo = lambda x: x*x

152 CHAPTER 7 ■ MORE ABSTRACTION Both create a function that returns the square of its argument, and both bind the variable foo to that function. The name foo may be defined in the global (module) scope, or it may be local to some function or method. The same thing happens when you define a class; all the code in the class statement is executed in a special namespace—the class namespace. This namespace is accessible later by all members of the class. Not all Python programmers know that class definitions are simply code sections that are executed, but it can be useful information. For example, you aren’t restricted to def statements: >>> class C: print 'Class C being defined...' Class C being defined... >>> Okay, that was a bit silly. But consider the following: class MemberCounter: members = 0 def init(self): MemberCounter.members += 1 >>> m1 = MemberCounter() >>> m1.init() >>> MemberCounter.members 1 >>> m2 = MemberCounter() >>> m2.init() >>> MemberCounter.members 2 In the preceding code, a variable is defined in the class scope, which can be accessed by all the members (instances), in this case to count the number of class members. Note the use of init to initialize all the instances: I’ll automate that in Chapter 9. This class scope variable is accessible from every instance as well, just as methods are: >>> m1.members 2 >>> m2.members 2 What happens when you rebind the members attribute in an instance? >>> m1.members = 'Two' >>> m1.members 'Two' >>> m2.members 2 The new members value has been written into an attribute in m1, shadowing the classwide variable. This mirrors the behavior of local and global variables.

152 CHAPTER 7 ■ MORE ABSTRACTION<br />

Both create a function that returns the square of its argument, and both bind the variable<br />

foo <strong>to</strong> that function. The name foo may be defined in the global (module) scope, or it may be<br />

local <strong>to</strong> some function or method. The same thing happens when you define a class; all the<br />

code in the class statement is executed in a special namespace—the class namespace. This<br />

namespace is accessible later by all members of the class. Not all <strong>Python</strong> programmers know<br />

that class definitions are simply code sections that are executed, but it can be useful information.<br />

For example, you aren’t restricted <strong>to</strong> def statements:<br />

>>> class C:<br />

print 'Class C being defined...'<br />

Class C being defined...<br />

>>><br />

Okay, that was a bit silly. But consider the following:<br />

class MemberCounter:<br />

members = 0<br />

def init(self):<br />

MemberCounter.members += 1<br />

>>> m1 = MemberCounter()<br />

>>> m1.init()<br />

>>> MemberCounter.members<br />

1<br />

>>> m2 = MemberCounter()<br />

>>> m2.init()<br />

>>> MemberCounter.members<br />

2<br />

In the preceding code, a variable is defined in the class scope, which can be accessed by all<br />

the members (instances), in this case <strong>to</strong> count the number of class members. Note the use of<br />

init <strong>to</strong> initialize all the instances: I’ll au<strong>to</strong>mate that in Chapter 9.<br />

This class scope variable is accessible from every instance as well, just as methods are:<br />

>>> m1.members<br />

2<br />

>>> m2.members<br />

2<br />

What happens when you rebind the members attribute in an instance?<br />

>>> m1.members = 'Two'<br />

>>> m1.members<br />

'Two'<br />

>>> m2.members<br />

2<br />

The new members value has been written in<strong>to</strong> an attribute in m1, shadowing the classwide<br />

variable. This mirrors the behavior of local and global variables.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!