[TOC]
## 第一章 面向對象設計
總體感覺,作者有點羅嗦,他有時開一些可有可無的玩笑,例如,“我們桌上的三個桔子(如果我們還沒有吃掉的話)”,括號里的內容并沒什么用處。
在Python中,“只讀”的概念毫無意義。
多重繼承可能是一項棘手的業務,一些編程語言(特別是Java)嚴格禁止它。
正如我們將在第5章“何時使用面向對象編程”中討論的,特性關鍵字在python中對于特定類型的屬性具有特殊的含義。
P14:`hollow`是空心的意思,但圖中明顯是實心箭頭。P15也有這個問題。
P16:這里講的繼承和多態是令人迷惑的,標題說“繼承提供抽象”,然后貌似講的是“多態”,貌似繼承之所以可以實現,是因為“多態”。
P21:注意異步信息。
P41:叫你的代碼如何優雅起來。
## 第三章 當對象是相似的
原書在P60中創建了一個聯系人類`Contact`,類中有一個類變量`all_contacts`,類變量在整個實例化的對象中是公用的,注意最后一行是`Contact.all_contacts.append(self)`。
```
class Contact:
all_contacts = []
def __init__(self, name, email):
self.name = name
self.email = email
Contact.all_contacts.append(self)
```
在P62,聯系人類`Contact`最后一行變成`self.all_contacts.append(self)`,看起來類變量變成了實例變量,但兩段代碼運行結果是相同的。至于原因嘛,目前不明。
```
class Contact:
all_contacts = ContactList()
def __init__(self,name,email):
self.name = name
self.email = email
self.all_contacts.append(self)
```
### Basic inheritance
parentClass or supuerClass
```
class Contact:
all_contacts = []
def __init__(self, name, email):
self.name = name
self.email = email
Contact.all_contacts.append(self)
```
```
class Supplier(Contact):
def order(self,order):
print("If this were a real system we would send ""'{}' order to '{}'".format(order,self.name))
# example:
>>> s = Supplier("Sup Plier", "supplier@example.net")
>>> s.order("I need pliers")
```
### Inheriting from built-ins
```
class ContactList(list):
def search(self,name):
matching_contacts = []
for contact in self:
if name in contact.name:
matching_contacts.append(contact)
return matching_contacts
class Contact:
all_contacts = ContactList()
def __init__(self,name,email):
self.name = name
self.email = email
self.all_contacts.append(self)
# example:
>>> c1 = Contact("John A", "johna@example.net")
>>> c2 = Contact("John B", "johnb@example.net")
>>> c3 = Contact("Jenna C", "jennac@example.net")
>>> [c.name for c in Contact.all_contacts.search('John')]
['John A', 'John B']
class LongNameDict(dict):
def longest_key(self):
longest = None
for key in self:
if not longest or len(key) > len(longest):
longest = key
return longest
# example:
>>> longkeys = LongNameDict()
>>> longkeys['hello'] = 1
>>> longkeys['longest yet'] = 5
>>> longkeys['hello2'] = 'world'
>>> longkeys.longest_key()
'longest yet'
```
### Overriding and super
```
class Friend(Contact):
def __init__(self,name,email,num,phone):
super().__init__(name,email,num)
self.phone = phone
```
### Multiple inheritance
The simplest and most useful form of multiple inheritance is called a **mixin**.
```
class MailSender:
def send_mail(self,messeage):
print("Sending mail '{}' to ".format(messeage) + self.email)
class EmailableContact(Contact,MailSender):
pass
# example:
>>> e = EmailableContact("John Smith", "jsmith@example.net")
>>> e.send_mail("Hello, test e-mail here")
Sending mail 'Hello, test e-mail here' to jsmith@example.net
```
```
class AddressHolder:
def __init__(self, street, city, state, code):
self.street = street
self.city = city
self.state = state
self.code = code
# The follow is A very bad method for inheritance ! NOT RECOMMENDED !
class Friend(Contact, AddressHolder):
def __init__(
self, name, email, phone,street, city, state, code):
Contact.__init__(self, name, email)
AddressHolder.__init__(self, street, city, state, code)
self.phone = phone
```
#### Diamond Problem

```
# The follow are still a bad method and could lead to some insidious bugs! e.g. like depositing into a bank account—twice.
class BaseClass:
num_base_calls = 0
def call_me(self):
print("Calling method on Base Class")
self.num_base_calls += 1
class LeftSubclass(BaseClass):
num_left_calls = 0
def call_me(self):
BaseClass.call_me(self)
print("Calling method on Left Subclass")
self.num_left_calls += 1
class RightSubclass(BaseClass):
num_right_calls = 0
def call_me(self):
BaseClass.call_me(self)
print("Calling method on Right Subclass")
self.num_right_calls += 1
class Subclass(LeftSubclass, RightSubclass):
num_sub_calls = 0
def call_me(self):
LeftSubclass.call_me(self)
RightSubclass.call_me(self)
print("Calling method on Subclass")
self.num_sub_calls += 1
>>> s = Subclass()
>>> s.call_me()
Calling method on Base Class
Calling method on Left Subclass
Calling method on Base Class
Calling method on Right Subclass
Calling method on Subclass
>>> print(
... s.num_sub_calls,
... s.num_left_calls,
... s.num_right_calls,
... s.num_base_calls)
1 1 1 2
```
#### Diamond Problem_Cont
```
# The follow are better methods ! NOT BEST!
class BaseClass:
num_base_calls = 0
def call_me(self):
print("Calling method on Base Class")
self.num_base_calls += 1
class LeftSubclass(BaseClass):
num_left_calls = 0
def call_me(self):
super().call_me()
print("Calling method on Left Subclass")
self.num_left_calls += 1
class RightSubclass(BaseClass):
num_right_calls = 0
def call_me(self):
super().call_me()
print("Calling method on Right Subclass")
self.num_right_calls += 1
class Subclass(LeftSubclass, RightSubclass):
num_sub_calls = 0
def call_me(self):
super().call_me()
print("Calling method on Subclass")
self.num_sub_calls += 1
>>> s = Subclass()
>>> s.call_me()
Calling method on Base Class
Calling method on Right Subclass
Calling method on Left Subclass
Calling method on Subclass
>>> print(s.num_sub_calls, s.num_left_calls, s.num_right_calls,
s.num_base_calls)
1 1 1 1
```
#### Friend multiple inheritance_Cont
```
class Contact:
all_contacts = []
def __init__(self, name='', email='', **kwargs):
super().__init(**kwargs)
self.name = name
self.email = email
self.all_contacts.append(self)
class AddressHolder:
def __init__(self, street='', city='',state='', code='',**kwargs):
super().__init__(**kwargs)
self.street = street
self.city =
```
第六章:
不要使用列表來收集具有單個項目的不同屬性。
如果列表含混合的不可排序的項,排序將引發`TypeError`異常。