Python語(yǔ)言特點(diǎn):
1.易于學(xué)習(xí):Python有相對(duì)較少的關(guān)鍵字,結(jié)構(gòu)簡(jiǎn)單,和一個(gè)明確定義的語(yǔ)法,學(xué)習(xí)起來(lái)更加簡(jiǎn)單。
2.易于閱讀:Python代碼定義的更清晰。
3.易于維護(hù):Python的成功在于它的源代碼是相當(dāng)容易維護(hù)的。
4.一個(gè)廣泛的標(biāo)準(zhǔn)庫(kù):Python的最大的優(yōu)勢(shì)之一是豐富的庫(kù),跨平臺(tái)的,在UNIX,Windows和Macintosh兼容很好。
5.互動(dòng)模式:互動(dòng)模式的支持,您可以從終端輸入執(zhí)行代碼并獲得結(jié)果的語(yǔ)言,互動(dòng)的測(cè)試和調(diào)試代碼片斷。
6.可移植:基于其開(kāi)放源代碼的特性,Python已經(jīng)被移植(也就是使其工作)到許多平臺(tái)。
7.可擴(kuò)展:如果你需要一段運(yùn)行很快的關(guān)鍵代碼,或者是想要編寫(xiě)一些不愿開(kāi)放的算法,你可以使用C或C++完成那部分程序,然后從你的Python程序中調(diào)用。
8.數(shù)據(jù)庫(kù):Python提供所有主要的商業(yè)數(shù)據(jù)庫(kù)的接口。
9.GUI編程:Python支持GUI可以創(chuàng)建和移植到許多系統(tǒng)調(diào)用。
10.可嵌入: 你可以將Python嵌入到C/C++程序,讓你的程序的用戶獲得'腳本化'的能力。
下載地址:https://www.python.org/
懶人模式,安裝提示里勾選上自動(dòng)配置環(huán)境變量,pip等,安裝完成后,你連環(huán)境變量都不用配置了。
但是學(xué)習(xí)的人還是要謙虛一點(diǎn),配環(huán)境變量也是基本功。
“Python.exe” 所在的文件夾C:\Python\Python36-32加入的環(huán)境變量的Path下面就好了
配置完成后cmd終端里檢查一下,如下圖沒(méi)有保錯(cuò),說(shuō)明配置正確。
對(duì)縮進(jìn)要求嚴(yán)格,四個(gè)空格,不建議用Tab,不同平臺(tái)上縮進(jìn)不一樣
我使用的IDE為Pycharm,注釋為ctrl + /
官方文檔 http://docs.python.org/2/
中文文檔 http://python.usyiyi.cn/
http://www.pythondoc.com/
一張圖概況Python學(xué)習(xí)(轉(zhuǎn)自W3Cschool)
目錄:
Python基礎(chǔ)語(yǔ)法:
(1)打印出hello world
(2)注釋
(3)數(shù)據(jù)類(lèi)型
(4)運(yùn)算
(5)輸入
(6)輸出
(7)序列
(8)相等比較
(9)選擇
(10)循環(huán)
(11)字典(dict)
(12)集合(set)(不常用)
(14)pass,del,exec,eval
(15)內(nèi)建函數(shù)
Python進(jìn)階語(yǔ)法:
(1)文件
(2)錯(cuò)誤和異常
(3)模塊和包
(4)作用域
(5)高階函數(shù)
(6)裝飾器
(7)參數(shù)
(8)面向?qū)ο?/p>
(9)定制類(lèi)(魔術(shù)方法)
(10)日期和時(shí)間
(11)數(shù)學(xué)與隨機(jī)數(shù)
(12)正則表達(dá)式
Python基礎(chǔ)語(yǔ)法:
(1)打印出hello world
# -*- coding: utf-8 -*- print 'hello world' print '你好 世界'
(2)注釋
1、(單行注釋?zhuān)┮?# 開(kāi)頭,后面的文字直到行尾都算注釋
2、(多行注釋?zhuān)┒嘈凶⑨屖怯萌?hào)''' '''包含的(單引號(hào)和雙引號(hào)均可)
3、(中文注釋?zhuān)┮⑨屩形谋仨毘绦蜷_(kāi)頭先寫(xiě)上# -*- coding: utf-8 -*-,不然會(huì)報(bào)錯(cuò)
(3)數(shù)據(jù)類(lèi)型
1、變量不需要聲明,可以直接輸入,大小寫(xiě)敏感
2、這里的var = xxxx不叫變量賦值,而叫變量綁定,一個(gè)符號(hào)可以綁定任意類(lèi)型的值。
3、內(nèi)置函數(shù)type(), 用以查詢變量的類(lèi)型
print var #1
print type(var) #整數(shù)類(lèi)型 # <type 'int'>
var = 1.1
print var # 1.1
print type(var) #浮點(diǎn)數(shù)類(lèi)型 # <type 'float'>
var = 'hello'
print var # hello
print type(var) #字符串 # <type 'str'>
var = (1==1)
print var # True
print type(var) #布爾型 # <type 'bool'>
var = None
print var # None
print type(var) #空值 # <type 'NoneType'>
var = 1+1j 或者complex(a,b)表示, 復(fù)數(shù)的實(shí)部a和虛部b都是浮點(diǎn)型
print var # (1+1j)
print type(var) #復(fù)數(shù)類(lèi)型 # <type 'complex'>
4、字符串以''或' '括起來(lái)的任意文本
5、布爾型(True, False,可以用and, or, not運(yùn)算,而不是C語(yǔ)言的&&和||)
6、多變量賦值
a = b = c = 1 a, b, c = 1, 2, 'john' #等號(hào)兩邊都是元組,建議加上括號(hào),增加可讀性 x,y = y,x #兩值交換,不需要temp,更加簡(jiǎn)潔
7、賦值語(yǔ)句不可以返回值,對(duì)象是通過(guò)引用傳遞的
(4)運(yùn)算
1、加、減、乘、除、求余、乘方
2、乘方 ** 右結(jié)合
2**3=8 2**2**3=256 (2**2)**3=64
3、整數(shù)運(yùn)算結(jié)果仍然是整數(shù),浮點(diǎn)數(shù)運(yùn)算結(jié)果仍然是浮點(diǎn)數(shù)。
但是整數(shù)和浮點(diǎn)數(shù)混合運(yùn)算的結(jié)果就變成浮點(diǎn)數(shù)了。
4、字符串與整數(shù)相乘
5、因?yàn)镻ython把0、空字符串''和None看成 False,其他數(shù)值和非空字符串都看成 True
True and 'a=T' 計(jì)算結(jié)果是 'a=T'
繼續(xù)計(jì)算 'a=T' or 'a=F' 計(jì)算結(jié)果還是 'a=T'
要解釋上述結(jié)果,又涉及到 and 和 or 運(yùn)算的一條重要法則:短路計(jì)算。
①在計(jì)算 a and b 時(shí),如果 a 是 False,則根據(jù)與運(yùn)算法則,整個(gè)結(jié)果必定為 False,因此返回 a;如果 a 是 True,則整個(gè)計(jì)算結(jié)果必定取決與 b,因此返回 b。
②在計(jì)算 a or b 時(shí),如果 a 是 True,則根據(jù)或運(yùn)算法則,整個(gè)計(jì)算結(jié)果必定為 True,因此返回 a;如果 a 是 False,則整個(gè)計(jì)算結(jié)果必定取決于 b,因此返回 b。
所以Python解釋器在做布爾運(yùn)算時(shí),只要能提前確定計(jì)算結(jié)果,它就不會(huì)往后算了,直接返回結(jié)果。
6、不支持自加(i++)和自減(i--)
7、地板除(//)除法不管操作數(shù)何種數(shù)值類(lèi)型,總是舍去小數(shù)部分,返回?cái)?shù)字序列中比真正的商小的最接近的數(shù)字。
print 5//3 #1 print 1.0//2.0 #0.0 print -1/2 #-1
(5)輸入
print type(x) #<type 'int'>
y = raw_input() #1+2
print type(y) # <type 'str'>
1、由此可見(jiàn), input() 在對(duì)待純數(shù)字輸入返回所輸入的數(shù)字的類(lèi)型(int,float)
而raw_input() 將所有輸入作為字符串看待,返回字符串類(lèi)型。
為了避免類(lèi)型發(fā)生錯(cuò)誤,一般情況下使用 raw_input() 來(lái)與用戶交互。
(6)輸出
1、Python2 里面print可以直接接字符串或者運(yùn)算。
2、Python3 里面print變成了一個(gè)函數(shù),上面的寫(xiě)法不支持了,必須用一個(gè)括號(hào)括起來(lái),否則會(huì)報(bào)告語(yǔ)法錯(cuò)誤。
3、>>>是Python解釋器的提示符,不是代碼的一部分。
4、print語(yǔ)句也可以跟上多個(gè)字符串,用逗號(hào)“,”隔開(kāi),遇到逗號(hào)“,”會(huì)輸出一個(gè)空格:
print '1+2=',1+2 #1+2= 3
5、多行輸出使用三個(gè)引號(hào)和使用換行符\n一致
哈
哈'''
print '哈\n哈\n哈'
# 輸出結(jié)果
# 哈
# 哈
# 哈
# 哈
# 哈
# 哈
6、轉(zhuǎn)義
print r'C:\log.txt' print 'C:\\log.txt' # C:\log.txt # C:\log.txt
7、print 語(yǔ)句與字符串格式運(yùn)算符( % )結(jié)合使用,可實(shí)現(xiàn)字符串替換功能
%s表示由一個(gè)字符串來(lái)替換,%d表示由一個(gè)整數(shù)來(lái)替換,%f表示由一個(gè)浮點(diǎn)數(shù)來(lái)替換。
Python 非常靈活,即使將數(shù)字傳遞給 %s,也不會(huì)像其他要求嚴(yán)格的語(yǔ)言一樣引發(fā)嚴(yán)重后果。
(7)序列
1、序列有兩種: list (可變列表) 和tuple(不可變?cè)M)
2、定義:序列是一組有順序的元素的集合,可以包含一個(gè)或多個(gè)元素,也可以沒(méi)有任何元素。
list = [0,1,2,3,4,5] #列表用中括號(hào),可改變,理解為數(shù)組 tuple = (0,1,2,3,4,5) #元祖用小括號(hào),不可改變
由于Python是動(dòng)態(tài)語(yǔ)言,所以list中包含的元素并不要求都必須是同一種數(shù)據(jù)類(lèi)型
2、序列的通用操作
print seq[0] #序列元素的下標(biāo)從0開(kāi)始。注意不要越界
print seq[-1] #倒序索引,-1代表倒數(shù)第一。
print seq[1:5] #支持切片操作,seq[start:end],start包含在結(jié)果中,end不包含在結(jié)果中。
print range(1,101)[0:10]#從第1個(gè)數(shù)元素開(kāi)始取,到第11元素結(jié)束
print seq[7:] #seq[start:end]中的end可以省略。
print seq[-3:] #分片也支持負(fù)數(shù)。
print seq[:3] #seq[start:end]中的start也可以省略。
print seq[:] #全部省略會(huì)復(fù)制整個(gè)序列。
print seq[::2] #支持步長(zhǎng)。
print seq[::-1] #逆序輸出。
print seq[9:1:-1] #支持負(fù)步長(zhǎng)。
print range(1,101)[2::3]#從第三元素開(kāi)始取,每隔2個(gè)取一個(gè)元素,即3的倍數(shù)
print range(1,101)[4:50:5]#從第五個(gè)取,每隔4個(gè)取一個(gè),50以內(nèi)5的倍數(shù)
print [1, 2, 3] + [4, 5, 6] # 序列支持相加,這解釋了為啥字符串可以相加。
print [1, 2, 3] * 3 #序列支持相乘,這解釋了為啥字符串可以相稱(chēng)。
print [None] * 10 #生成一個(gè)空序列。
print 1 in [1, 2, 3] #成員判斷。
print range(1,101)[4::5][-10:] #切片可以嵌套,最后10個(gè)5的倍數(shù),先獲得5的倍數(shù)再取后10個(gè)
記住倒數(shù)第一個(gè)元素的索引是-1。倒序切片包含起始索引,不包含結(jié)束索引。
3、可變的列表(list)
list = [0,1,2,3,4,5] list.append(7) #append()總是把新元素添加到list的尾部 print list # [0, 1, 2, 3, 4, 5, 7] list.insert(0,-1) #insert()接受兩個(gè)參數(shù),第一個(gè)是索引,第二個(gè)是元素 print list # [-1, 0, 1, 2, 3, 4, 5, 7] list.insert(-1,6) #insert(-1)是最后一個(gè)元素之前,即倒數(shù)第二個(gè)元素,因?yàn)閕nsert()前插 print list # [-1, 0, 1, 2, 3, 4, 5, 6, 7] list.pop() #pop()方法總是刪掉最后一個(gè)元素 print list # [-1, 0, 1, 2, 3, 4, 5, 6] list.pop(0) #參數(shù)為索引 print list # [0, 1, 2, 3, 4, 5, 6] list[6]=7 #對(duì)list中的某一個(gè)索引賦值,就可以直接用新的元素替換掉原來(lái)的元素 print list # [0, 1, 2, 3, 4, 5, 7] list[0],list[-1]=list[-1],list[0] #第一與最后位置調(diào)換 print list # [7, 1, 2, 3, 4, 5, 0]
在使用可變對(duì)象的方法如 sort(),extend()和 reverse()的時(shí)候要注意,這些操作會(huì)在列表
中原地執(zhí)行操作,也就是說(shuō)現(xiàn)有的列表內(nèi)容會(huì)被改變,但是沒(méi)有返回值!
4、不可變的元組(tuple)
字符串是一種特殊的元組
沒(méi)有 append()方法,也沒(méi)有insert()和pop()方法,也不能賦值
Tuple 比 list 操作速度快.如果您定義了一個(gè)值的常量集,并且唯一要用它做的是不斷地遍歷它,請(qǐng)使用 tuple 代替 list.如月份,星期。
print (1,) #一個(gè)元素的元祖。
因?yàn)?)既可以表示tuple,又可以作為括號(hào)表示運(yùn)算時(shí)的優(yōu)先級(jí),結(jié)果 (1) 被Python解釋器計(jì)算出結(jié)果 1,導(dǎo)致我們得到的不是tuple,而是整數(shù) 1。正是因?yàn)橛?)定義單元素的tuple有歧義,所以 Python 規(guī)定,單元素 tuple 要多加一個(gè)逗號(hào)“,”,這樣就避免了歧義。
可變的元組:tuple的元素指向list,而list內(nèi)的值可變
5、序列解包
print x, y, z
(x, y, z) = (1, 2, 3)
print x, y, z
(x, y, z) = [1, 2, 3]
print x, y, z
(8)相等比較
#== 和 is的差別,==比較的是值,is比較的是引用。 x = [1, 2, 3] y = x z = [1, 2, 3] print(x == y) #True print(x == z) #True print(x is y) #True print(x is z) #False
(9)選擇
1、Python代碼的縮進(jìn)規(guī)則。具有相同縮進(jìn)的代碼被視為代碼塊
2、縮進(jìn)請(qǐng)嚴(yán)格按照Python的習(xí)慣寫(xiě)法:4個(gè)空格,不要使用Tab,更不要混合Tab和空格
3、格式
statement
elif 條件2:
statement
elif 條件3:
statement
else:
statement
If后面不需要括號(hào),但是條件后面需要冒號(hào)
elif 即 else if
4、三元運(yùn)算符
x, y = 4, 3 if x < y: result = x else: result = y print result #等價(jià)于 result = x if x < y else y print result
(10)循環(huán)
1、for循環(huán)依次把list或tuple的每個(gè)元素迭代出來(lái)
格式
statement
name 這個(gè)變量是在 for 循環(huán)中定義的,意思是,依次取出list中的每一個(gè)元素,并把元素賦值給 name,然后執(zhí)行for循環(huán)體(就是縮進(jìn)的代碼塊)
L = ['Adam', 'Lisa', 'Bart'] for name in L: print name
這樣一來(lái),遍歷一個(gè)list或tuple就非常容易了。
2、while循環(huán),不會(huì)迭代 list 或 tuple 的元素,而是根據(jù)表達(dá)式判斷循環(huán)是否結(jié)束。
statement
3、中斷循環(huán) break和continue
4、range()的用法
range(1,5) #代表從1到5(不包含5) [1, 2, 3, 4] range(1,5,2) #代表從1到5,間隔2(不包含5) [1, 3] range(5) #代表從0到5(不包含5) [0, 1, 2, 3, 4]
5、Python中,迭代永遠(yuǎn)是取出元素本身,而非元素的索引。
對(duì)于有序集合,元素確實(shí)是有索引的。使用enumerate() 函數(shù)拿到索引
for index, name in enumerate(L):
print index, '-', name
#結(jié)果
# 0 - Adam
# 1 - Lisa
# 2 - Bart
# 3 - Paul
使用 enumerate() 函數(shù),我們可以在for循環(huán)中同時(shí)綁定索引index和元素name。但是,這不是 enumerate() 的特殊語(yǔ)法。實(shí)際上,enumerate() 函數(shù)把:
['Adam', 'Lisa', 'Bart', 'Paul']
變成了類(lèi)似:
[(0, 'Adam'), (1, 'Lisa'), (2, 'Bart'), (3, 'Paul')]
因此,迭代的每一個(gè)元素實(shí)際上是一個(gè)tuple:
6、好用的zip()方法
for x, y in zip(range(1, 10), range(1, 10)): print(x, y) # 結(jié)果 # (1, 1) # (2, 2) # (3, 3) # (4, 4) # (5, 5) # (6, 6) # (7, 7) # (8, 8) # (9, 9)
7、列表生成式,非常簡(jiǎn)潔
要生成[1x1, 2x2, 3x3, ..., 10x10]
#[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
列表生成式的 for 循環(huán)后面還可以加上 if 判斷。例如:
print [x * x for x in range(1, 11) if x % 2 == 0] # [4, 16, 36, 64, 100]
8、迭代器
它為類(lèi)序列對(duì)象提供了一個(gè)類(lèi)序列的接口。
迭代非序列集合(例如映射和文件)時(shí), 可以創(chuàng)建更簡(jiǎn)潔可讀的代碼。
i = iter(myTuple)
print i.next() #123
print i.next() #xyz
print i.next() #45.67
i.next() #報(bào)錯(cuò)
(11)字典(dict)
1、字典的元素沒(méi)有順序。你不能通過(guò)下標(biāo)引用元素。字典是通過(guò)鍵來(lái)引用,用大括號(hào)
查找速度快,無(wú)論dict有10個(gè)元素還是10萬(wàn)個(gè)元素,查找速度都一樣。而list的查找速度隨著元素增加而逐漸下降。
dict的缺點(diǎn)是占用內(nèi)存大,還會(huì)浪費(fèi)很多內(nèi)容
dict是按 key 查找,所以,在一個(gè)dict中,key不能重復(fù)
作為 key 的元素必須不可變
2、已知兩個(gè)列表,一個(gè)是名字,一個(gè)是成績(jī),要根據(jù)名字找到對(duì)應(yīng)的成績(jī)用兩個(gè)list不方便,如果把名字和分?jǐn)?shù)關(guān)聯(lián)起來(lái),組成類(lèi)似的查找表,即 Python中的dict
用 dict 表示“名字”-“成績(jī)”的查找表如下:
dic = {'tom':11, 'sam':57,'lily':100} print type(dic) #<type 'dict'> d = { 'Adam': 95, 'Lisa': 85, 'Bart': 59 } print d #{'Lisa': 85, 'Adam': 95, 'Bart': 59}
3、我們把名字稱(chēng)為key,對(duì)應(yīng)的成績(jī)稱(chēng)為value,dict就是通過(guò) key 來(lái)查找 value。
4、花括號(hào) {} 表示這是一個(gè)dict,然后按照 key: value, 寫(xiě)出來(lái)即可。最后一個(gè) key: value 的逗號(hào)可以省略。
5、由于dict也是集合,len()函數(shù)可以計(jì)算任意集合的大小:
print len(d) #運(yùn)算結(jié)果為3
一個(gè) key-value 算一個(gè),因此,dict大小為3。
6、可以簡(jiǎn)單地使用 d[key] 的形式來(lái)查找對(duì)應(yīng)的 value,這和 list 很像,不同之處是,list 必須使用索引返回對(duì)應(yīng)的元素,而dict使用key:
注意: 通過(guò) key 訪問(wèn) dict 的value,只要 key 存在,dict就返回對(duì)應(yīng)的value。如果key不存在,會(huì)直接報(bào)錯(cuò):KeyError。
要避免 KeyError 發(fā)生,有兩個(gè)辦法:
一是先判斷一下 key 是否存在,用 in 操作符:
二是使用dict本身提供的一個(gè) get 方法,在Key不存在的時(shí)候,返回None:
print d.get('Bart') #59 print d.get('Paul') #None
7、在字典中增添一個(gè)新元素的方法:
'Adam': 95,
'Lisa': 85,
'Bart': 59
}
print d #{'Lisa': 85, 'Adam': 95, 'Bart': 59}
d['lilei'] = 99
print d #{'lilei': 99, 'Lisa': 85, 'Adam': 95, 'Bart': 59}
8、循環(huán)調(diào)用
for key in d: #或for key in d.keys() print d[key] # 結(jié)果 # 99 # 85 # 95 # 59
9、字典的常用方法
print d.values() # 返回d所有的值
print d.items() # 返回d所有的元素(鍵值對(duì))
d.clear() # 清空d,dict變?yōu)閧}
del d['xxx’] # 刪除 d 的'xxx’元素
for key, value in d.items():
print key, ':', value
10、cmp()比較
(1)先比較字典長(zhǎng)度
(2)再比較字典的鍵
(3)最后比較字典的值
(4)都一樣就相等
(12)集合(set)(不常用)
1、dict的作用是建立一組 key 和一組 value 的映射關(guān)系,dict的key是不能重復(fù)的。
有的時(shí)候,我們只想要 dict 的 key,不關(guān)心 key 對(duì)應(yīng)的 value,目的就是保證這個(gè)集合的元素不會(huì)重復(fù),這時(shí),set就派上用場(chǎng)了。
2、set 持有一系列元素,這一點(diǎn)和 list 很像,但是set的元素沒(méi)有重復(fù),而且是無(wú)序的,這點(diǎn)和 dict 的 key很像。
3、創(chuàng)建 set 的方式是調(diào)用 set() 并傳入一個(gè) list,list的元素將作為set的元素:
s = set(['A', 'B', 'C']) print s #set(['A', 'C', 'B'])
4、添加、刪除
print s #set(['A', 'C', 'B', 'D'])
s.add('D') #已存在不會(huì)報(bào)錯(cuò)
s.remove('D')
print s #set(['A', 'C', 'B'])
s.remove('D') #報(bào)錯(cuò),需要先判斷
(13)函數(shù)
1、定義一個(gè)函數(shù)要使用 def 語(yǔ)句,依次寫(xiě)出函數(shù)名、括號(hào)、括號(hào)中的參數(shù)和冒號(hào):,然后,在縮進(jìn)塊中編寫(xiě)函數(shù)體,函數(shù)的返回值用 return 語(yǔ)句返回。
def say_b(): print 'b' say_b() #調(diào)用函數(shù),打印出b
2、如果沒(méi)有return語(yǔ)句,函數(shù)執(zhí)行完畢后也會(huì)返回結(jié)果,只是結(jié)果為 None。
3、函數(shù)返回多個(gè)值
def move(x, y, step, angle):
nx = x + step * math.cos(angle)
ny = y - step * math.sin(angle)
return nx, ny
x, y = move(100, 100, 60, math.pi / 6)
print x, y #151.961524227 70.0
r = move(100, 100, 60, math.pi / 6)
print r #(151.96152422706632, 70.0)
其實(shí)這只是一種假象,Python函數(shù)返回的仍然是單一值,是一個(gè)tuple:
但是,在語(yǔ)法上,返回一個(gè)tuple可以省略括號(hào),而多個(gè)變量可以同時(shí)接收一個(gè)tuple,按位置賦給對(duì)應(yīng)的值,所以,Python的函數(shù)返回多值其實(shí)就是返回一個(gè)tuple,但寫(xiě)起來(lái)更方便。
4、在函數(shù)內(nèi)部,可以調(diào)用其他函數(shù)。如果一個(gè)函數(shù)在內(nèi)部調(diào)用自身本身,這個(gè)函數(shù)就是遞歸函數(shù)。
def fact(n): if n==1: return 1 return n * fact(n - 1) print fact(10) #計(jì)算10的階乘
5、定義函數(shù)的時(shí)候,還可以有默認(rèn)參數(shù)。
s = 1
while n > 0:
n = n - 1
s = s * x
return s
print power(2) #默認(rèn)計(jì)算2的平方
print power(2,3) #計(jì)算2的三次方
由于函數(shù)的參數(shù)按從左到右的順序匹配,所以默認(rèn)參數(shù)只能定義在必需參數(shù)的后面:
6、一個(gè)函數(shù)能接受任意個(gè)參數(shù),我們就可以定義一個(gè)可變參數(shù):
def fn(*args): print args fn('a') #('a',) fn('a', 'b') #('a', 'b') fn('a', 'b', 'c') #('a', 'b', 'c')
可變參數(shù)的名字前面有個(gè) * 號(hào),我們可以傳入0個(gè)、1個(gè)或多個(gè)參數(shù)給可變參數(shù):
7、基本數(shù)據(jù)類(lèi)型的參數(shù):值傳遞
表作為參數(shù):指針傳遞
(14)pass,del,exec,eval
1、pass語(yǔ)句
pass代表該語(yǔ)句什么都不做,因?yàn)閜ython中空代碼是非法的,比如一個(gè)if語(yǔ)句要求什么內(nèi)容都不做,我們就可以使用pass語(yǔ)句。
2、del語(yǔ)句
一般來(lái)說(shuō)python會(huì)刪除那些不在使用的對(duì)象(因?yàn)槭褂谜卟粫?huì)再通過(guò)任何變量或者數(shù)據(jù)結(jié)構(gòu)引用它們)
3、exec語(yǔ)句(運(yùn)行字符串中的程序)
4、eval函數(shù)(會(huì)計(jì)算python表達(dá)式(以字符串形式書(shū)寫(xiě)),并且返回結(jié)果)
print eval('2+ 2') #4 print eval(raw_input('please input number:')) #輸入2+2 得4
(15)內(nèi)建函數(shù)
1、cmp(obj1, obj2) 比較 obj1 和 obj2, 根據(jù)比較結(jié)果返回整數(shù) i:
if obj1 > obj2 返回i > 0
if obj1 == obj2 返回i == 0
如果是用戶自定義對(duì)象, cmp()會(huì)調(diào)用該類(lèi)的特殊方法__cmp__()
2、str() 強(qiáng)制轉(zhuǎn)換成字符串
3、type() :詳見(jiàn)(3)數(shù)據(jù)類(lèi)型 - 3、
4、help():通過(guò)用函數(shù)名作為 help()的參數(shù)就能得到相應(yīng)的幫助信息
5、isinstance(變量名,類(lèi)型): 判斷是否是這個(gè)類(lèi)型的元素,可以用if語(yǔ)句
6、abs():取絕對(duì)值
7、enumerate():詳見(jiàn)(10)循環(huán) - 5、
8、len(seq):返回seq的長(zhǎng)度
9、sorted(iter):排序,會(huì)調(diào)用cmp()
10、zip(a1,a2……):詳見(jiàn)(10)循環(huán) - 6、
11、range():詳見(jiàn)(10)循環(huán) - 4、
12、string.lower():轉(zhuǎn)換字符串中所有大寫(xiě)字符為小寫(xiě)
13、string.upper():轉(zhuǎn)換字符串中所有小寫(xiě)字符為大寫(xiě)
14、string.strip():刪去字符串開(kāi)頭和結(jié)尾的空格
15、string.capitalize():把字符串第一個(gè)字符大寫(xiě)
16、string.title():所有單詞都以大寫(xiě)開(kāi)頭
17、max()和min():找出最大和最小值
18、sum():求和
19、reversed():倒序輸出
Python進(jìn)階語(yǔ)法:
(1)文件
1、文件也是一個(gè)對(duì)象。
2、打開(kāi)文件
f = open(文件名,模式)
文件名可以是相對(duì)路徑或者絕對(duì)路徑
模式有:'r' 只讀、“w” 寫(xiě)入、“a” 追加,“r+/w+”讀寫(xiě)
使用 'r' 或 'U' 模式打開(kāi)的文件必須是已經(jīng)存在的。 使用 'w' 模式打開(kāi)的文件若存在則首先清空, 然后(重新)創(chuàng)建。 以 'a' 模式打開(kāi)的文件是為追加數(shù)據(jù)作準(zhǔn)備的, 所有寫(xiě)入的數(shù)據(jù)都將追加到文件的末尾。 即使你 seek 到了其它的地方。 如果文件不存在, 將被自動(dòng)創(chuàng)建, 類(lèi)似以 'w'模式打開(kāi)文件。
test = open('test.txt', 'w')
3、屬性
print '文件名: ', test.name #文件名: test.txt
print '是否已關(guān)閉 : ', test.closed #是否已關(guān)閉 : False
print '訪問(wèn)模式 : ', test.mode #訪問(wèn)模式 : w
4、關(guān)閉 close()
test = open('test.txt', 'w') test.close() print '是否已關(guān)閉 : ', test.closed #是否已關(guān)閉 : True
5、寫(xiě)入write()
write()方法可將任何字符串寫(xiě)入一個(gè)打開(kāi)的文件。
write()方法不在字符串的結(jié)尾不添加換行符('\n'):
test.write('this is a test\n this is a test again \n')
test.close()
#可以在文件中看到
# this is a test
# this is a test again
主動(dòng)調(diào)用close()寫(xiě)緩存同步到磁盤(pán),或者寫(xiě)入數(shù)據(jù)量大于或等于寫(xiě)緩存,寫(xiě)緩存同步到磁盤(pán)
6、讀取 read()、readline()、readlines()
read(size)方法從一個(gè)打開(kāi)的文件中讀取一個(gè)字符串。size若不填則為盡量多的字符串,若填了則為結(jié)束位置。
readline()讀取當(dāng)前行,允許有參數(shù) readlines()讀取剩余行,返回一個(gè)字符串列表 test = open ('test.txt', 'w') test.write('python is a language \npython is a great language ') test.close() test = open('test.txt', 'r') str = test.read() print str test.close() #python is a language #python is a great language
7、文件位置
tell()方法告訴你文件內(nèi)的當(dāng)前位置;即下一次的讀寫(xiě)會(huì)發(fā)生在文件開(kāi)頭這么多字節(jié)之后:
seek(offset [,from])方法改變當(dāng)前文件的位置。Offset變量表示要移動(dòng)的字節(jié)數(shù)。From變量指定開(kāi)始移動(dòng)字節(jié)的參考位置。如果from被設(shè)為0,這意味著將文件的開(kāi)頭作為移動(dòng)字節(jié)的參考位置。如果設(shè)為1,則使用當(dāng)前的位置作為參考位置。如果它被設(shè)為2,那么該文件的末尾將作為參考位置。
test.write('python is a language \npython is a great language ')
test.close()
test = open('test.txt', 'r')
str = test.read()
print 'the first input:\n',str
#輸出
# the first input:
# python is a language
# python is a great language
# 查找當(dāng)前位置
position = test.tell()
print position
#50
# 把指針再次重新定位到文件開(kāi)頭
position = test.seek(0, 0)
str2 = test.read(10)
print 'the second input:\n', str2
# the second input:
# python is
test.close()
8、重命名
Python的os模塊提供了幫你執(zhí)行文件處理操作的方法,必須先導(dǎo)入它,才可以調(diào)用。
os.rename(當(dāng)前文件名,新的文件名)
9、刪除文件
同樣需要導(dǎo)入os模塊,才可以調(diào)用。
os.remove(文件名)
(2)錯(cuò)誤和異常
1、錯(cuò)誤類(lèi)型
OverflowError數(shù)值運(yùn)算超出最大限制
ZeroDivisionError 除(或取模)零 (所有數(shù)據(jù)類(lèi)型)
AttributeError對(duì)象沒(méi)有這個(gè)屬性
IOError 輸入/輸出操作失敗
IndexError 序列中沒(méi)有此索引(index)
NameError 未聲明/初始化對(duì)象 (沒(méi)有屬性)
SyntaxError Python 語(yǔ)法錯(cuò)誤
TypeError 對(duì)類(lèi)型無(wú)效的操作
ValueError 傳入無(wú)效的參數(shù)
2、try-except處理異常
try-except語(yǔ)句用來(lái)檢測(cè)try語(yǔ)句塊中的錯(cuò)誤,從而讓except語(yǔ)句捕獲異常信息并處理。
try: <語(yǔ)句> #運(yùn)行別的代碼 except Exception1,e:#Exception是錯(cuò)誤類(lèi)型名,e是儲(chǔ)存錯(cuò)誤,可以調(diào)用 <語(yǔ)句> #如果在try部份引發(fā)了'名字'異常 except Exception2,e: <語(yǔ)句> #如果引發(fā)了'名字'異常,獲得附加的數(shù)據(jù) else: <語(yǔ)句> #如果沒(méi)有異常發(fā)生
當(dāng)try后的語(yǔ)句執(zhí)行時(shí)發(fā)生異常,python就跳回到try并執(zhí)行第一個(gè)匹配該異常的except子句,異常處理完畢,控制流就通過(guò)整個(gè)try語(yǔ)句(除非在處理異常時(shí)又引發(fā)新的異常)。如果在try子句執(zhí)行時(shí)沒(méi)有發(fā)生異常,python將執(zhí)行else語(yǔ)句后的語(yǔ)句(如果有else的話),然后控制流通過(guò)整個(gè)try語(yǔ)句。
fh = open('testfile', 'w')
fh.write('This is my test file for exception handling!!')
except IOError:
print 'Error: can\'t find file or read data'
else:
print 'Written content in the file successfully' #Written content in the file successfully
try:
fh = open('testfile', 'r') #只讀文件不能寫(xiě)入
fh.write('This is my test file for exception handling!!')
except IOError,e:
print 'Error: can\'t find file or read data'
print 'catch error:',e
else:
print 'Written content in the file successfully'
#Error: can't find file or read data
#atch error: File not open for writing
except若不帶任何異常類(lèi)型,即捕獲所有發(fā)生的異常。但是不能捕獲語(yǔ)法錯(cuò)誤異常,如if a,因?yàn)槭沁\(yùn)行前錯(cuò)誤而不是運(yùn)行時(shí)錯(cuò)誤
也可帶多種類(lèi)型except(Exception1[, Exception2[,...ExceptionN]]]):
錯(cuò)誤類(lèi)型后面跟著變量e,可以print錯(cuò)誤提示
案例如下
import random num = random.randint(0,100) while 1: try: guess = int(raw_input('Enter 1-100:')) except ValueError,e: print 'error ! please enter 1-100' continue if guess > num: print 'guess bigger:',guess elif guess < num: print 'guess smaller:',guess else: print 'guess right,game over' break
3、try-finally語(yǔ)句
語(yǔ)句是否發(fā)生異常都將執(zhí)行最后的代碼。將異常保留下來(lái)交給系統(tǒng)處理,本身不處理異常。
作用:為處理異常事件提供清理機(jī)制,用來(lái)關(guān)閉文件或者釋放系統(tǒng)資源。
<語(yǔ)句>
finally:
<語(yǔ)句> #退出try時(shí)總會(huì)執(zhí)行
raise
可以使用except語(yǔ)句或者finally語(yǔ)句,但是兩者不能同時(shí)使用。else語(yǔ)句也不能與finally語(yǔ)句同時(shí)使用。
4、try-except-finally
若try語(yǔ)句沒(méi)有捕獲異常,執(zhí)行完try代碼段后,執(zhí)行finally
若try捕獲異常,首先執(zhí)行except處理異常,然后執(zhí)行finally
5、try-except-else-finally
若try語(yǔ)句沒(méi)有捕獲異常,執(zhí)行完try代碼段后,執(zhí)行else代碼段,最后執(zhí)行finally
若try捕獲異常,首先執(zhí)行except處理錯(cuò)誤,然后執(zhí)行finally
6、try-finally-except
當(dāng)在try塊中拋出一個(gè)異常,立即執(zhí)行finally塊代碼。
finally塊中的所有語(yǔ)句執(zhí)行后,異常被再次提出,并執(zhí)行except塊代碼。
7、with語(yǔ)句
用來(lái)代替try-except-finally語(yǔ)句,使代碼更加簡(jiǎn)潔
with context[as var]: with_suite
context表達(dá)式返回是一個(gè)對(duì)象
var用來(lái)保存context返回對(duì)象,單個(gè)返回值或元組
with_suite使用var變量對(duì)context返回對(duì)象進(jìn)行操作
for line in f.readline():
print line
1、打開(kāi)1.txt文件
2、f變量接收文件對(duì)象返回的對(duì)象
3、with中的代碼執(zhí)行完成后,關(guān)閉文件
程序使用了上下文管理器 (with...as...)。上下文管理器有隸屬于它的程序塊。當(dāng)隸屬的程序塊執(zhí)行結(jié)束的時(shí)候(也就是不再縮進(jìn)),上下文管理器自動(dòng)關(guān)閉了文件
運(yùn)用情況:①文件操作 ②進(jìn)城之間互斥操作:例如互斥鎖 ③支持上下文的其他對(duì)象
8、raise主動(dòng)拋出異常
#格式 rasie [exception[,args]] #Exception 異常類(lèi) #args 描述異常信息的元組 raise TypeError,'Test Error' #TypeError: Test Error
9、assert語(yǔ)句
斷言語(yǔ)句:assert語(yǔ)句是用于檢測(cè)表達(dá)式是否為真,如果為假,引發(fā)AssertionError錯(cuò)誤
assert expression [,args]
#expression 表達(dá)式
#args 判斷條件的描述信息
10、自定義異常
通過(guò)創(chuàng)建一個(gè)新的異常類(lèi),程序可以命名它們自己的異常。異常應(yīng)該是典型的繼承自Exception類(lèi),通過(guò)直接或間接的方式。
自定義異常只能主動(dòng)觸發(fā)。
class FileError(IOError):
pass
try:
raise FileError,'test error'
except FileError,e:
print e #test error
class CustomError(Exception):
def __init__(self,info):
Exception.__init__(self)
self.errorinfo = info
def __str__(self):
return 'CustomError:%s' %self.errorinfo
try:
raise CustomError('test CustomError')
except CustomError,e:
print 'ErrorInfo:',e #ErrorInfo: CustomError:test CustomError
(3)模塊和包
1、概念介紹
#test.py 自身模塊名test
import p1.util 引用p1包的模塊util
print p1.util.f(2) 調(diào)用p1.util的函數(shù)f()
如何區(qū)分包和普通目錄 包下面有個(gè)__inti__.py文件
2、如果我們只希望導(dǎo)入用到的math模塊的某幾個(gè)函數(shù),而不是所有函數(shù),可以用下面的語(yǔ)句:
from math import pow, sin, log
3、可以給函數(shù)起個(gè)“別名”來(lái)避免沖突:as
from logging import log as logger # logging的log現(xiàn)在變成了logger
print log(10) # 調(diào)用的是math的log
logger(10, 'import from logging') # 調(diào)用的是logging的log
4、如果導(dǎo)入的模塊不存在,Python解釋器會(huì)報(bào) ImportError 錯(cuò)誤:
5、第三方模塊管理系統(tǒng)
-easy_install
-pip(推薦,已內(nèi)置到Python2.7.9)
(4)作用域
1、函數(shù)作用域LEGB L>E>G>B
L:local 函數(shù)內(nèi)部作用域
E:enclosing 函數(shù)內(nèi)部與內(nèi)嵌函數(shù)之間,即閉包
G:global全局作用域
B:bulid-in 內(nèi)置作用域 list,tuple之類(lèi)
passline = 60 #全局 def func(val): passline = 90 #函數(shù)內(nèi)部 if val >= passline: print 'pass' else: print 'failed' def in_func(): print val #函數(shù)內(nèi)部與內(nèi)嵌函數(shù)之間 in_func() func(69) #failed #69
(5)高階函數(shù)
1、由于參數(shù) x, y和 f 都可以任意傳入,如果 f 傳入其他函數(shù),就可以得到不同的返回值。
return f(x) + f(y)
print add(-5, 9, abs) #abs(-5) + abs(9) = 14
2、map() 映射
map()是 Python 內(nèi)置的高階函數(shù),它接收一個(gè)函數(shù)f和一個(gè)list,并通過(guò)把函數(shù)f依次作用在 list的每個(gè)元素上,得到一個(gè)新的 list 并返回。
def f(x): return x*x print map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9]) #[1, 4, 9, 16, 25, 36, 49, 64, 81]
利用map()函數(shù),可以把一個(gè) list 轉(zhuǎn)換為另一個(gè) list,只需要傳入轉(zhuǎn)換函數(shù)。
由于list包含的元素可以是任何類(lèi)型,因此,map()不僅僅可以處理只包含數(shù)值的 list,事實(shí)上它可以處理包含任意類(lèi)型的 list,只要傳入的函數(shù)f可以處理這種數(shù)據(jù)類(lèi)型。
3、reduce()折疊
reduce()函數(shù)接收的參數(shù)和 map()類(lèi)似,一個(gè)函數(shù)f,一個(gè)list,但reduce()傳入的函數(shù)f必須接收兩個(gè)參數(shù),reduce()對(duì)list的每個(gè)元素反復(fù)調(diào)用函數(shù)f,并返回最終結(jié)果值。
return x + y
print reduce(f, [1, 3, 5, 7, 9]) #25
#先計(jì)算頭兩個(gè)元素:f(1, 3),結(jié)果為4;
#再把結(jié)果和第3個(gè)元素計(jì)算:f(4, 5),結(jié)果為9;
#再把結(jié)果和第4個(gè)元素計(jì)算:f(9, 7),結(jié)果為16;
#再把結(jié)果和第5個(gè)元素計(jì)算:f(16, 9),結(jié)果為25;
#由于沒(méi)有更多的元素了,計(jì)算結(jié)束,返回結(jié)果25。
#初始值100
print reduce(f, [1, 3, 5, 7, 9], 100) #125
reduce()還可以接收第3個(gè)可選參數(shù),作為計(jì)算的初始值。
4、filter() 過(guò)濾
filter()函數(shù)接收一個(gè)函數(shù)f和一個(gè)list,這個(gè)函數(shù) f 的作用是對(duì)每個(gè)元素進(jìn)行判斷,返回 True或 False,filter()根據(jù)判斷結(jié)果自動(dòng)過(guò)濾掉不符合條件的元素,返回由符合條件元素組成的新list。
def is_odd(x): #是奇數(shù) return x % 2 == 1 print filter(is_odd, [1, 4, 6, 7, 9, 12, 17]) #[1, 7, 9, 17]
利用filter(),可以完成很多有用的功能,例如,刪除 None 或者空字符串:
return s and len(s.strip()) > 0
print filter(is_not_empty, ['test', None, '', 'str', ' ', 'END'])
#['test', 'str', 'END']
5、sorted():對(duì)list進(jìn)行排序
print sorted([36, 5, 12, 9, 21]) #[5, 9, 12, 21, 36]
但sorted()也是一個(gè)高階函數(shù),它可以接收一個(gè)比較函數(shù)來(lái)實(shí)現(xiàn)自定義排序,比較函數(shù)的定義是,傳入兩個(gè)待比較的元素x, y,如果x應(yīng)該排在y的前面,返回-1,如果x應(yīng)該排在y的后面,返回1。如果x和y相等,返回0。
def reversed_cmp(x, y):
if x > y:
return -1
if x < y:
return 1
return 0
print sorted([36, 5, 12, 9, 21], reversed_cmp) #[36, 21, 12, 9, 5]
6、Python的函數(shù)不但可以返回int、str、list、dict等數(shù)據(jù)類(lèi)型,還可以返回函數(shù)!
def f(): print 'call f()...' # 定義函數(shù)g: def g(): print 'call g()...' # 返回函數(shù)g: return g x = f() # 調(diào)用f() call f()... x # 變量x是f()返回的函數(shù): #<function g at 0x00000000022CDA58> x() # x指向函數(shù),因此可以調(diào)用 call g()... x=f(),x()=g()
請(qǐng)注意區(qū)分返回函數(shù)和返回值:
return abs # 返回函數(shù)
def myabs2(x):
return abs(x) # 返回函數(shù)調(diào)用的結(jié)果,返回值是一個(gè)數(shù)值
在函數(shù)內(nèi)部定義的函數(shù)和外部定義的函數(shù)是一樣的,只是他們無(wú)法被外部訪問(wèn):
7、閉包(closure)
內(nèi)部函數(shù)中引用了外層函數(shù)的變量(enclosing作用域的變量),然后返回內(nèi)層函數(shù)的情況。
閉包的作用是封裝和代碼復(fù)用。
傳遞的是參數(shù)
#如果要實(shí)現(xiàn)兩個(gè)功能,可以定義兩個(gè)函數(shù)。 def func_150(val): passline = 90 #150 if val >= passline: print ('pass') else: print 'failed' def func_100(val): passline = 60 #150 if val >= passline: print ('pass') else: print 'failed' func_100(69)#pass func_150(69)#failed #如果用閉包的話只需要定義一個(gè)函數(shù) def set_passline(passline):#passline def cmp(val): if val >= passline: print 'pass' else: print 'failed' return cmp #返回值是一個(gè)函數(shù) f_100 = set_passline(60) #f_100就是cmp,f_100()就是cmp(),而且內(nèi)置一個(gè)passline=60 f_150 = set_passline(90) f_100(69)#pass f_150(69)#failed
傳遞的是函數(shù)
def my_sum(*arg):
if len(arg)==0:
return 0
for val in arg:
if not isinstance(val,int):
return 0
return sum(arg)
def my_average(*arg):
if len(arg)==0:
return 0
for val in arg:
if not isinstance(val,int):
return 0
return sum(arg)/len(arg)
print my_sum(1,2,3,4,5) #15
print my_sum(1,2,3,4,5,'6')#0
print my_average(1,2,3,4,5)#3
print my_average()#0
#使用閉包
def my_sum(*arg):
print 'in my_sum'
return sum(arg)
def my_average(*arg):
return sum(arg)/len(arg)
def dec(func):
def in_dec(*arg):
print 'in_dec()=',arg
if len(arg) == 0:
return 0
for val in arg:
if not isinstance(val, int):
return 0
return func(*arg)
return in_dec #別加括號(hào)
#dec return in_dec -> my_sum
#my_sum = in_dec(*arg)
my_sum = dec(my_sum)
my_average = dec(my_average)#同理
print my_sum(1,2,3,4,5)
print my_sum(1,2,3,4,5,'6')
# 結(jié)果
# in_dec()= (1, 2, 3, 4, 5)
# in my_sum
# 15
# in_dec()= (1, 2, 3, 4, 5, '6')
# 0
正確使用閉包,就要確保引用的局部變量在函數(shù)返回后不能變。
返回函數(shù)不要引用任何循環(huán)變量,或者后續(xù)會(huì)發(fā)生變化的變量。
# 希望一次返回3個(gè)函數(shù),分別計(jì)算1x1,2x2,3x3: def count(): fs = [] for i in range(1, 4): def f(): return i*i fs.append(f) return fs f1, f2, f3 = count() print f1(),f2(),f3() #9 9 9 #當(dāng)count()函數(shù)返回了3個(gè)函數(shù)時(shí),這3個(gè)函數(shù)所引用的變量 i 的值已經(jīng)變成了3。由于f1、f2、f3并沒(méi)有被調(diào)用,所以,此時(shí)他們并未計(jì)算 i*i,當(dāng) f1 被調(diào)用時(shí),才計(jì)算i*i,但現(xiàn)在i的值已經(jīng)變?yōu)? #正確如下 def count(): fs = [] for i in range(1, 4): def f(j): def g(): return j*j return g r = f(i) fs.append(r) return fs f1, f2, f3 = count() print f1(), f2(), f3() #1 4 9
8、匿名函數(shù)lambda
return x*x
print map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9]) #[1, 4, 9, 16, 25, 36, 49, 64, 81]
print map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]) #[1, 4, 9, 16, 25, 36, 49, 64, 81]
通過(guò)對(duì)比可以看出,匿名函數(shù) lambda x: x * x 實(shí)際上就是:
def f(x):
return x * x
關(guān)鍵字lambda表示匿名函數(shù),冒號(hào)前面的x 表示函數(shù)參數(shù)。
匿名函數(shù)有個(gè)限制,就是只能有一個(gè)表達(dá)式,不寫(xiě)return,返回值就是該表達(dá)式的結(jié)果。
使用匿名函數(shù),可以不必定義函數(shù)名,直接創(chuàng)建一個(gè)函數(shù)對(duì)象,很多時(shí)候可以簡(jiǎn)化代碼:
print sorted([1, 3, 9, 5, 0], lambda x,y: -cmp(x,y)) #[9, 5, 3, 1, 0]
返回函數(shù)的時(shí)候,也可以返回匿名函數(shù):
print myabs(-1) #1
print myabs(1) #1
(6)裝飾器
1、decorator本質(zhì)上就是一個(gè)高階函數(shù),它接收一個(gè)函數(shù)作為參數(shù),然后,返回一個(gè)新函數(shù)。
使用 decorator 用Python提供的@語(yǔ)法,這樣可以避免手動(dòng)編寫(xiě)f=decorate(f)這樣的代碼。
2、裝飾器用來(lái)裝飾函數(shù),返回一個(gè)函數(shù)對(duì)象
被裝飾函數(shù)標(biāo)識(shí)符指向返回的函數(shù)對(duì)象
def dec(func): print 'call dec' def in_dec(*arg): print 'in_dec()=',arg if len(arg) == 0: return 0 for val in arg: if not isinstance(val, int): return 0 return func(*arg) return in_dec #別加括號(hào) @dec # 代替了my_sum = dec(my_sum) def my_sum(*arg): #my_sum = in_dec print 'in my_sum' return sum(arg) print my_sum(1,2,3,4,5) # call dec # in_dec()= (1, 2, 3, 4, 5) # in my_sum # 15
3、傳入函數(shù),含有兩個(gè)參數(shù)
def in_deco(x,y):
print 'in deco'
func(x,y)
print 'call deco'
return in_deco
@deco #代替 bar = deco(bar) = in_deco #bar()-> in_deco()->bar()
def bar(x,y):
print 'in bar',x+y
bar(1,2)
# call deco
# in deco
# in bar
4、@log的定義
def log(f): def fn(x): print 'call ' + f.__name__ + '()...' return f(x) return fn @log def factorial(n): return reduce(lambda x,y: x*y, range(1, n+1)) print factorial(10) # call factorial()... # 3628800
但是,對(duì)于參數(shù)不是一個(gè)的函數(shù),調(diào)用將報(bào)錯(cuò)。@log寫(xiě)死了只含一個(gè)參數(shù)的返回函數(shù)。
5、要讓@log自適應(yīng)任何參數(shù)定義的函數(shù),可以利用Python的*args和**kw,保證任意個(gè)數(shù)的參數(shù)總是能正常調(diào)用:
可變參數(shù)*args表示任何多個(gè)無(wú)名參數(shù),它是一個(gè)tuple;**kwargs表示關(guān)鍵字參數(shù),它是一個(gè)dict。并且同時(shí)使用*args和**kwargs時(shí),必須*args參數(shù)列要在**kwargs前。
def fn(*args, **kw):
print 'call ' + f.__name__ + '()...'
return f(*args, **kw)
return fn
@log
def add(x, y):
return x + y
print add(1, 2)
# call add()...
# 3
6、@performance,它可以打印出函數(shù)調(diào)用的時(shí)間。
計(jì)算函數(shù)調(diào)用的時(shí)間可以記錄調(diào)用前后的當(dāng)前時(shí)間戳,然后計(jì)算兩個(gè)時(shí)間戳的差。
import time def performance(f): def fn(*args, **kw): t1 = time.time() r = f(*args, **kw) t2 = time.time() print 'call %s() in %fs' % (f.__name__, (t2 - t1)) return r return fn @performance def factorial(n): return reduce(lambda x,y: x*y, range(1, n+1)) print factorial(5) # call factorial() in 0.000000s # 120
7、對(duì)于被裝飾的函數(shù),log打印的語(yǔ)句是不能變的(除了函數(shù)名)。
如果有的函數(shù)非常重要,希望打印出'[INFO] call xxx()...',有的函數(shù)不太重要,希望打印出'[DEBUG] call xxx()...',這時(shí),log函數(shù)本身就需要傳入'INFO'或'DEBUG'這樣的參數(shù):
def my_func():
pass
#把上面的定義翻譯成高階函數(shù)的調(diào)用,就是:
my_func = log('DEBUG')(my_func)
#上面的語(yǔ)句看上去還是比較繞,再展開(kāi)一下:
log_decorator = log('DEBUG')
my_func = log_decorator(my_func)
#上面的語(yǔ)句又相當(dāng)于:
log_decorator = log('DEBUG')
@log_decorator
def my_func():
pass
所以,帶參數(shù)的log函數(shù)首先返回一個(gè)decorator函數(shù),再讓這個(gè)decorator函數(shù)接收my_func并返回新函數(shù):
而且wrapper(*args, **kw)要調(diào)用外層參數(shù)prefix,所以無(wú)法拆開(kāi)
def log(prefix): def log_decorator(f): def wrapper(*args, **kw): print '[%s] %s()...' % (prefix, f.__name__) return f(*args, **kw) return wrapper return log_decorator @log('DEBUG') def test(): pass print test() # [DEBUG] test()... # None
8、區(qū)別
def f1(x):
pass
print f1.__name__ #f1
#有decorator的情況下,再打印函數(shù)名:
def log(f):
def wrapper(*args, **kw):
print 'call...'
return f(*args, **kw)
return wrapper
@log
def f2(x):
pass
print f2.__name__ #wrapper
可見(jiàn),由于decorator返回的新函數(shù)函數(shù)名已經(jīng)不是'f2',而是@log內(nèi)部定義的'wrapper'。這對(duì)于那些依賴(lài)函數(shù)名的代碼就會(huì)失效。decorator還改變了函數(shù)的__doc__等其它屬性。如果要讓調(diào)用者看不出一個(gè)函數(shù)經(jīng)過(guò)了@decorator的“改造”,就需要把原函數(shù)的一些屬性復(fù)制到新函數(shù)中:
def log(f): def wrapper(*args, **kw): print 'call...' return f(*args, **kw) wrapper.__name__ = f.__name__ wrapper.__doc__ = f.__doc__ return wrapper
這樣寫(xiě)decorator很不方便,因?yàn)槲覀円埠茈y把原函數(shù)的所有必要屬性都一個(gè)一個(gè)復(fù)制到新函數(shù)上,所以Python內(nèi)置的functools可以用來(lái)自動(dòng)化完成這個(gè)“復(fù)制”的任務(wù):
def log(f):
@functools.wraps(f)
def wrapper(*args, **kw):
print 'call...'
return f(*args, **kw)
return wrapper
@log
def f2(x):
pass
print f2.__name__ #f2
9、當(dāng)一個(gè)函數(shù)有很多參數(shù)時(shí),調(diào)用者就需要提供多個(gè)參數(shù)。如果減少參數(shù)個(gè)數(shù),就可以簡(jiǎn)化調(diào)用者的負(fù)擔(dān)。
比如,int()函數(shù)可以把字符串轉(zhuǎn)換為整數(shù),當(dāng)僅傳入字符串時(shí),int()函數(shù)默認(rèn)按十進(jìn)制轉(zhuǎn)換:
但int()函數(shù)也提供額外的base參數(shù),默認(rèn)為10。如果傳入base參數(shù),就可以做N進(jìn)制轉(zhuǎn)換:
print int('10') #10 print int('10', 8) #8 print int('A', 16) #10
假設(shè)要轉(zhuǎn)換大量的二進(jìn)制字符串,每次都傳入int(x, base=2)非常麻煩,于是,我們想到,可以定義一個(gè)int2()的函數(shù),默認(rèn)把base=2傳進(jìn)去:
return int(x, base)
print int2('1000000') #64
print int2('1010101') #85
functools.partial就是幫助我們創(chuàng)建一個(gè)偏函數(shù)的,不需要我們自己定義int2(),可以直接使用下面的代碼創(chuàng)建一個(gè)新的函數(shù)int2:
import functools int2 = functools.partial(int, base=2) print int2('1000000') #64 print int2('1010101') #85
所以,functools.partial可以把一個(gè)參數(shù)多的函數(shù)變成一個(gè)參數(shù)少的新函數(shù),少的參數(shù)需要在創(chuàng)建時(shí)指定默認(rèn)值,這樣,新函數(shù)調(diào)用的難度就降低了。
(7)參數(shù)
1、位置參數(shù)必須以在被調(diào)用函數(shù)中定義的準(zhǔn)確順序來(lái)傳遞,參數(shù)數(shù)目必須一致。
2、所有必需的參數(shù)都要在默認(rèn)參數(shù)之前。
def func_with_parameters(x, y):
print(x, y)
func_with_parameters(1, 2)
#默認(rèn)值參數(shù)
def func_with_default_value_parameters(x, y, z = 3):
print(x, y, z)
func_with_default_value_parameters(y = 2, x = 1)
3、如果命名了參數(shù),這里可以不按順序給出參數(shù)。
#命名參數(shù) def func_with_named_parameters(x, y, z): print(x, y, z) func_with_named_parameters(z = 1, y = 2, x = 3)
4、變長(zhǎng)的參數(shù)在函數(shù)聲明中不是顯式命名的,因?yàn)閰?shù)的數(shù)目在運(yùn)行時(shí)之前是未知的(甚至在運(yùn)行的期間,每次函數(shù)調(diào)用的參數(shù)的數(shù)目也可能是不同的),這和常規(guī)參數(shù)(位置和默認(rèn))明顯不同,常規(guī)參數(shù)都是在函數(shù)聲明中命名的。由于函數(shù)調(diào)用提供了關(guān)鍵字以及非關(guān)鍵字兩種參數(shù)類(lèi)型,python 用兩種方法來(lái)支持變長(zhǎng)參數(shù)。
func(*tuple_grp_nonkw_args, **dict_grp_kw_args)
其中的 tuple_grp_nonkw_args 是以元組形式體現(xiàn)的非關(guān)鍵字參數(shù)組, dict_grp_kw_args 是裝有關(guān)鍵字參數(shù)的字典。
5、可變長(zhǎng)的參數(shù)元組必須在位置和默認(rèn)參數(shù)之后。
def func_with_collection_rest_parameters(x, y=0, *rest):
print(x, y)
print(rest)
func_with_collection_rest_parameters(1, 2, 3, 4, 5)
星號(hào)操作符之后的形參將作為元組傳遞給函數(shù),元組保存了所有傳遞給函數(shù)的'額外'的參數(shù)(匹配了所有位置和具名參數(shù)后剩余的)。如果沒(méi)有給出額外的參數(shù),元組為空。
6、關(guān)鍵字變量參數(shù)(Dictionary)
在我們有不定數(shù)目的或者額外集合的關(guān)鍵字的情況中, 參數(shù)被放入一個(gè)字典中,字典中鍵為參數(shù)名,值為相應(yīng)的參數(shù)值。
#收集命名參數(shù)
def func_with_collection_rest_naned_parameters(*args, **kw):
print(args)
print(kw)
func_with_collection_rest_naned_parameters(1, 2, 3, x = 4, y = 5, z = 6)
func_with_collection_rest_naned_parameters([1, 2, 3], {'x': 4, 'y': 4, 'z': 6})
#這會(huì)導(dǎo)致args[0]指向第一個(gè)實(shí)參,args[1]指向第二個(gè)實(shí)參。
#([1, 2, 3], {'y': 4, 'x': 4, 'z': 6})
#{}
func_with_collection_rest_naned_parameters(*[1, 2, 3], **{'x': 4, 'y': 4, 'z': 6})
#這里的執(zhí)行相當(dāng)于
func_with_collection_rest_naned_parameters(1, 2, 3, x = 4, y = 5, z = 6)。
(8)面向?qū)ο?/p>
1、類(lèi)通過(guò)class關(guān)鍵字定義。類(lèi)名以大寫(xiě)字母開(kāi)頭,緊接著是(object),表示該類(lèi)是從哪個(gè)類(lèi)繼承下來(lái)的。
類(lèi)也要細(xì)致命名,像“AddrBookEntry”,“RepairShop”等等就是很好的名字
Python 并不支持純虛函數(shù)(像 C++)或者抽象方法(如在 JAVA 中)
class Person(object):
pass
2、有了Person類(lèi)的定義,就可以創(chuàng)建出具體的xiaoming、xiaohong等實(shí)例。創(chuàng)建實(shí)例使用類(lèi)名+(),類(lèi)似函數(shù)調(diào)用的形式創(chuàng)建:
Python 規(guī)范推薦使用駱駝?dòng)浄ǖ南聞澗€方式,比如,“update_phone”“update_email”。
xiaoming = Person()
xiaohong = Person()
3、由于Python是動(dòng)態(tài)語(yǔ)言,對(duì)每一個(gè)實(shí)例,都可以直接給他們的屬性賦值:
xiaoming = Person()
xiaoming.name = 'Xiao Ming'
xiaoming.gender = 'Male'
xiaoming.birth = '1990-1-1'
4、構(gòu)造函數(shù)__init__()方法
class Person(object):
def __init__(self, name, gender, birth):
self.name = name
self.gender = gender
self.birth = birth
__init__()方法的第一個(gè)參數(shù)必須是self(也可以用別的名字,但建議使用習(xí)慣用法),后續(xù)參數(shù)則可以自由指定,和定義函數(shù)沒(méi)有任何區(qū)別。
相應(yīng)地,創(chuàng)建實(shí)例時(shí),就必須要提供除self以外的參數(shù):
xiaoming = Person('Xiao Ming', 'Male', '1991-1-1')
xiaohong = Person('Xiao Hong', 'Female', '1992-2-2')
print xiaoming.name # 輸出 'Xiao Ming'
print xiaohong.birth # 輸出 '1992-2-2'
定義Person類(lèi)的__init__方法,除了接受 name、gender 和 birth 外,還可接受任意關(guān)鍵字參數(shù),并把他們都作為屬性賦值給實(shí)例。
要定義關(guān)鍵字參數(shù),使用 **kw;
除了可以直接使用self.name = 'xxx'設(shè)置一個(gè)屬性外,還可以通過(guò) setattr(self, 'name', 'xxx') 設(shè)置屬性。
class Person(object): def __init__(self, name, gender, birth, **kw): self.name = name self.gender = gender self.birth = birth for k, v in kw.iteritems(): setattr(self, k, v) xiaoming = Person('Xiao Ming', 'Male', '1990-1-1', job='Student') print xiaoming.name #輸出Xiao Ming print xiaoming.job #輸出Student
5、析構(gòu)函數(shù)
由于 Python 具有垃圾對(duì)象回收機(jī)制(靠引用計(jì)數(shù)),這個(gè)函數(shù)要直到該實(shí)例對(duì)象所有的引用都被清除掉后才會(huì)執(zhí)行。所以很少用到。
class Person(object):
def __init__(self, ……):
6、Python對(duì)屬性權(quán)限的控制是通過(guò)屬性名來(lái)實(shí)現(xiàn)的,如果一個(gè)屬性由雙下劃線開(kāi)頭(__),該屬性就無(wú)法被外部訪問(wèn)。
def __init__(self, name):
self.name = name
self._title = 'Mr'
self.__job = 'Student'
p = Person('Bob')
print p.name # => Bob
print p._title # => Mr
print p._Person__job # => Student #所以實(shí)際上并不是嚴(yán)格的私有成員
print p.__job # => Error
但是,如果一個(gè)屬性以'__xxx__'的形式定義,那它又可以被外部訪問(wèn)了,以'__xxx__'定義的屬性在Python的類(lèi)中被稱(chēng)為特殊屬性,有很多預(yù)定義的特殊屬性可以使用,通常我們不要把普通屬性用'__xxx__'定義。
以單下劃線開(kāi)頭的屬性'_xxx'可以在子類(lèi)中使用,不應(yīng)該被外部訪問(wèn),理解為保護(hù)成員。
'__xxx'可以理解為私有成員,但實(shí)質(zhì)并不是,不建議訪問(wèn)。
7、類(lèi)屬性是直接綁定在類(lèi)上的,所以,訪問(wèn)類(lèi)屬性不需要?jiǎng)?chuàng)建實(shí)例,就可以直接訪問(wèn):
class Person(object): address = 'Earth' def __init__(self, name): self.name = name p1=Person(xiaoming) print Person.address # => Earth print p1.address # => Earth # 由于Python是動(dòng)態(tài)語(yǔ)言,類(lèi)屬性也是可以動(dòng)態(tài)添加和修改的: Person.address = 'China' print p1.address # => 'China'
8、在實(shí)例變量上修改類(lèi)屬性
當(dāng)實(shí)例屬性和類(lèi)屬性重名時(shí),實(shí)例屬性優(yōu)先級(jí)高,它將屏蔽掉對(duì)類(lèi)屬性的訪問(wèn)。而其他不變
9、訪問(wèn)類(lèi)的屬性
有兩種方法。最簡(jiǎn)單的是使用 dir()內(nèi)建函數(shù)。另外是通過(guò)訪問(wèn)類(lèi)的字典屬性__dict__,這是所有類(lèi)都具備的特殊屬性之一。
10、實(shí)例的方法。
實(shí)例的方法就是在類(lèi)中定義的函數(shù),它的第一個(gè)參數(shù)永遠(yuǎn)是self,指向調(diào)用該方法的實(shí)例本身,其他參數(shù)和一個(gè)普通函數(shù)是完全一樣的:在其他語(yǔ)言中,self就是this.
def __init__(self, name):
self.__name = name
def get_name(self):
return self.__name
p1 = Person('Bob')
print p1.get_name() # self不需要顯式傳入 # => Bob
print p1.__dict__ # {'_Person__name': 'Bob'}
print p1._Person__name # => Bob
在實(shí)例方法內(nèi)部,可以訪問(wèn)所有實(shí)例屬性,這樣,如果外部需要訪問(wèn)私有屬性,可以通過(guò)方法調(diào)用獲得,這種數(shù)據(jù)封裝的形式除了能保護(hù)內(nèi)部數(shù)據(jù)一致性外,還可以簡(jiǎn)化外部調(diào)用的難度。
11、方法也分實(shí)例方法和類(lèi)方法。
@classmethod 調(diào)用的時(shí)候用類(lèi)名而不是某個(gè)對(duì)象
在class中定義的全部是實(shí)例方法,實(shí)例方法第一個(gè)參數(shù)self是實(shí)例本身。
要在class中定義類(lèi)方法,需要這么寫(xiě):
class Person(object): count = 0 @classmethod def how_many(cls): return cls.count def __init__(self, name): self.name = name Person.count = Person.count + 1 print Person.how_many() #0 p1 = Person('Bob') print Person.how_many() #1
通過(guò)標(biāo)記一個(gè)@classmethod,該方法將綁定到Person類(lèi)上,而非類(lèi)的實(shí)例。類(lèi)方法的第一個(gè)參數(shù)將傳入類(lèi)本身,通常將參數(shù)名命名為cls,上面的cls.count實(shí)際上相當(dāng)于Person.count。
因?yàn)槭窃陬?lèi)上調(diào)用,而非實(shí)例上調(diào)用,因此類(lèi)方法無(wú)法獲得任何實(shí)例變量,只能獲得類(lèi)的引用
12、@property 像訪問(wèn)屬性一樣調(diào)用方法,即不用括號(hào)
count = 0
def __init__(self, name,age,weight):
self.name = name
self._age = age
self.__weight = weight
Person.count = Person.count + 1
@classmethod
def how_many(cls):
return cls.count
@property
def get_weight(self):
return self.__weight
print Person.how_many() # 0
p1 = Person('Bob',20,50)
print Person.how_many() # 1
print p1.get_weight #50
get/set方法:
class Student(object): def __init__(self, name, score): self.name = name self.__score = score def get_score(self): return self.__score def set_score(self, score): if score < 0 or score > 100: raise ValueError('invalid score') self.__score = score #但是寫(xiě) s.get_score() 和 s.set_score() 沒(méi)有直接寫(xiě) s.score 來(lái)得直接。
用裝飾器函數(shù)把get/set方法“裝飾”成屬性調(diào)用:
把一個(gè)getter方法變成屬性,只需要加上 @ property就可以了
setter是關(guān)鍵字,這種“@+方法名字+點(diǎn)+setter”是個(gè)固定格式與@property搭配使用。
def __init__(self, name, score):
self.name = name
self.__score = score
@property
def score(self):
return self.__score
@score.setter
def score(self, score):
if score < 0 or score > 100:
raise ValueError('invalid score')
self.__score = score
s = Student('Bob',100)
print s.score #100
s.score = 90 #屬性賦值
print s.score #90
13、函數(shù)和方法
函數(shù)是直接調(diào)用函數(shù)名,僅僅是一部分代碼
方法必須和對(duì)象結(jié)合在一起使用,是類(lèi)的一部分
方法可以看做是類(lèi)的屬性
class Test(object): def test(self): pass a = Test() print a.test #<bound method Test.test of <__main__.Test object at 0x00000000022B8E10>> print a.test() #None a.test= '123' print a.test #123 print a.test() #報(bào)錯(cuò)
14、定義子類(lèi)
def __init__(self, name, gender):
self.name = name
self.gender = gender
class Student(Person):
def __init__(self, name, gender, score):
super(Student, self).__init__(name, gender) #初始化
self.score = score
一定要用super(Student, self).__init__(name, gender)去初始化父類(lèi),否則,繼承自Person的Student將沒(méi)有name和gender。
函數(shù)super(Student, self)將返回當(dāng)前類(lèi)繼承的父類(lèi),即Person,然后調(diào)用__init__()方法,注意self參數(shù)已在super()中傳入,在__init__()中將隱式傳遞,不需要寫(xiě)出(也不能寫(xiě))
使用super()的漂亮之處在于,你不需要明確給出任何基類(lèi)名字,這意味著如果你改變了類(lèi)繼承關(guān)系,你只需要改一行代碼(class語(yǔ)句本身)而不必在大量代碼中去查找所有被修改的那個(gè)類(lèi)的名字。
一個(gè)實(shí)例可以看成它本身的類(lèi)型,也可以看成它父類(lèi)的類(lèi)型。
15、多重繼承
class A(object): def __init__(self, a): print 'init A...' self.a = a class B(A): def __init__(self, a): super(B, self).__init__(a) print 'init B...' class C(A): def __init__(self, a): super(C, self).__init__(a) print 'init C...' class D(B, C): def __init__(self, a): super(D, self).__init__(a) print 'init D...'
像這樣,D 同時(shí)繼承自 B 和 C,也就是 D 擁有了 A、B、C 的全部功能。多重繼承通過(guò)super()調(diào)用__init__()方法時(shí),A 雖然被繼承了兩次,但__init__()只調(diào)用一次:
多重繼承的目的是從兩種繼承樹(shù)中分別選擇并繼承出子類(lèi),以便組合功能使用。
舉個(gè)例子,Python的網(wǎng)絡(luò)服務(wù)器有TCPServer、UDPServer、UnixStreamServer、UnixDatagramServer,而服務(wù)器運(yùn)行模式有多進(jìn)程ForkingMixin和多線程ThreadingMixin兩種。
要?jiǎng)?chuàng)建多進(jìn)程模式的 TCPServer:
class MyTCPServer(TCPServer, ForkingMixin)
pass
要?jiǎng)?chuàng)建多線程模式的 UDPServer:
class MyUDPServer(UDPServer, ThreadingMixin):
pass
如果沒(méi)有多重繼承,要實(shí)現(xiàn)上述所有可能的組合需要 4x2=8 個(gè)子類(lèi)。
16、多態(tài)
用一個(gè)類(lèi)繼承多個(gè)類(lèi),調(diào)用同一個(gè)方法,會(huì)有不同的反應(yīng),因?yàn)楸恢貙?xiě)了。
17、鴨子類(lèi)型
定義:“當(dāng)看到一只鳥(niǎo)走起來(lái)像鴨子、游泳起來(lái)像鴨子、叫起來(lái)也像鴨子,那么這只鳥(niǎo)就可以被稱(chēng)為鴨子。
這種風(fēng)格適用于動(dòng)態(tài)語(yǔ)言(比如PHP、Python、Ruby、Typescript、Perl、Objective-C、Lua、Julia、JavaScript、Java、Groovy、C#等)和某些靜態(tài)語(yǔ)言
在鴨子類(lèi)型中,關(guān)注的不是對(duì)象的類(lèi)型本身,而是它是如何使用的。例如,在不使用鴨子類(lèi)型的語(yǔ)言中,我們可以編寫(xiě)一個(gè)函數(shù),它接受一個(gè)類(lèi)型為鴨的對(duì)象,并調(diào)用它的走和叫方法。在使用鴨子類(lèi)型的語(yǔ)言中,這樣的一個(gè)函數(shù)可以接受一個(gè)任意類(lèi)型的對(duì)象,并調(diào)用它的走和叫方法。
鴨子類(lèi)型通常得益于不測(cè)試方法和函數(shù)中參數(shù)的類(lèi)型,而是依賴(lài)文檔、清晰的代碼和測(cè)試來(lái)確保正確使用。從靜態(tài)類(lèi)型語(yǔ)言轉(zhuǎn)向動(dòng)態(tài)類(lèi)型語(yǔ)言的用戶通常試圖添加一些靜態(tài)的(在運(yùn)行之前的)類(lèi)型檢查,從而影響了鴨子類(lèi)型的益處和可伸縮性,并約束了語(yǔ)言的動(dòng)態(tài)特性。
鴨子類(lèi)型比接口更好用。
def say(self):
print('我是鴨子1')
class TestClass2:
def say(self):
print('我是鴨子2')
def duck_say(duck):
duck.say()
duck_say(TestClass1()) # 我是鴨子1
duck_say(TestClass2()) # 我是鴨子2
18、getattr()、setattr()和delattr():
getattr()和 setattr()函數(shù)相應(yīng)地取得和賦值給對(duì)象的屬性,
getattr()會(huì)在你試圖讀取一個(gè)不存在的屬性時(shí),引發(fā) AttributeError 異常,除非給出那個(gè)可選的默認(rèn)參數(shù)。
setattr()將要么加入一個(gè)新的屬性,要么取代一個(gè)已存在的屬性。
delattr()函數(shù)會(huì)從一個(gè)對(duì)象中刪除屬性
class Person(object): def __init__(self, name, gender): self.name = name self.gender = gender class Student(Person): def __init__(self, name, gender, score): super(Student, self).__init__(name, gender) self.score = score def whoAmI(self): return 'I am a Student, my name is %s' % self.name s = Student('Bob', 'Male', 88) print getattr(s, 'name') # 獲取name屬性 #Bob setattr(s, 'name', 'Adam') # 設(shè)置新的name屬性 print s.name #Adam getattr(s, 'age') # 獲取age屬性,但是屬性不存在,報(bào)錯(cuò): getattr(s, 'age', 20) # 獲取age屬性,如果屬性不存在,就返回默認(rèn)值20:
(9)定制類(lèi)(魔術(shù)方法)
1、__str__():把一個(gè)類(lèi)的實(shí)例變成 str
__repr__()轉(zhuǎn)換為機(jī)器看的字符串,可以由eval()執(zhí)行
def __init__(self, name, gender):
self.name = name
self.gender = gender
def __str__(self):
return '(Person: %s, %s)' % (self.name, self.gender)
p = Person('Bob', 'male')
print p #(Person: Bob, male)
2、比較運(yùn)算符_cmp__():可以實(shí)現(xiàn)對(duì)一組 Student 類(lèi)的實(shí)例排序
__eq__()判斷等于,__lt__()判斷小于,__gt__()判斷大于
class Student(object): def __init__(self, name, score): self.name = name self.score = score def __str__(self): return '(%s: %s)' % (self.name, self.score) def __cmp__(self, s): if self.name < s.name: return -1 elif self.name > s.name: return 1 else: return 0 L = [Student('Tim', 99), Student('Bob', 88), Student('Alice', 77)] print sorted(L) #[(Alice: 77), (Bob: 88), (Tim: 99)] L = [Student('Tim', 99), Student('Bob', 88), 100, 'Hello'] #list不僅僅包含 Student 類(lèi) print sorted(L) #報(bào)錯(cuò)
上述 Student 類(lèi)實(shí)現(xiàn)了__cmp__()方法,__cmp__用實(shí)例自身self和傳入的實(shí)例 s 進(jìn)行比較,如果self應(yīng)該排在前面,就返回 -1,如果s應(yīng)該排在前面,就返回1,如果兩者相當(dāng),返回 0。
3、__len__():返回元素的個(gè)數(shù)
def __init__(self, *args):
self.names = args
def __len__(self):
return len(self.names)
ss = Students('Bob', 'Alice', 'Tim')
print len(ss) #3
4、四則運(yùn)算:__add__(),__sub__(),__mul__(),__div__()
邏輯運(yùn)算 __or__(),__and__()
def gcd(a, b): if b == 0: return a return gcd(b, a % b) class Rational(object): def __init__(self, p, q): self.p = p self.q = q def __add__(self, r): return Rational(self.p * r.q + self.q * r.p, self.q * r.q) def __sub__(self, r): return Rational(self.p * r.q - self.q * r.p, self.q * r.q) def __mul__(self, r): return Rational(self.p * r.p, self.q * r.q) def __div__(self, r): return Rational(self.p * r.q, self.q * r.p) def __str__(self): g = gcd(self.p, self.q) return '%s/%s' % (self.p / g, self.q / g) __repr__ = __str__ r1 = Rational(1, 2) r2 = Rational(1, 4) print r1 + r2 #3/4 print r1 - r2 #1/4 print r1 * r2 #1/8 print r1 / r2 #2/1
我們也許還有希望覆蓋“原位”操作, 比如, __iadd__()。這是用來(lái)支持像 mon += tue 這樣的操作符,并把正確的結(jié)果賦給 mon。重載一個(gè)__i*__()方法的唯一秘密是它必須返回 self。把下面的片斷加到我們例子中,以修復(fù)上面的 repr()問(wèn)題,并支持增量賦值:
5、類(lèi)型轉(zhuǎn)換:__int__(),__float__()
def __init__(self, p, q):
self.p = p
self.q = q
def __int__(self):
return self.p // self.q
def __float__(self):
return float(self.p) / self.q
print int(Rational(7, 2)) #3
print int(Rational(1, 3)) #0
print float(Rational(7, 2)) #3.5
print float(Rational(1, 3)) #0.333333333333
6、__slots__():限制當(dāng)前類(lèi)所能擁有的屬性,能節(jié)省內(nèi)存
class Person(object): __slots__ = ('name', 'gender') def __init__(self, name, gender): self.name = name self.gender = gender p = Person('Bob', 'male') print p.name #Bob print p.gender #male print p.score #報(bào)錯(cuò) class Student(Person): __slots__ = ('score',) def __init__(self, name, gender, score): super(Student, self).__init__(name, gender) self.score = score s = Student('Bob', 'male', 59) print s.score # 59
__slots__定義的屬性僅對(duì)當(dāng)前類(lèi)起作用,對(duì)繼承的子類(lèi)是不起作用的。除非在子類(lèi)中也定義__slots__
7、__call__():
在Python中,所有的函數(shù)都是可調(diào)用對(duì)象。
一個(gè)類(lèi)實(shí)例也可以變成一個(gè)可調(diào)用對(duì)象,只需要實(shí)現(xiàn)一個(gè)特殊方法__call__()。
def __init__(self, name, gender):
self.name = name
self.gender = gender
def __call__(self, friend):
print 'My name is %s...' % self.name
print 'My friend is %s...' % friend
p = Person('Bob', 'male')
p('Tim')
# My name is Bob...
# My friend is Tim...
單看p('Tim')你無(wú)法確定p是一個(gè)函數(shù)還是一個(gè)類(lèi)實(shí)例,所以,在Python中,函數(shù)也是對(duì)象,對(duì)象和函數(shù)的區(qū)別并不顯著。
(10)日期和時(shí)間
1、time包基于C語(yǔ)言的庫(kù)函數(shù)(library functions)。Python的解釋器通常是用C編寫(xiě)的,Python的一些函數(shù)也會(huì)直接調(diào)用C語(yǔ)言的庫(kù)函數(shù)。
2、時(shí)間間隔是以秒為單位的浮點(diǎn)小數(shù)。
3、每個(gè)時(shí)間戳都以自從1970年1月1日午夜(歷元)經(jīng)過(guò)了多長(zhǎng)時(shí)間來(lái)表示。
import time; # 引入time模塊 ticks = time.time() print ticks
4、獲取當(dāng)前時(shí)間
localtime = time.localtime(time.time())
print '本地時(shí)間為 :', localtime
#本地時(shí)間為 : time.struct_time(tm_year=2017, tm_mon=2, tm_mday=13, tm_hour=22, tm_min=20, tm_sec=59, tm_wday=0, tm_yday=44, tm_isdst=0)
#時(shí)間元組struct_time:年,月,日,小時(shí),分鐘,秒,一周第幾天(0是周一),一年第幾天,夏令時(shí)
5、獲取格式化時(shí)間
最簡(jiǎn)單的獲取可讀的時(shí)間模式的函數(shù)是asctime():
import time localtime = time.asctime( time.localtime(time.time()) ) print '本地時(shí)間為 :', localtime #本地時(shí)間為 : Mon Feb 13 22:23:57 2017
我們可以使用 time 模塊的 strftime 方法來(lái)格式化日期:
# 格式化成2016-03-20 11:45:39形式
print time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
#2017-02-13 22:25:08
# 格式化成Sat Mar 28 22:24:24 2016形式
print time.strftime('%a %b %d %H:%M:%S %Y', time.localtime())
#Mon Feb 13 22:25:08 2017
# 將格式字符串轉(zhuǎn)換為時(shí)間戳
a = 'Sat Mar 28 22:24:24 2016'
print time.mktime(time.strptime(a, '%a %b %d %H:%M:%S %Y'))
#1459175064.0
python中時(shí)間日期格式化符號(hào):
%y 兩位數(shù)的年份表示(00-99)
%Y 四位數(shù)的年份表示(000-9999)
%m 月份(01-12)
%d 月內(nèi)中的一天(0-31)
%H 24小時(shí)制小時(shí)數(shù)(0-23)
%I 12小時(shí)制小時(shí)數(shù)(01-12)
%M 分鐘數(shù)(00=59)
%S 秒(00-59)
%a 本地簡(jiǎn)化星期名稱(chēng)
%A 本地完整星期名稱(chēng)
%b 本地簡(jiǎn)化的月份名稱(chēng)
%B 本地完整的月份名稱(chēng)
%j 年內(nèi)的一天(001-366)
%U 一年中的星期數(shù)(00-53)星期天為星期的開(kāi)始
%w 星期(0-6),星期天為星期的開(kāi)始
%W 一年中的星期數(shù)(00-53)星期一為星期的開(kāi)始
6、獲取某月日歷
Calendar模塊有很廣泛的方法用來(lái)處理年歷和月歷,例如打印某月的月歷:
import calendar cal = calendar.month(2017, 2) print '以下輸出2017年2月份的日歷:' print cal 以下輸出2017年2月份的日歷: # February 2017 # Mo Tu We Th Fr Sa Su # 1 2 3 4 5 # 6 7 8 9 10 11 12 # 13 14 15 16 17 18 19 # 20 21 22 23 24 25 26 # 27 28
7、time.sleep(secs):推遲調(diào)用線程的運(yùn)行,secs指秒數(shù)。
print('start')
time.sleep(3) # sleep for 3 seconds
print('wake up')
8、datetime包
datetime包是基于time包的一個(gè)高級(jí)包, 為我們提供了多一層的便利。
datetime可以理解為date和time兩個(gè)組成部分。date是指年月日構(gòu)成的日期(相當(dāng)于日歷),time是指時(shí)分秒微秒構(gòu)成的一天24小時(shí)中的具體時(shí)間(相當(dāng)于手表)。
import datetime t = datetime.datetime(2017,2,13,21,30) print(t)#2017-02-13 21:30:00
datetime包還定義了時(shí)間間隔對(duì)象(timedelta)。一個(gè)時(shí)間點(diǎn)(datetime)加上一個(gè)時(shí)間間隔(timedelta)可以得到一個(gè)新的時(shí)間點(diǎn)(datetime)。同理,兩個(gè)時(shí)間點(diǎn)相減會(huì)得到一個(gè)時(shí)間間隔。
t = datetime.datetime(2017,2,13,21,30)
t_next = datetime.datetime(2017,2,13,23,30)
delta1 = datetime.timedelta(seconds = 600)
delta2 = datetime.timedelta(weeks = 3)
print(t + delta1) #2017-02-13 21:40:00
print(t + delta2) #2017-03-06 21:30:00
print(t_next - t) #2:00:00
9、其他模塊:pytz模塊、dateutil模塊
(11)數(shù)學(xué)與隨機(jī)數(shù)
1、math包主要處理數(shù)學(xué)相關(guān)的運(yùn)算。math包定義了兩個(gè)常數(shù):
math.e # 自然常數(shù)e
math.pi # 圓周率pi
2、math包運(yùn)算
math.ceil(x) # 對(duì)x向上取整,比如x=1.2,返回2
math.floor(x) # 對(duì)x向下取整,比如x=1.2,返回1
math.pow(x,y) # 指數(shù)運(yùn)算,得到x的y次方
math.log(x) # 對(duì)數(shù),默認(rèn)基底為e??梢允褂胋ase參數(shù),來(lái)改變對(duì)數(shù)的基地。
math.sqrt(x) # 平方根
3、math包三角函數(shù):
math.sin(x), math.cos(x), math.tan(x), math.asin(x), math.acos(x), math.atan(x)
這些函數(shù)都接收一個(gè)弧度(radian)為單位的x作為參數(shù)。
角度和弧度互換: math.degrees(x), math.radians(x)
4、random包
1) 隨機(jī)挑選和排序
random.choice(seq) # 從序列的元素中隨機(jī)挑選一個(gè)元素
比如random.choice(range(10)) #從0到9中隨機(jī)挑選一個(gè)整數(shù)。
random.sample(seq,k) # 從序列中隨機(jī)挑選k個(gè)元素
random.shuffle(seq) # 將序列的所有元素隨機(jī)排序
2)隨機(jī)生成實(shí)數(shù)
random.random() # 隨機(jī)生成下一個(gè)實(shí)數(shù),它在[0,1)范圍內(nèi)。
random.uniform(a,b) # 隨機(jī)生成下一個(gè)實(shí)數(shù),它在[a,b]范圍內(nèi)。
5、decimal 十進(jìn)制浮點(diǎn)運(yùn)算類(lèi) Decimal
(12)正則表達(dá)式
1、匹配字符串
str.startswith()和str.endswith()
一個(gè)句子結(jié)尾是\n來(lái)結(jié)束的,所以用endswith('’)方法匹配時(shí)要注意傳入的變量帶有\(zhòng)n
或者用切片操作,str[:-1].endswith()
def find(fname): f = open(fname,'r+') for line in f : if line.startswith('this')\ #一個(gè)句子太長(zhǎng)時(shí)使用 \ 符號(hào)來(lái)?yè)Q行 or line[:-1].endswith('apple'): print line find('test1.txt') # this is an apple # this is a pear # this is a banana # that is an apple
2、正則表達(dá)式概念
使用單個(gè)字符串來(lái)描述匹配一系列符合某個(gè)句法規(guī)則的字符串,是對(duì)字符串操作的一種邏輯公式,應(yīng)用場(chǎng)景在處理文本和數(shù)據(jù)。
re 模塊使Python語(yǔ)言擁有全部的正則表達(dá)式功能。
3、導(dǎo)入re模塊 #import re
利用re.compile(正則表達(dá)式)返回pattern
利用pattern.match(待匹配字符串)返回match
match.group()返回子串
match.string()返回主串
match.span()返回子串在主串中的位置
str1 = 'this is an apple'
regex = re.compile(r'this') #r' ’內(nèi)的字符不轉(zhuǎn)義
print regex #<_sre.SRE_Pattern object at 0x0000000001D2DDD8>
ma = regex.match(str1)
print ma #<_sre.SRE_Match object at 0x0000000002075510>
print ma.group() #this
print ma.span() #(0, 4)
print ma.string #this is an apple
print ma.re #=regex
4、re.match 嘗試從字符串的開(kāi)始匹配一個(gè)模式。
re.match(pattern, string, flags=0)
pattern 匹配的正則表達(dá)式
string 要匹配的字符串
flags 標(biāo)志位,用于控制正則表達(dá)式的匹配方式,如:是否區(qū)分大小寫(xiě), 多行匹配等等
匹配成功re.match方法返回一個(gè)匹配的對(duì)象,否則返回None。
5、group(num)或groups()匹配對(duì)象函數(shù)來(lái)獲取匹配表達(dá)式。
group(num=0)匹配的整個(gè)表達(dá)式的字符串,group()可以一次輸入多個(gè)組號(hào),在這種情況下它將返回一個(gè)包含那些組所對(duì)應(yīng)值的元組。
groups()返回一個(gè)包含所有小組字符串的元組。
6、基本匹配符
①. 匹配任意字符(除了\n),一個(gè)點(diǎn)只是一個(gè)字符
②[…] 匹配字符集 如[a-z][A-Z][0-9][a-zA-Z0-9]
③[^…] 匹配不在[]中的任意字符
④\d 匹配數(shù)字等價(jià)于[0-9]
⑤\D 匹配非數(shù)字
⑥\s 匹配空白,包括空格、制表符、換頁(yè)符等等。等價(jià)于[\f\n\r\t\v]
⑦\(yùn)S 匹配非空白
⑧\w 匹配單詞字符,匹配包括下劃線的任何單詞字符。等價(jià)于[A-Za-z0-9_]
⑨\W 匹配非單詞字符
ma = re.match(r'[\w]','0')
print ma.group()#0
ma = re.match(r'\[[\w]\]','[0]')
print ma.group()#[0]
7、特殊匹配符
①* 匹配前一個(gè)字符0次或無(wú)限次
②+ 匹配前一個(gè)字符1次或無(wú)限次
③? 匹配前一個(gè)字符0次或1次
④{m} 匹配前一個(gè)字符m次
⑤{m,n} 匹配前一個(gè)字符m到n次
⑥*?或+?或?? 匹配模式變?yōu)榉秦澙罚ūM可能減少匹配字符)
import re ma = re.match(r'[a-zA-Z0-9]*','SAFGAFG') print ma.group() #SAFGAFG ma = re.match(r'[a-zA-Z0-9]{3,6}@163.com','SAFGFG@163.com') print ma.group() #SAFGFG@163.com ma = re.match(r'[0-9][a-z]*','1bc') print ma.group() #1bc ma = re.match(r'[0-9][a-z]*?','1bc') print ma.group() #1
8、高級(jí)匹配符
①^ 匹配字符串開(kāi)頭
②$ 匹配字符串結(jié)尾
③\A 指定的字符串必須出現(xiàn)在開(kāi)頭
④\Z 指定的字符串必須出現(xiàn)在結(jié)尾
⑤| 或,匹配左右任意一個(gè)表達(dá)式
⑥(ab) 括號(hào)中表達(dá)式作為一個(gè)分組
⑦\(yùn)<number> 引用編號(hào)為num的分組匹配到的字符串
⑧(?P<name>) 分組起一個(gè)別名
⑨(?P=name) 引用別名為name的分組匹配字符串
ma = re.match(r'^[\w]{4,10}@163.com$','abc123@163.com')
print ma.group() #abc123@163.com
ma = re.match(r'\Aabc[\w]*','abc123')
print ma.group() #abc123
ma = re.match(r'[1-9]?\d$','99')#0-99
print ma.group() #99
ma = re.match(r'[1-9]?\d$|100','100')#0-99
print ma.group() #100
ma = re.match(r'[\w]{4,6}@(163|126|qq).com','abc123@qq.com')
print ma.group() #abc123@qq.com
ma = re.match(r'<([\w]+>)[\w]+</\1','<book>python</book>')
print ma.group() #<book>python</book>
ma = re.match(r'<(?P<mark>[\w]+>)[\w]+</(?P=mark)','<book>python</book>')
print ma.group() #<book>python</book>
ma = re.match(r'<(?P<ht>[\w]+>)<(?P<h>[\w]+>)<(?P<s>[\w]+>).+</(?P=s)</(?P=h)</(?P=ht)','<html><head><script>javascript:alect('hello world')</script></head></html>')
print ma.group() #<html><head><script>javascript:alect('hello world')</script></head></html>
print ma.groups() #('html>', 'head>', 'script>')
9、其他方式
①search(pattern,string,flags=0)
會(huì)在字符串內(nèi)查找模式匹配,直到找到第一個(gè)匹配
匹配成功re.search方法返回一個(gè)匹配的對(duì)象,否則返回None
②findall(pattern,string,flags=0)
找到匹配,返回所有匹配部分的列表
③sub(pattern,repl,string,count=0,flags=0)
將字符串中匹配正則表達(dá)式的部分替換為其他值
④split(pattern,string,maxsplit=0,flags=0)
根據(jù)匹配分割字符串,返回分割字符串組成的列表
import re str1 = 'abc = 100' info = re.search(r'\d+',str1) print info.group() #100 str2 = 'c++=100,java=90,python=80' info = re.search(r'\d+',str2) print info.group() #100 info = re.findall(r'\d+',str2) print info #['100', '90', '80'] print sum([int(x) for x in info]) #270 #列表解析 str3 = 'python video = 1000' info = re.sub(r'\d+','1001',str3) #sub是調(diào)用findall而不是search print info #python video = 1001 def add3(match): val = match.group() num = int(val)+3 return str(num) info = re.sub(r'\d+',add3,str3) print info #python video = 1001 str4 = 'class:C C++ JAVA Python C#' info = re.split(r':| |,',str4) print info #['class', 'C', 'C++', 'JAVA', 'Python', 'C#']
10、修飾符
正則表達(dá)式可以包含一些可選標(biāo)志修飾符來(lái)控制匹配的模式。修飾符被指定為一個(gè)可選的標(biāo)志。多個(gè)標(biāo)志可以通過(guò)按位 OR(|) 它們來(lái)指定。
①re.I 使匹配對(duì)大小寫(xiě)不敏感
②re.M 多行匹配,影響 ^和$
③re.S 使.匹配包括換行在內(nèi)的所有字符
11、抓取網(wǎng)頁(yè)中的圖片到本地
1:抓取網(wǎng)頁(yè)
2:獲取圖片地址
3:抓取圖片內(nèi)容并保存到本地
req = urllib2.urlopen('http://www.imooc.com/course/list')
buf = req.read()
listurl = re.findall(r'http:.+\.jpg',buf)
i = 0
for url in listurl:
f = open(str(i)+'.jpg','wb')
req = urllib2.urlopen(url)
buf = req.read()
f.write(buf)
i+=1
print I #看看輸出了多少個(gè),此時(shí)也生成i個(gè).jpg
目前python的主要領(lǐng)域
WEB開(kāi)發(fā)——最火的Python web框架Django, 支持異步高并發(fā)的Tornado框架,短小精悍的flask,bottle, Django官方的標(biāo)語(yǔ)把Django定義為the framework for perfectionist with deadlines(大意是一個(gè)為完全主義者開(kāi)發(fā)的高效率web框架)
網(wǎng)絡(luò)編程——支持高并發(fā)的Twisted網(wǎng)絡(luò)框架, py3引入的asyncio使異步編程變的非常簡(jiǎn)單
爬蟲(chóng)——爬蟲(chóng)領(lǐng)域,Python幾乎是霸主地位,Scrapy\Request\BeautifuSoap\urllib等,想爬啥就爬啥
云計(jì)算——目前最火最知名的云計(jì)算框架就是OpenStack,Python現(xiàn)在的火,很大一部分就是因?yàn)樵朴?jì)算
人工智能——誰(shuí)會(huì)成為AI 和大數(shù)據(jù)時(shí)代的第一開(kāi)發(fā)語(yǔ)言?這本已是一個(gè)不需要爭(zhēng)論的問(wèn)題。如果說(shuō)三年前,Matlab、Scala、R、Java 和 Python還各有機(jī)會(huì),局面尚且不清楚,那么三年之后,趨勢(shì)已經(jīng)非常明確了,特別是前兩天 Facebook 開(kāi)源了 PyTorch 之后,Python 作為 AI 時(shí)代頭牌語(yǔ)言的位置基本確立,未來(lái)的懸念僅僅是誰(shuí)能坐穩(wěn)第二把交椅。
自動(dòng)化運(yùn)維——問(wèn)問(wèn)中國(guó)的每個(gè)運(yùn)維人員,運(yùn)維人員必須會(huì)的語(yǔ)言是什么?10個(gè)人相信會(huì)給你一個(gè)相同的答案,它的名字叫Python
金融分析——我個(gè)人之前在金融行業(yè),10年的時(shí)候,我們公司寫(xiě)的好多分析程序、高頻交易軟件就是用的Python,到目前,Python是金融分析、量化交易領(lǐng)域里用的最多的語(yǔ)言
科學(xué)運(yùn)算—— 你知道么,97年開(kāi)始,NASA就在大量使用Python在進(jìn)行各種復(fù)雜的科學(xué)運(yùn)算,隨著NumPy, SciPy, Matplotlib, Enthought librarys等眾多程序庫(kù)的開(kāi)發(fā),使的Python越來(lái)越適合于做科學(xué)計(jì)算、繪制高質(zhì)量的2D和3D圖像。和科學(xué)計(jì)算領(lǐng)域最流行的商業(yè)軟件Matlab相比,Python是一門(mén)通用的程序設(shè)計(jì)語(yǔ)言,比Matlab所采用的腳本語(yǔ)言的應(yīng)用范圍更廣泛
游戲開(kāi)發(fā)——在網(wǎng)絡(luò)游戲開(kāi)發(fā)中Python也有很多應(yīng)用。相比Lua or C++,Python 比 Lua 有更高階的抽象能力,可以用更少的代碼描述游戲業(yè)務(wù)邏輯,與 Lua 相比,Python 更適合作為一種 Host 語(yǔ)言,即程序的入口點(diǎn)是在 Python 那一端會(huì)比較好,然后用 C/C++ 在非常必要的時(shí)候?qū)懸恍U(kuò)展。Python 非常適合編寫(xiě) 1 萬(wàn)行以上的項(xiàng)目,而且能夠很好地把網(wǎng)游項(xiàng)目的規(guī)??刂圃?10 萬(wàn)行代碼以內(nèi)。另外據(jù)我所知,知名的游戲<文明> 就是用Python寫(xiě)的