好久沒更新了呀,Python的學(xué)習(xí)可不能落下你画!??
面向?qū)ο缶幊?/h2>
面向?qū)ο笤O(shè)計思想:抽象出類(Class)抵碟,根據(jù)類創(chuàng)建實例(Instance)桃漾。
面向?qū)ο蟮娜筇攸c:封裝,繼承拟逮,多態(tài)撬统。
-
類和實例:
- 類的定義:
class Student(object): pass
Student類繼承了object - 創(chuàng)建實例:
yzl = Student()
, 創(chuàng)建實例后,可以自由的給實例綁定屬性yzl.age = 18
, 僅對本實例有效 - 類的方法定義:
def __init__(self, name, age):
, 第一個變量必須是self, 但不用傳敦迄,表示此實例變量恋追。
- 類的定義:
-
訪問限制:以
__
開頭的是私有變量,外部訪問不到(但其實可以訪問到罚屋,只是Python解釋器把私有變量換了個名字苦囱,比如_Student__name
),以_
開頭的雖然可以訪問脾猛,但也要當(dāng)做私有變量撕彤,不要輕易訪問∶退總之羹铅,Python本身沒有任何機制阻止你干壞事,一切全靠自覺漆弄。class Student(object): def __init__(self, name, score): self.__name = name self.__score = score def print_score(self): print('%s: %s' % (self.__name, self.__score))
-
繼承與多態(tài):對于靜態(tài)語言睦裳,比如Java造锅,一個函數(shù)的入?yún)㈩愋捅仨毷谴_定的撼唾,而對于動態(tài)語言,只要file-like object即可. 鴨子類型:一個對象只要“看起來像鴨子哥蔚,走起路來像鴨子”倒谷,那它就可以被看做是鴨子。
只要whatever有run()方法就可以糙箍。def run_twice(whatever): whatever.run()
-
獲取對象信息:
-
type()
判斷對象類型type(123): <class 'int'>
-
isinstance()
判斷一個對象是否是某種類型isinstance('abc', str): True
-
dir()
獲取一個對象的所有屬性和方法渤愁,它返回一個包含字符串的list -
hasattr(obj, 'x')
獲取屬性setattr(obj, 'y', 19)
設(shè)置屬性,注意:只有在不知道對象信息的時候深夯,我們才會去獲取對象信息
-
實例屬性和類屬性:不通過
__init__()
構(gòu)造抖格,直接在class里定義屬性的是類屬性。實例屬性和類屬性名字不要一樣咕晋,否則類屬性在當(dāng)前實例會被覆蓋掉雹拄。限制實例的屬性:
__slots__ = ('name', 'age')
, 定義一個__slots__
限制類的實例屬性只能在tuple里,否則將報AttributeError
錯誤掌呜,注意:__slots__
只作用于當(dāng)前類實例滓玖,對子類不起作用,若子類也定義了slots质蕉,則還要加上父類的slots势篡。-
@property : 相當(dāng)于 getter翩肌,@name.setter : 相當(dāng)于 setter,這兩個decorator的目的是讓方法變?yōu)閷傩?調(diào)用方法生成了屬性)禁悠,可以寫出更簡短的代碼念祭,同時保證對參數(shù)進行必要性的檢查。
class Screen(object): @property def width(self): return self.__width @width.setter def width(self, w): self.__width = w s = Screen() print(dir(s)) # 結(jié)果為: ['__class__', '__delattr__', '__dict__', ...] s.width = 1 print(dir(s)) # 結(jié)果為: ['_Screen__width', '__class__', '__delattr__', '__dict__', ...]
多繼承:Python支持多繼承碍侦,
class class Dog(Mammal, Runnable):
-
定制類:重寫class的函數(shù)棒卷,使之符合我們的需求,以下是常用的定制類:
-
__str__
: 自定義打印實例祝钢,變量調(diào)用的是__repr__
class Student(object): def __init__(self, name): self.name = name def __str__(self): return 'Student object (name=%s)' % self.name __repr__ = __str__
-
__iter__
: 返回一個迭代對象比规,通過__next()__
方法循環(huán)獲取下一個值,知道遇到StopIteration
錯誤時推出循環(huán)class Fib(object): def __init__(self): self.a, self.b = 0, 1 # 初始化兩個計數(shù)器a拦英,b def __iter__(self): return self # 實例本身就是迭代對象蜒什,故返回自己 def __next__(self): self.a, self.b = self.b, self.a + self.b # 計算下一個值 if self.a > 100000: # 退出循環(huán)的條件 raise StopIteration(); return self.a # 返回下一個值
-
__getitem__
: 按照下標(biāo)或切片取出元素# 重寫__getitem__ 支持索引和切片 class Fib(object): def __getitem__(self, n): if isinstance(n, int): # n是索引 a, b = 1, 1 for x in range(n): a, b = b, a + b return a if isinstance(n, slice): # n是切片 start = n.start stop = n.stop if start is None: start = 0 a, b = 1, 1 L = [] for x in range(stop): if x >= start: L.append(a) a, b = b, a + b return L print(Fib()[9]) print(Fib()[:10])
-
__getattr__
: 動態(tài)返回一個屬性, 可以寫一個鏈?zhǔn)秸{(diào)用def __getattr__(self, path): return Chain('%s/%s' % (self._path, path))
-
__call__
: 直接在實例本身上調(diào)用, 通過callable()
函數(shù),可以判斷一個對象是否是“可調(diào)用”對象疤估。class Student(object): def __init__(self, name): self.name = name def __call__(self): print('My name is %s.' % self.name) s = Student('DreamYoung') if callable(s): s() # self參數(shù)不要傳入
-
-
枚舉類:
Enum
枚舉類灾常,把一組相關(guān)常量定義在一個class中,class不可變铃拇,成員可直接比較from enum import Enum, unique @unique # @unique裝飾器用于檢查有沒有重復(fù)值 class Weekday(Enum): Sun = 0 # Sun的value被設(shè)定為0 Mon = 1, 2 Tue = 2 print(Weekday.Sun) # Weekday.Sun print(Weekday.Sun.value) # 0 print(Weekday.Mon.value) # (1, 2) print(Weekday(2)) # Weekday.Tue print(Weekday['Tue']) # Weekday.Tue print(Weekday['Tue'].value) # 2
可見钞瀑,既可以用成員名稱引用枚舉常量,又可以直接根據(jù)value的值獲得枚舉常量
-
元類:Python的class的定義是運行時創(chuàng)建的慷荔,創(chuàng)建的方法就是使用
type()
函數(shù)雕什!type()
函數(shù)既可以返回一個對象的類型,又可以創(chuàng)建出新的類型显晶,無需使用class關(guān)鍵字贷岸。def fun(self, name='DreamYoung'): print('Hello, ' + name) Hello = type('Hello', (object,), dict(hello=fun)) # 創(chuàng)建Hello class h = Hello() h.hello()
type()
函數(shù)需要三個參數(shù):函數(shù)名稱,繼承的父類集合(tuple)磷雇,方法名綁定的函數(shù)偿警。
Python創(chuàng)建類也是掃一下class關(guān)鍵字,然后通過type創(chuàng)建出來類唯笙。
如果要控制類的行為螟蒸,可以使用元類?metaclass,可以把類理解為metaclass創(chuàng)建的實例崩掘。 先定義metaclass七嫌,就可以創(chuàng)建類,最后創(chuàng)建實例呢堰。metaclass暫時不會用到抄瑟,如果需要深入了解,可以參考這篇文章
錯誤、調(diào)試和測試
-
錯誤:Python內(nèi)置了
try...except...finally...
用于捕獲異常皮假,所有的異常都繼承自BaseException
, 查看異常繼承關(guān)系注意:
- except可以有多個鞋拟,多個except異常 父類會覆蓋子類的異常, except后可以跟else
- finally在最后執(zhí)行惹资,可以不寫
- 可以使用
logging
模塊記錄日志贺纲,通過查看調(diào)用堆棧,定位排查錯誤
寫法:
try: print(1/0) except ZeroDivisionError as e: logging.exception(e) else: print('else') finally: print('finally')
-
調(diào)試:要想調(diào)試起來爽褪测,要善于使用
logging
猴誊!logging
有debug、info侮措、warning懈叹、error幾個級別,通過:import logging logging.basicConfig(level=logging.INFO) # info級別日志分扎,debug日志不會顯示
指定當(dāng)前模塊的日志級別澄成,
logging
的好處是通過簡單的配置,日志可以輸出到文件等等 -
單元測試:編寫單元測試需要引入
unittest
模塊畏吓,并編寫一個從unittest.TestCase
繼承測試類墨状。
注意,測試方法必須以test
開頭(test_xxx()
)菲饼,否則在測試時不會被執(zhí)行肾砂。unittest
提供了很多內(nèi)置條件的判斷,比如:assertEqual()
宏悦、assertRaises()
等等 用于判斷輸出值是否是我們的期望值镐确。運行前與運行后:編寫兩個特殊的方法
setUp()
和tearDown()
,在每個單元測試方法執(zhí)行之前執(zhí)行setUp()
肛根,執(zhí)行之后執(zhí)行tearDown()
辫塌。這個用處大大的漏策,比如可以在setUp()
方法連接測試庫派哲,tearDown()
方法關(guān)閉連接。運行單元測試有兩種方法:
-
加上兩行代碼掺喻,這樣可以當(dāng)做正常的Python腳步運行:
if __name__ == '__main__': unittest.main()
-
(薦)通過命令行參數(shù)直接運行單元測試 :可以批量執(zhí)行單元測試
$ python3 -m unittest my_test1.py my_test2.py
-
-
文檔測試:Python的很多官方文檔都是示例代碼芭届,通過
doctest
模塊,可以提前并執(zhí)行文檔注釋代碼感耙。
比如就絕對值的函數(shù)abs()
寫上這樣的注釋:def abs(n): """ Function to get absolute value of number. Example: >>> abs('') Traceback (most recent call last): ... TypeError: unorderable types: str() >= int() >>> abs(1) 1 >>> abs(-1) 1 >>> abs(0) 0 """ return n if n >= 0 else (-n + 1) # 正確的代碼應(yīng)為: return n if n >= 0 else (-n) if __name__ == '__main__': import doctest doctest.testmod()
會得到以下輸出:
File "xxxx/demo/dream/young/python/Test.py", line 13, in main.abs
Failed example:
abs(-1)
Expected:
1
Got:
2
1 items had failures:
1 of 4 in main.abs
Test Failed 1 failures.
如果沒有輸出任何信息褂乍,說明注釋代碼沒有錯誤。注意:當(dāng)模塊正常導(dǎo)入時即硼,doctest不會被執(zhí)行逃片。只有在命令行直接運行時,才執(zhí)行doctest只酥。所以褥实,不必?fù)?dān)心doctest會在非測試環(huán)境下執(zhí)行呀狼。