1+ [ Contents] ( ../Contents ) \| [ Previous (4.4 Exceptions)] ( ../04_Classes_objects/04_Defining_exceptions ) \| [ Next (5.2 Encapsulation)] ( 02_Classes_encapsulation )
2+
13# 5.1 Dictionaries Revisited
24
3- The Python object system is largely based on an implementation based on dictionaries. This
4- section discusses that.
5+ The Python object system is largely based on an implementation
6+ involving dictionaries. This section discusses that.
57
68### Dictionaries, Revisited
79
@@ -15,12 +17,14 @@ stock = {
1517}
1618```
1719
18- Dictionaries are commonly used for simple data structures.
19- However, they are used for critical parts of the interpreter and may be the * most important type of data in Python* .
20+ Dictionaries are commonly used for simple data structures. However,
21+ they are used for critical parts of the interpreter and may be the
22+ * most important type of data in Python* .
2023
2124### Dicts and Modules
2225
23- In a module, a dictionary holds all of the global variables and functions.
26+ Within a module, a dictionary holds all of the global variables and
27+ functions.
2428
2529``` python
2630# foo.py
@@ -33,7 +37,7 @@ def spam():
3337 ...
3438```
3539
36- If we inspect ` foo.__dict__ ` or ` globals() ` , you'll see the dictionary.
40+ If you inspect ` foo.__dict__ ` or ` globals() ` , you'll see the dictionary.
3741
3842``` python
3943{
@@ -45,8 +49,9 @@ If we inspect `foo.__dict__` or `globals()`, you'll see the dictionary.
4549
4650### Dicts and Objects
4751
48- User defined objects also use dictionaries for both instance data and classes.
49- In fact, the entire object system is mostly an extra layer that's put on top of dictionaries.
52+ User defined objects also use dictionaries for both instance data and
53+ classes. In fact, the entire object system is mostly an extra layer
54+ that's put on top of dictionaries.
5055
5156A dictionary holds the instance data, ` __dict__ ` .
5257
@@ -59,8 +64,8 @@ A dictionary holds the instance data, `__dict__`.
5964You populate this dict (and instance) when assigning to ` self ` .
6065
6166``` python
62- class Stock ( object ) :
63- def __init__ (self ,name ,shares ,price ):
67+ class Stock :
68+ def __init__ (self , name , shares , price ):
6469 self .name = name
6570 self .shares = shares
6671 self .price = price
@@ -79,27 +84,28 @@ The instance data, `self.__dict__`, looks like this:
7984** Each instance gets its own private dictionary.**
8085
8186``` python
82- s = Stock(' GOOG' ,100 ,490.1 ) # {'name' : 'GOOG','shares' : 100, 'price': 490.1 }
83- t = Stock(' AAPL' ,50 ,123.45 ) # {'name' : 'AAPL','shares' : 50, 'price': 123.45 }
87+ s = Stock(' GOOG' , 100 , 490.1 ) # {'name' : 'GOOG','shares' : 100, 'price': 490.1 }
88+ t = Stock(' AAPL' , 50 , 123.45 ) # {'name' : 'AAPL','shares' : 50, 'price': 123.45 }
8489```
8590
86- If you created 200 instances of some class, there are 100 dictionaries sitting around holding data.
91+ If you created 100 instances of some class, there are 100 dictionaries
92+ sitting around holding data.
8793
8894### Class Members
8995
9096A separate dictionary also holds the methods.
9197
9298``` python
93- class Stock ( object ) :
94- def __init__ (self ,name ,shares ,price ):
99+ class Stock :
100+ def __init__ (self , name , shares , price ):
95101 self .name = name
96102 self .shares = shares
97103 self .price = price
98104
99105 def cost (self ):
100106 return self .shares * self .price
101107
102- def sell (self ,nshares ):
108+ def sell (self , nshares ):
103109 self .shares -= nshares
104110```
105111
@@ -115,8 +121,8 @@ The dictionary is in `Stock.__dict__`.
115121
116122### Instances and Classes
117123
118- Instances and classes are linked together.
119- The ` __class__ ` attribute refers back to the class.
124+ Instances and classes are linked together. The ` __class__ ` attribute
125+ refers back to the class.
120126
121127``` python
122128>> > s = Stock(' GOOG' , 100 , 490.1 )
@@ -127,7 +133,9 @@ The `__class__` attribute refers back to the class.
127133>> >
128134```
129135
130- The instance dictionary holds data unique to each instance, whereas the class dictionary holds data collectively shared by * all* instances.
136+ The instance dictionary holds data unique to each instance, whereas
137+ the class dictionary holds data collectively shared by * all*
138+ instances.
131139
132140### Attribute Access
133141
@@ -207,26 +215,30 @@ This provides a link to parent classes.
207215
208216### Reading Attributes with Inheritance
209217
210- First, check in local ` __dict__ ` . If not found, look in ` __dict__ ` of class through ` __class__ ` .
211- If not found in class, look in base classes through ` __bases__ ` .
218+ Logically, the process of finding an attribute is as follows. First,
219+ check in local ` __dict__ ` . If not found, look in ` __dict__ ` of the
220+ class. If not found in class, look in the base classes through
221+ ` __bases__ ` . However, there are some subtle aspects of this discussed next.
212222
213223### Reading Attributes with Single Inheritance
214224
215- In inheritance hierarchies, attributes are found by walking up the inheritance tree.
225+ In inheritance hierarchies, attributes are found by walking up the
226+ inheritance tree in order.
216227
217228``` python
218- class A ( object ) : pass
229+ class A : pass
219230class B (A ): pass
220231class C (A ): pass
221232class D (B ): pass
222233class E (D ): pass
223234```
224- With Single Inheritance , there ia single path to the top.
235+ With single inheritance , there is single path to the top.
225236You stop with the first match.
226237
227238### Method Resolution Order or MRO
228239
229240Python precomputes an inheritance chain and stores it in the * MRO* attribute on the class.
241+ You can view it.
230242
231243``` python
232244>> > E.__mro__
@@ -236,38 +248,39 @@ Python precomputes an inheritance chain and stores it in the *MRO* attribute on
236248>> >
237249```
238250
239- This chain is called the ** Method Resolutin Order** .
240- The find the attributes , Python walks the MRO. First match, wins.
251+ This chain is called the ** Method Resolutin Order** . The find an
252+ attribute , Python walks the MRO in order. The first match wins.
241253
242254### MRO in Multiple Inheritance
243255
244- There is no single path to the top with multiple inheritance .
256+ With multiple inheritance, there is no single path to the top.
245257Let's take a look at an example.
246258
247259``` python
248- class A ( object ) : pass
249- class B ( object ) : pass
260+ class A : pass
261+ class B : pass
250262class C (A , B ): pass
251263class D (B ): pass
252264class E (C , D ): pass
253265```
254266
255- What happens when we do ?
267+ What happens when you access at attribute ?
256268
257269``` python
258270e = E()
259271e.attr
260272```
261273
262- A similar search process is carried out, but what is the order? That's a problem.
274+ A attribute search process is carried out, but what is the order? That's a problem.
263275
264- Python uses * cooperative multiple inheritance* .
265- These are some rules about class ordering:
276+ Python uses * cooperative multiple inheritance* which obeys some rules
277+ about class ordering.
266278
267- * Children before parents
268- * Parents go in order
279+ * Children are always checked before parents
280+ * Parents (if multiple) are always checked in the order listed.
269281
270- The MRO is computed using those rules.
282+ The MRO is computed by sorting all of the classes in a hierarchy
283+ according to those rules.
271284
272285``` python
273286>> > E.__mro__
@@ -281,12 +294,18 @@ The MRO is computed using those rules.
281294>> >
282295```
283296
284- ### An Odd Code Reuse
297+ The underlying algorithm is called the "C3 Linearization Algorithm."
298+ The precise details aren't important as long as you remember that a
299+ class hierarchy obeys the same ordering rules you might follow if your
300+ house was on fire and you had to evacuate--children first, followed by
301+ parents.
302+
303+ ### An Odd Code Reuse (Involving Multiple Inheritance)
285304
286305Consider two completely unrelated objects:
287306
288307``` python
289- class Dog ( object ) :
308+ class Dog :
290309 def noise (self ):
291310 return ' Bark'
292311
@@ -295,14 +314,14 @@ class Dog(object):
295314
296315class LoudDog (Dog ):
297316 def noise (self ):
298- # Code commonality with LoudBike
317+ # Code commonality with LoudBike (below)
299318 return super ().noise().upper()
300319```
301320
302321And
303322
304323``` python
305- class Bike ( object ) :
324+ class Bike :
306325 def noise (self ):
307326 return ' On Your Left'
308327
@@ -311,19 +330,20 @@ class Bike(object):
311330
312331class LoudBike (Bike ):
313332 def noise (self ):
314- # Code commonality with LoudDog
333+ # Code commonality with LoudDog (above)
315334 return super ().noise().upper()
316335```
317336
318337There is a code commonality in the implementation of ` LoudDog.noise() ` and
319- ` LoudBike.noise() ` . In fact, the code is exactly the same.
338+ ` LoudBike.noise() ` . In fact, the code is exactly the same. Naturally,
339+ code like that is bound to attract software engineers.
320340
321341### The "Mixin" Pattern
322342
323343The * Mixin* pattern is a class with a fragment of code.
324344
325345``` python
326- class Loud ( object ) :
346+ class Loud :
327347 def noise (self ):
328348 return super ().noise().upper()
329349```
@@ -339,26 +359,31 @@ class LoudBike(Loud, Bike):
339359 pass
340360```
341361
342- This is one of the primary uses of multiple inheritance in Python.
362+ Miraculously, loudness was now implemented just once and reused
363+ in two completely unrelated classes. This sort of trick is one
364+ of the primary uses of multiple inheritance in Python.
343365
344366### Why ` super() `
345367
346368Always use ` super() ` when overriding methods.
347369
348370``` python
349- class Loud ( object ) :
371+ class Loud :
350372 def noise (self ):
351373 return super ().noise().upper()
352374```
353375
354376` super() ` delegates to the * next class* on the MRO.
355377
356- The tricky bit is that you don't know what it is when you create the Mixin.
378+ The tricky bit is that you don't know what it is. You especially don't
379+ know what it is if multiple inheritance is being used.
357380
358381### Some Cautions
359382
360- Multiple inheritance is a powerful tool. Remember that with power comes responsibility.
361- Frameworks / libraries sometimes use it for advanced features involving composition of components.
383+ Multiple inheritance is a powerful tool. Remember that with power
384+ comes responsibility. Frameworks / libraries sometimes use it for
385+ advanced features involving composition of components. Now, forget
386+ that you saw that.
362387
363388## Exercises
364389
@@ -376,7 +401,8 @@ few instances:
376401
377402### Exercise 5.1: Representation of Instances
378403
379- At the interactive shell, inspect the underlying dictionaries of the two instances you created:
404+ At the interactive shell, inspect the underlying dictionaries of the
405+ two instances you created:
380406
381407``` python
382408>> > goog.__dict__
@@ -537,7 +563,7 @@ two steps and something known as a bound method. For example:
537563``` python
538564>> > s = goog.sell
539565>> > s
540- < bound method Stock.sell of Stock(' GOOG' ,100 ,490.1 )>
566+ < bound method Stock.sell of Stock(' GOOG' , 100 , 490.1 )>
541567>> > s(25 )
542568>> > goog.shares
54356975
0 commit comments