好久沒更新了呀,Python的學(xué)習(xí)可不能落下!??
面向?qū)ο缶幊?/h2>
面向?qū)ο笤O(shè)計(jì)思想:抽象出類(Class),根據(jù)類創(chuàng)建實(shí)例(Instance)。
面向?qū)ο蟮娜筇攸c(diǎn):封裝,繼承,多態(tài)。
-
類和實(shí)例:
- 類的定義:
class Student(object): passStudent類繼承了object - 創(chuàng)建實(shí)例:
yzl = Student(), 創(chuàng)建實(shí)例后,可以自由的給實(shí)例綁定屬性yzl.age = 18, 僅對(duì)本實(shí)例有效 - 類的方法定義:
def __init__(self, name, age):, 第一個(gè)變量必須是self, 但不用傳,表示此實(shí)例變量。
- 類的定義:
-
訪問限制:以
__開頭的是私有變量,外部訪問不到(但其實(shí)可以訪問到,只是Python解釋器把私有變量換了個(gè)名字,比如_Student__name),以_開頭的雖然可以訪問,但也要當(dāng)做私有變量,不要輕易訪問??傊?,Python本身沒有任何機(jī)制阻止你干壞事,一切全靠自覺。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):對(duì)于靜態(tài)語言,比如Java,一個(gè)函數(shù)的入?yún)㈩愋捅仨毷谴_定的,而對(duì)于動(dòng)態(tài)語言,只要file-like object即可. 鴨子類型:一個(gè)對(duì)象只要“看起來像鴨子,走起路來像鴨子”,那它就可以被看做是鴨子。
只要whatever有run()方法就可以。def run_twice(whatever): whatever.run() -
獲取對(duì)象信息:
-
type()判斷對(duì)象類型type(123): <class 'int'> -
isinstance()判斷一個(gè)對(duì)象是否是某種類型isinstance('abc', str): True -
dir()獲取一個(gè)對(duì)象的所有屬性和方法,它返回一個(gè)包含字符串的list -
hasattr(obj, 'x')獲取屬性setattr(obj, 'y', 19)設(shè)置屬性,注意:只有在不知道對(duì)象信息的時(shí)候,我們才會(huì)去獲取對(duì)象信息
-
實(shí)例屬性和類屬性:不通過
__init__()構(gòu)造,直接在class里定義屬性的是類屬性。實(shí)例屬性和類屬性名字不要一樣,否則類屬性在當(dāng)前實(shí)例會(huì)被覆蓋掉。限制實(shí)例的屬性:
__slots__ = ('name', 'age'), 定義一個(gè)__slots__限制類的實(shí)例屬性只能在tuple里,否則將報(bào)AttributeError錯(cuò)誤,注意:__slots__只作用于當(dāng)前類實(shí)例,對(duì)子類不起作用,若子類也定義了slots,則還要加上父類的slots。-
@property : 相當(dāng)于 getter,@name.setter : 相當(dāng)于 setter,這兩個(gè)decorator的目的是讓方法變?yōu)閷傩?調(diào)用方法生成了屬性),可以寫出更簡短的代碼,同時(shí)保證對(duì)參數(shù)進(jìn)行必要性的檢查。
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__: 自定義打印實(shí)例,變量調(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__: 返回一個(gè)迭代對(duì)象,通過__next()__方法循環(huán)獲取下一個(gè)值,知道遇到StopIteration錯(cuò)誤時(shí)推出循環(huán)class Fib(object): def __init__(self): self.a, self.b = 0, 1 # 初始化兩個(gè)計(jì)數(shù)器a,b def __iter__(self): return self # 實(shí)例本身就是迭代對(duì)象,故返回自己 def __next__(self): self.a, self.b = self.b, self.a + self.b # 計(jì)算下一個(gè)值 if self.a > 100000: # 退出循環(huán)的條件 raise StopIteration(); return self.a # 返回下一個(gè)值 -
__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__: 動(dòng)態(tài)返回一個(gè)屬性, 可以寫一個(gè)鏈?zhǔn)秸{(diào)用def __getattr__(self, path): return Chain('%s/%s' % (self._path, path)) -
__call__: 直接在實(shí)例本身上調(diào)用, 通過callable()函數(shù),可以判斷一個(gè)對(duì)象是否是“可調(diào)用”對(duì)象。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)常量定義在一個(gè)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的定義是運(yùn)行時(shí)創(chuàng)建的,創(chuàng)建的方法就是使用
type()函數(shù)!type()函數(shù)既可以返回一個(gè)對(duì)象的類型,又可以創(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ù)需要三個(gè)參數(shù):函數(shù)名稱,繼承的父類集合(tuple),方法名綁定的函數(shù)。
Python創(chuàng)建類也是掃一下class關(guān)鍵字,然后通過type創(chuàng)建出來類。
如果要控制類的行為,可以使用元類?metaclass,可以把類理解為metaclass創(chuàng)建的實(shí)例。 先定義metaclass,就可以創(chuàng)建類,最后創(chuàng)建實(shí)例。metaclass暫時(shí)不會(huì)用到,如果需要深入了解,可以參考這篇文章
錯(cuò)誤、調(diào)試和測(cè)試
-
錯(cuò)誤:Python內(nèi)置了
try...except...finally...用于捕獲異常,所有的異常都繼承自BaseException, 查看異常繼承關(guān)系注意:
- except可以有多個(gè),多個(gè)except異常 父類會(huì)覆蓋子類的異常, except后可以跟else
- finally在最后執(zhí)行,可以不寫
- 可以使用
logging模塊記錄日志,通過查看調(diào)用堆棧,定位排查錯(cuò)誤
寫法:
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幾個(gè)級(jí)別,通過:import logging logging.basicConfig(level=logging.INFO) # info級(jí)別日志,debug日志不會(huì)顯示指定當(dāng)前模塊的日志級(jí)別,
logging的好處是通過簡單的配置,日志可以輸出到文件等等 -
單元測(cè)試:編寫單元測(cè)試需要引入
unittest模塊,并編寫一個(gè)從unittest.TestCase繼承測(cè)試類。
注意,測(cè)試方法必須以test開頭(test_xxx()),否則在測(cè)試時(shí)不會(huì)被執(zhí)行。unittest提供了很多內(nèi)置條件的判斷,比如:assertEqual()、assertRaises()等等 用于判斷輸出值是否是我們的期望值。運(yùn)行前與運(yùn)行后:編寫兩個(gè)特殊的方法
setUp()和tearDown(),在每個(gè)單元測(cè)試方法執(zhí)行之前執(zhí)行setUp(),執(zhí)行之后執(zhí)行tearDown()。這個(gè)用處大大的,比如可以在setUp()方法連接測(cè)試庫,tearDown()方法關(guān)閉連接。運(yùn)行單元測(cè)試有兩種方法:
-
加上兩行代碼,這樣可以當(dāng)做正常的Python腳步運(yùn)行:
if __name__ == '__main__': unittest.main() -
(薦)通過命令行參數(shù)直接運(yùn)行單元測(cè)試 :可以批量執(zhí)行單元測(cè)試
$ python3 -m unittest my_test1.py my_test2.py
-
-
文檔測(cè)試:Python的很多官方文檔都是示例代碼,通過
doctest模塊,可以提前并執(zhí)行文檔注釋代碼。
比如就絕對(duì)值的函數(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()會(huì)得到以下輸出:
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.
如果沒有輸出任何信息,說明注釋代碼沒有錯(cuò)誤。注意:當(dāng)模塊正常導(dǎo)入時(shí),doctest不會(huì)被執(zhí)行。只有在命令行直接運(yùn)行時(shí),才執(zhí)行doctest。所以,不必?fù)?dān)心doctest會(huì)在非測(cè)試環(huán)境下執(zhí)行。