【Python】编程笔记7
文章目錄
- 面向對象高級編程
- 一、__slots__
- 二、@property裝飾器
- 三、多重繼承——MixIn
- 四、定制類——`__xxx__`
- 1、`__str__()` 與 `__repr__()`
- 2、`__iter__()`
- 3、`__getitem__()`
- 4、`__getattr__()`
- 5、`__call__()`
- 五、枚舉類——Enum類
- 六、使用元類
- 1、type()
- 七、錯誤、調試和測試
- 1、錯誤處理
- 2、調用堆棧
- 3、記錄錯誤
- 4、拋出錯誤
- 5、調試
- 6、單元測試
面向對象高級編程
高級特性:多重繼承、定制類、元類等概念。
一、slots
__slots__變量:限制該 class 實例能添加的屬性。
class Student(object):__slots__ = ('name', 'age')s = Student() s.name = 'Michael' s.age = 25 s.score = 99 print(s.name) print(s.age) print(s.score)==》AttributeError 的錯誤
AttributeError: 'Student' object has no attribute 'score'注意:__slots__ 定義的屬性僅對當前類實例起作用,對繼承的子類是不起作用的。除非在子類中也定義 __slots__,這樣,子類實例允許定義的屬性就是自身的__slots__加上父類的__slots__。
class GraduateStudent(Student):pass g = GraduateStudent() g.score = 9999 print(g.score) ## 9999二、@property裝飾器
負責把一個方法變成屬性調用的。
class Student(object):@propertydef score(self):return self._score@score.setterdef score(self, value):if not isinstance(value, int):raise ValueError('score must be an integer!')if value < 0 or value > 100:raise ValueError('score must between 0 ~ 100!')self._score = values = Student() s.score = 60 print(s.score) s.score = 999 print(s.score)輸出結果
60 Traceback (most recent call last):File "E:/codes/python/basic/6.py", line 169, in <module>s.score = 999File "E:/codes/python/basic/6.py", line 163, in scoreraise ValueError('score must between 0 ~ 100!') ValueError: score must between 0 ~ 100!把一個 getter 方法變成屬性,只需要加上@property 就可以了,此時, @property 本身又創建了另一個裝飾器@score.setter,負責把一個 setter 方法變成屬性賦值。
三、多重繼承——MixIn
MixIn 的目:給一個類增加多個功能。
在設計類的時候,要優先考慮通過多重繼承來組合多個 MixIn 的功能,而不是設計多層次的復雜的繼承關系。
class Animal(object):passclass RunnableMixIn(object):def run(self):print('Running...') class Mammal(Animal):pass ## Dog為多繼承,繼承于 Mammal 和 RunnableMixIn class Dog(Mammal, RunnableMixIn):pass四、定制類——__xxx__
Python 的 class 中還有許多這樣有特殊用途的函數,可以幫
助我們定制類。
1、__str__() 與 __repr__()
class Student(object):def __init__(self, name):self.name = namedef __str__(self):return 'Student object (name: %s)' % self.nameprint(Student('Michael'))結果對比:
- 未自定義 __str__() 的結果
<__main__.Student object at 0x000001994F615FD0> - 自定義 __str__() 的結果
Student object (name: Michael)
在交互的模式下,直接輸出 s,打印出來的 <__main__.Student object at 0x109afb310> 也并不好看。
直接顯示變量調用的是 __repr__() 而非 __str__() 。
==》
區別:__str__()返回用戶看到的字符串,而__repr__()返回程序開發者看到的字符串,也就是說,__repr__()是為調試服務的。
==》解決辦法:再定義一個__repr__()
2、__iter__()
__iter__():用于 for…in 循環,該函數返回一個迭代對象。
然后,Python 的 for 循環就不斷用該迭代對象的 __next__() 方法獲取循環的下一個值,直到遇到 StopIteration 錯誤時退出循環。
class Fib(object):def __init__(self):self.a, self.b = 0, 1 # 初始化兩個計數器a,bdef __iter__(self):return self # 實例本身就是迭代對象,故返回自己def __next__(self):self.a, self.b = self.b, self.a + self.b # 計算下一個值if self.a > 100000: # 退出循環的條件raise StopIterationreturn self.afor n in Fib():print(n)輸出結果
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 750253、__getitem__()
可以按照下標取出元素 ==》__getitem__() 方法
class Fib(object):def __getitem__(self, n):a, b = 1, 1for x in range(n):a, b = b, a + breturn a f = Fib() print(f[0]) print(f[1]) print(f[100])輸出結果
1 1 573147844013817084101==》切片操作
原因:__getitem__() 傳入的參數可能是一個 int,也可能是一個切片對象 slice,所以要做判斷。
輸出結果
[1, 1, 2, 3, 5] [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]分析:沒有對 step 參數、負數等做處理。
==》將對象看出 dict
==》__getitem__() 的參數可能作 key 的 object。其對應的 __setitem__() 方法:將對象看作 list 或 dict 來對集合賦值;__delitem__() 方法:刪除某個元素。
4、__getattr__()
為了避免由于類的方法或屬性不在造成的 AttributeError 錯誤,使用 __getattr__() ,動態返回一個屬性。
class Student(object):def __init__(self):self.name = 'Michael'def __getattr__(self, attr):if attr == 'score':return 99elif attr == 'age':return lambda:25# 若均不匹配,則拋出 AttributeError 的錯誤raise AttributeError('\'Student\'object has no attribute \'%s\'' % attr)==》當調用不存在的屬性時,比如 score, Python 解釋器會試圖調用__getattr__(self, ‘score’)來嘗試獲得屬性,從而可以返回score的值99。
常約定 class 只響應特定的幾個屬性,否則拋出 AttributeError 的錯誤。
5、__call__()
對實例進行直接調用。
class Student(object):def __init__(self, name):self.name = namedef __call__(self, *args, **kwargs):print('My name is %s' % self.name)s = Student('Michael') print(s()) # My name is Michael判斷一個對象是否能被調用,若可被調用,則該對象是一個 Callable 對象——callable()
>>> callable(Student()) True >>> callable(max) True >>> callable([1, 2, 3]) False >>> callable(None) False >>> callable('str') False五、枚舉類——Enum類
from enum import Enum# Month類型的枚舉類 定義 Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')) print(Month.Jun)# 枚舉所有成員,value屬性為int常量,默認從1開始計數 for name, member in Month.__members__.items():print(name, '=>', member, ',', member.value)精確控制枚舉類型 ==》Enum的派生類
from enum import Enum, unique @unique # 該裝飾器確保無重復值 class Weekday(Enum):Sun = 0 # Sun 的 value 被設定為 0Mon = 1Tue = 2Wed = 3Thu = 4Fri = 5Sat = 6## 枚舉類型的訪問 day1 = Weekday.Mon print(day1) print(Weekday.Tue) # 用成員名稱引用枚舉常量 print(Weekday['Tue']) print(Weekday.Tue.value) print(day1 == Weekday.Mon) print(day1 == Weekday.Tue) print(Weekday(1)) # 根據 value 的值獲得枚舉常量 print(day1 == Weekday(1)) # print(Weekday(7)) for name, member in Weekday.__members__.items():print(name, '=>', member)既可以用成員名稱引用枚舉常量,又可以直接根據 value 的值獲得枚舉常量。
六、使用元類
1、type()
動態語言的函數和類的定義在運行時動態創建的。
type()函數既可以返回一個對象的類型,又可以創建出新的類型。
。。。。。
七、錯誤、調試和測試
1、錯誤處理
處理機制:try…except…finally…(可以多個except)
如果執行出錯,則后續代碼不會繼續執行,而是直接跳轉至錯誤處理代碼,即 except 語句塊,執行完 except 后,如果有 finally 語句塊,則執行 finally 語句塊,至此,執行完畢。
若沒有錯誤,執行完try部分,不執行except部分而執行finally部分。
try:print('try...')r = 10 / int('a')print('result: ', r) except ValueError as e:print('ValueError: ', e) except ZeroDivisionError as e:print('ZeroDivisionError: ', e) finally:print('finally...') print('END')輸出結果
try... ValueError: invalid literal for int() with base 10: 'a' finally... ENDPython 所有的錯誤都是從 BaseException 類派生的,常見的錯誤類型和繼承關系看這里:
https://docs.python.org/3/library/exceptions.html#exception-hierarchy
2、調用堆棧
解讀錯誤信息是定位錯誤的關鍵。我們從上往下可以看到整個錯誤的調用函數鏈。
3、記錄錯誤
import loggingdef foo(s):return 10 / int(s) def bar(s):return foo(s) * 2 def main():try:bar('0')except Exception as e:logging.exception(e)main() print('END')4、拋出錯誤
5、調試
- print()可能錯誤的變量值
- 斷言(assert):assert 表達式, ‘輸出語句’==》表達式為真,繼續執行,否則拋出 AssertionError錯誤并輸出后面的輸出語句。
- python -0 文件.py ==》關閉assert
- logging輸出到文件;
- 調試器 pdb,可以單步調試
6、單元測試
用來對一個模塊、一個函數或者一個類來進行正確性檢驗的測試工作。
==》確保一個程序模塊的行為符合我們設計的測試用例。
測試用例:
- 輸入正數;
- 輸入負數;
- 輸入0;
- 輸入非數值類型
總結
以上是生活随笔為你收集整理的【Python】编程笔记7的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Python】编程笔记6
- 下一篇: 【Python】编程笔记8