寫在前面的話
代碼中的# > 表示的是輸出結(jié)果
輸入
- 使用input()函數(shù)
- 用法
str = input('請輸入內(nèi)容:')
print(str)
#>> 此時控制臺上打印的一定是你輸入的字符串
- 注意
- input函數(shù)輸出的均是字符串烦绳,如需要接收其他類型的變量,就需要使用強制類型轉(zhuǎn)換配紫。
- 例如:將字符串轉(zhuǎn)換為數(shù)字類型的變量
num = input('請輸入數(shù)字:')
print(type(num))
# >> <class 'str'>
#此時可以看見径密,就算輸入數(shù)字類型的變量,num接收的值依然是一個字符串類型
num = int(num) #強制轉(zhuǎn)換為int類型
print(type(num))
# >> <class 'int'>
#此時控制臺返回的是num變量的類型,可以看到,類型已經(jīng)是int了
輸出
- 使用print()函數(shù)
- 用法
#常用用法
print('Hello World!')
# 自定義用法
print(value,sep = ' ',end = '\n')
value表示需要打印的值
sep表示打印多個值之間的分隔符衡蚂,默認是一個空格
end表示打印結(jié)束后的分隔符,默認是\n
變量伪很、函數(shù)戚啥、類命名規(guī)則
- 可以使用數(shù)字奋单、字母、下劃線
- 不可以用數(shù)字開頭
- 不可以使用關(guān)鍵字和保留字
- 推薦駝峰命名法
- 類名使用大駝峰猫十,如MyFirst
- 變量览濒、函數(shù)使用小駝峰,如myFirst
- 也可使用posix寫法拖云,如my_first
常用操作
- type()函數(shù)贷笛,查看當前變量類型
- id()函數(shù),查看當前變量地址
- help()函數(shù)宙项,查找?guī)椭臋n
變量進行賦值
- 單獨賦值
a = 5
b = 'hh'
- 一起賦值
a , b = 5 , 'hh'
- 兩個變量之間的互換
a , b = 5 , 10
#如果遇到JAVA程序員乏苦,會這樣寫
int temp = a
a = b
b = temp
#但是在python中,只需要進行簡單交換即可
a , b = b , a
#通過這種方式就完成了兩個變量值的交換
變量的類型
數(shù)字型(number)
- 整數(shù)(int)
- 二進制
- 八進制
- 十進制
- 十六進制
- 浮點小數(shù)(float)
- 一般采用的是科學計數(shù)法,以e表示10汇荐,e上面為次方
- 布爾值(boolean)
- True洞就,可用數(shù)字表示,除了0以外的數(shù)字都為True
- False掀淘,可用數(shù)字0表示
- 復(fù)數(shù)(complex)
- 一般不會涉及到
字符串型(string)
- 用單引號旬蟋,雙引號或者是三引號進行表示
a = 'Jack'
b = "Jack"
c = "Bob,'haha',Jack"
print(c)
#其結(jié)果為Bob,'haha',Jack
- 格式化的兩種方式
-
利用%
%s : 格式化字符串
%d : 格式化整數(shù)
-
n = '我是XX'
print('你好,%s'%n)
- 利用format()函數(shù)進行格式化
n = '我是XX'
print('你好,{0}'.format(n))
#還可以這么使用
age = 18
name = 'Bob'
print('我是{0},我今年{1}歲,你也{1}歲'.format(name,age))
- 字符串的轉(zhuǎn)義
用"\"表示
最簡單的一種方法就是字符串前面加上"r",表示的是原始字符:字符串中的所有轉(zhuǎn)義字符都不進行轉(zhuǎn)義
-
使用轉(zhuǎn)義字符
\\ : 表示\
\n : 表示換行
\t : 表示制表符
\r : 表示回車
```
print(r'\\')
#打印出的為\\
print('\\\\')
#這樣也可以打印出\\
```
-
常用函數(shù)
capitalize() : 將字符串的第一個字母大寫,其他小寫
strip() : 去掉字符串兩邊的空格
replace() : 替換字符串
lower() : 全部小寫
upper() : 全部大寫
encode() : 編碼
decode() : 解碼
s1 = ' abc ' s2 = 'aBc' s1.strip() # > abc s2.capitalize() # > Abc s2.lower() # > abc s2.upper() # > ABC s2.encode('utf-8') # > b'aBc' b'aBc'.decode('utf-8') # > aBc s2.replace('B','*') # > a*c
列表(list)
-
創(chuàng)建列表的方式
list = [1,2,3,4,5]
-
列表屬于一個可迭代對象,可用于迭代
-
使用for對列表中的元素進行迭代
for item in list: print(item) #此時會輸出 # > 1 # > 2 # > 3 # > 4 # > 5 #item表示的是列表中的元素
-
使用下角標進行操作革娄,但是一般不會這么使用
for i in range(len(list)): print(list[i]) #len()函數(shù)表示測量某個迭代序列的長度倾贰,返回int #range()函數(shù)用于組成從0數(shù)字到給定值的序列
-
-
可使用成員判斷符 in
print(1 in list) # > True
-
可使用 * ,表示一個列表重復(fù)N次拦惋,并組成一個新的列表
print(list * 5) # > [1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
-
可使用 + 匆浙,表示兩個列表相加,組成一個新列表
print(list + [6.7,8]) # > [1, 2, 3, 4, 5, 6,7,8]
-
常用函數(shù)
del: 刪除列表
len(): 長度
max()厕妖、min():最大吞彤、最小值
list() : 將可迭代的序列轉(zhuǎn)化為list
append() : 在列表末尾添加元素
index() : 返回列表中某個元素的引索值
remove() : 移除列表中的某個元素
pop() :移除列表中引索值為XX的元素
insert() : 向列表中引索值為XX的位置添加一個元素
reverse() : 反向列表元素
copy() : 復(fù)制一份列表到新的列表中
list = [1,2,3,4,5] del list # > 刪除list len(list) # > 5 max(list) # > 5 min(list) # > 1 list.append(6) # > [1,2,3,4,5,6] list.index(1) # > 0 list.remove(6) # > [1,2,3,4,5] list.pop(0) # > [2, 3, 4, 5] list.insert(0,7) # > [7, 1, 2, 3, 4, 5] list.reverse() # > [5, 4, 3, 2, 1] l = list.copy # > [1,2,3,4,5]
-
列表生成式
可操作列表中的單個元素,并迭代整個列表組成一個新列表
-
使用方法:list2 = [i for i in list1 if ....]
list1 = [1,2,3,4,5,6,7,8,9] #下面我們使用列表生成式挑選偶數(shù)組成一個新的列表 list2 = [i for i in list1 if i % 2 == 0] # > [2, 4, 6, 8] # i for i in list1 表示遍歷list1列表中的元素 # if i % 2 == 0 表示挑選出所有能整除2的元素
-
列表生成式的嵌套
list1 = [1,2] list2 = [3,4] list3 = [x+y for x in list1 for y in list2] # > [4, 5, 5, 6] #可以看出叹放,新的列表的結(jié)果是list1中的每個元素加上list2中每個元素的結(jié)果 #組成是[list1[0]+list2[0],list1[0]+list2[1],list1[1]+list2[0],list1[1]+list2[1]]
元組(tuple)
-
創(chuàng)建元組的方式
tuple = (1,2,3)
元組具有l(wèi)ist中的部分屬性饰恕,但只可以進行讀取操作,不能進行寫入操作
-
可以將一個list列表轉(zhuǎn)化為一個元組tuple
t = tuple(list)
字典(dict)
-
字典的創(chuàng)建方式
dict = {'jack':24,'bob':18} #或者是 d = dict(jack = 24,bob = 18)
字典是一組鍵——值對應(yīng)序列井仰,它是一個無序的對象埋嵌。
-
遍歷字典
-
使用item()方法遍歷
for key,value in dict.items(): print(key,value) #jack 24 #bob 18
-
直接遍歷
for i in dict: print(i,dict[i]) #jack 24 #bob 18
-
注意,一旦使用dict[key]查找value值俱恶,當key的值不存在時雹嗦,就會報錯,推薦使用get()方法
-
常用方法
get() : 查找對應(yīng)鍵的值合是,當鍵不存在時不會報錯
keys() : 將字典所有key組成一個可迭代的序列
values() : 將字典所有value組成一個可迭代的序列
items() : 將字典的每組key和value組成一個元組了罪,并將所有組組成一個序列,序列的類型是dict_items
fromkeys() : 將一個列表作為key值傳入,并指定默認的value值
dict.get('jack') # > 24 dict.keys() # > dict_keys(['jack', 'bob']) dict.values() # > dict_values([24, 18]) dict.items() # > dict_items([('jack', 24), ('bob', 18)]) list = ['jack', 'bob'] d = dict.fromkeys(list , 18) # > {'jack': 18, 'bob': 18}
集合(set)
-
定義方式
list = [1,2,3,4,4] s = set(list) # > {1, 2, 3, 4} #或者是 s = {1,2,3,4}
注意:不要與dict字典搞混淆聪全,字典也是{}定義的泊藕,但是卻是由key-value組成的一對
set集合中數(shù)據(jù)也是無序的,且不包含重復(fù)元素难礼,必須是可哈希數(shù)據(jù)
-
常用函數(shù)
add() : 添加單個數(shù)據(jù)
update : 添加可迭代數(shù)據(jù)
remove() : 移除集合中某個值娃圆,一旦值不存在,便會報錯
discard() : 移除集合中某個值蛾茉,就算值不存在讼呢,也不會報錯
clear() : 清空集合數(shù)據(jù)
intersection() : 求交集
difference() : 求差集
union() : 求并集
issubset() : 檢查一個集合是否是另一個集合的子集
issuperset() : 檢查一個集合是否是另一集合的超集
s = {1,2,3,4,5} s1 = {4,5,6,7,8} list = [5,6,7,8,9] s.add(6) # > {1,2,3,4,5,6} s.update() # > {1, 2, 3, 4, 5, 6, 7, 8, 9} s.remove(5) # > {1,2,3,4} s.discard(5) # > {1,2,3,4} s.clear() s.intersection(s1) # > {4, 5} s.difference(s1) # > {1, 2, 3} s.union(s1) # > {1, 2, 3, 4, 5, 6, 7, 8}
運算符
算數(shù)運算符
-
加法運算符 +
-
在數(shù)字中表示兩個數(shù)字相加
print(2+5) # > 7
-
在字符串中表示兩個字符串相連
print('hello'+'world') # > helloworld
-
在列表中表示兩個列表首尾相連
l1 = [1,2,3] l2 = [3,4,5] l = l1 + l2 # > [1,2,3,3,4,5]
-
-
減法運算符 -
print(5 - 3) # > 2
-
乘法運算符 *
-
當對象為數(shù)字型時,執(zhí)行乘法運算
print(5 * 2) # > 10
-
當對象為非數(shù)字型時谦炬,打印N次,并組成一個新對象
print('a'*3) # > aaa print([1,2,3] * 2) # > [1, 2, 3, 1, 2, 3]
-
-
除法運算符 /
print(6 / 2) # > 3
-
取余運算符 %
- 計算兩個數(shù)字的余數(shù)
print(3 % 2) # > 1
- 計算兩個數(shù)字的余數(shù)
-
整除運算符 //
-
計算兩個數(shù)整除的數(shù)字悦屏,不會保留小數(shù)點
print( 3 // 2 ) # > 1
-
-
冪運算符 **
-
次方運算
print(2 ** 3) # > 8
-
比較運算符
注意:返回的都為布爾值類型
-
等于 ==
print(1 == 1) # > True
-
不等于 !=
print(1 != 1) # > False
-
小于 <
print(1 < 1) # > False
-
小于等于 <=
print(1 <= 1) # > True
-
大于 >
print(1 > 1) # > False
-
大于等于 >=
print(1 >= 1) # > True
賦值運算符
- 等于 =
邏輯運算符
- and 與
print(True and False) # > False
- or 或
print(True and False) # > True
- not 非
s = 'abc' print('d' not in s) # > True
成員運算符
注意:成員運算符需要判斷的對象是一個可以迭代的類型
-
in 在里面
print('a' in 'abc') # > True
-
not in 不在里面
print('a' not in 'abc') # > False
身份運算符
- 注意,身份運算符是比較兩個對象內(nèi)存地址是否相同
- is 是
- not is 不是
運算符的優(yōu)先級
- 永遠記住,括號里面的最先開始運算础爬,具有最高優(yōu)先級
程序結(jié)構(gòu)
順序結(jié)構(gòu)
- 按照代碼編寫的方式逐行進行
分支散劫、判斷結(jié)構(gòu)
- if...else語句
a = 10 b = 5 if a > b: print(a,'>',b) else: print(a,'<',b) # > 10 > 5
- if..elif..else語句
- 注意,以上代碼并不嚴謹幕帆,缺少相等的時候
a = 10 b = 10 if a > b: print(a,'>',b) elif: print(a,'=',b) else: print(a,'<',b) # > 10 = 10
循環(huán)結(jié)構(gòu)
- 使用for進行循環(huán)(知道具體循環(huán)次數(shù)的時候)
s = 'abcdefg' for i in s: print(i) # > a # > b # > c # > d # > e # > f # > g
- 使用while進行循環(huán)(不知道具體循環(huán)次數(shù))
- while
n = 0 while n < 10: print(n) n = n + 1 # > 0 # > 1 # > 2 # > 3 # > 4 # > 5 # > 6 # > 7 # > 8 # > 9
- while
- break 跳出整個循環(huán)
- 當需要跳出整個循環(huán)的時候可以用break
n = 1 while n < 10: print(n) n = n + 1 if n == 3: break # > 1 # > 2
- 當需要跳出整個循環(huán)的時候可以用break
- continue 結(jié)束本次循環(huán)
- 當某些條件時获搏,跳過本次循環(huán)
n = 0 while n < 10: n = n + 1 if n == 3: continue print(n) # > 1 # > 2 # > 4 # > 5 # > 6 # > 7 # > 8 # > 9 # > 10
- 當某些條件時获搏,跳過本次循環(huán)
函數(shù)
定義函數(shù)
-
使用def進行定義,后面跟著方法名和()
def func(): print('hello')
調(diào)用,傳入函數(shù)
- 調(diào)用函數(shù)時失乾,用函數(shù)名加括號
#調(diào)用函數(shù) func() # > hello
- 傳參時常熙,只用函數(shù)名
#如tk框架中綁定按鈕事件 button = Button(text = '按鈕' ,command = func) #如使用help函數(shù) print(help(print)) # > Help on built-in function print in module builtins: # > print(...) # > print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False) # > Prints the values to a stream, or to sys.stdout by default. # > Optional keyword arguments: # > file: a file-like object (stream); defaults to the current sys.stdout. # > sep: string inserted between values, default a space. # > end: string appended after the last value, default a newline. # > flush: whether to forcibly flush the stream. # > None
函數(shù)的參數(shù)
-
位置參數(shù)
- 根據(jù)定義函數(shù)時參數(shù)的位置,自動進行參數(shù)傳遞碱茁,此時裸卫,必須嚴格按照參數(shù)的順序進行傳參
def func(name,age): print('my name is {0},I am {1} years old.'.format(name,age)) func('jack',24) # > my name is jack,I am 24 years old. # 此時傳遞參數(shù)的順序必須是name,age纽竣,否則參數(shù)就會傳遞不正確墓贿,嚴重時,會報錯
- 根據(jù)定義函數(shù)時參數(shù)的位置,自動進行參數(shù)傳遞碱茁,此時裸卫,必須嚴格按照參數(shù)的順序進行傳參
-
關(guān)鍵字參數(shù)
- 根據(jù)指定的關(guān)鍵字進行傳遞參數(shù)蜓氨,傳參的順序是否正確聋袋,不會影響函數(shù)的參數(shù)傳遞
def func(name,age): print('my name is {0},I am {1} years old.'.format(name,age)) func(age = 24,name = 'jack') # > my name is jack,I am 24 years old.
- 根據(jù)指定的關(guān)鍵字進行傳遞參數(shù)蜓氨,傳參的順序是否正確聋袋,不會影響函數(shù)的參數(shù)傳遞
-
默認參數(shù)
- 在定義函數(shù)時,就傳遞默認值穴吹,被傳遞默認值的參數(shù)如果不進行再次傳參幽勒,就會使用默認值
def func(name,age = 0): print('my name is {0},I am {1} years old.'.format(name,age)) func('jack') # > my name is jack,I am 0 years old. func('jacl',24) # > my name is jack,I am 24 years old.
- 在定義函數(shù)時,就傳遞默認值穴吹,被傳遞默認值的參數(shù)如果不進行再次傳參幽勒,就會使用默認值
可變參數(shù)
-
解包:是將可迭代的對象變?yōu)閱蝹€元素
-
明確一個概念,可迭代的對象可以進行解包操作港令,而且可以不使用解包的操作符號
list = [1,2,3] a , b , c = list # > 1 # > 2 # > 3 #可以看出啥容,對于一個知道長度的可迭代對象我們可以用賦值的方式將其解包
-
使用*對可迭代的對象進行解包
#但如果對于一個我們不知道長度的列表如何進行解包呢? #這就是*的用法 list = [1,2,3,4] print(*list) # > 1 2 3 4 #可以看出顷霹,此時列表list已經(jīng)被用*解包為單個元素
-
使用**對字典進行解包
#首先我們使用*對dict解包咪惠,看能得到什么? dict = {'jack':24 , 'bob':18} print(*dict) # > jack bob # 結(jié)論:使用*進行解包時淋淀,我們只是得到了字典的key值 # 那我們試試**吧 print(**dict) # > TypeError: 'jack' is an invalid keyword argument for this function # 百度后得知print()函數(shù)不支持打印**對象 # 那就試試打印出key對應(yīng)的值 print('{jack},{bob}'.format(**dict)) # > 24,18 #參考網(wǎng)上資料遥昧,**dict解包之后應(yīng)該是這樣的 **dict = Jack = 24 , bob = 18 #現(xiàn)在你想到了什么?
-
-
壓包绅喉,將幾個不同的可迭代對象的單個元素按順序用元組的形式結(jié)合成一個列表
- 使用zip()函數(shù)進行壓包
list1 = [1,2,3] list2 = ['a','b','c'] list3 = ['one','two','three'] for i in zip(list1,list2,list3): print(i) # > (1, 'a', 'one') # > (2, 'b', 'two') # > (3, 'c', 'three') # 可以看出這里對每個列表的第一元素渠鸽、第二個元素叫乌、第三個元素柴罐,都進行了組合,使之成為了了一個新的元組 a = zip(list1 ,list2 ,list3 ) print(list(a)) # > [(1, 'a', 'one'), (2, 'b', 'two'), (3, 'c', 'three')] #可以看出憨奸,將三個序列壓包后革屠,每個序列中下標相同的元素,重新組成了一個元組,而這些元組都構(gòu)成了一個列表
- 使用zip()函數(shù)進行壓包
-
可變參數(shù)函數(shù)
- 了解了*解包之后我們就可以明白函數(shù)的可變參數(shù)是怎么回事了
- 定義一個可變參數(shù)的函數(shù)
#注意:這里args可以是任何變量似芝,但為了程序的可讀性那婉,我們需要遵循傳統(tǒng),寫上args党瓮,讓其他人一看就知道這里應(yīng)該是可變參數(shù) def func(*args): print(args) func('jack','hello',28,41) # >('jack', 'hello', 28, 41) #可以看出我們不論寫多少參數(shù)详炬,函數(shù)就會接收多少個參數(shù),看到這里你也許會說寞奸,這并沒有什么用扒好铡? #是的枪萄,但是你想想如果我們需要將一個列表的元素都傳入函數(shù)中去的時候要怎么辦隐岛? #總不能用list[0],list[1]...一個一個進行傳參吧? list = ['name','age','sex','birth'] func(*list) # > ('name', 'age', 'sex', 'birth') #可以看出瓷翻,*list確實是將單個元素傳入了函數(shù)中
- 可變參數(shù)的關(guān)鍵字函數(shù)
#剛才對字典解包后得出**dict = Jack = 24 , bob = 18 #仔細一想聚凹,如果把**dict當成參數(shù),這不就是一個關(guān)鍵字參數(shù)嘛
- 定義一個可變參數(shù)的關(guān)鍵字函數(shù)
def func(**kwargs): print('我的名字是{0},我今年{1}齐帚,我是{2}妒牙,我的生日是{3}'.format(kwargs.get('name'),kwargs.get('age'),kwargs.get('sex'),kwargs.get('birth'))) func(name = 'jack',age = 24 ,sex = 'male',birth = '1980-10-10') # > 我的名字是jack,我今年24,我是male对妄,我的生日是1980-10-10 #定義一個字典傳入函數(shù)中 dict = {'name':'jack','age':24} func(**dict) # > 我的名字是jack,我今年24单旁,我是None,我的生日是None # 可以看出饥伊,即使有些參數(shù)是不填的函數(shù)也可以正常運行象浑,這是不可變參數(shù)函數(shù)所不能達到的效果
-
參數(shù)混用
- 需要遵照函數(shù)(位置函數(shù),關(guān)鍵字函數(shù)琅豆,可變參數(shù)函數(shù)愉豺,可變參關(guān)鍵字函數(shù))的順序進行
def func(name , age = 24 , *args , **kwargs): pass
- 需要遵照函數(shù)(位置函數(shù),關(guān)鍵字函數(shù)琅豆,可變參數(shù)函數(shù)愉豺,可變參關(guān)鍵字函數(shù))的順序進行
函數(shù)的返回值
- 所有函數(shù)都有返回值,表示函數(shù)調(diào)用已經(jīng)結(jié)束
- 定義函數(shù)返回值,使用return
def func(a): return a+10 b = func(1) # > 11
- 即使沒有定義return茫因,解釋器也會自動加上 return None
函數(shù)文檔
當使用help()函數(shù)時蚪拦,顯示的幫助文檔
也可以使用doc調(diào)用文檔
當你在不知道怎么使用函數(shù)或者是類時,都可以調(diào)用幫助文檔冻押,里面會給你詳細說明各種用法
-
自定義函數(shù)幫助文檔驰贷,在開頭加上''' '''即可,如果使用的ide洛巢,會自動給你加上其他參數(shù)
def func(x,y): ''' 這個函數(shù)什么也不做 :param x: 傳參x :param y: 傳參y :return: None ''' pass print(help(func)) # > Help on function func in module __main__: # > func(x, y) # > 這個函數(shù)什么也不做 # > :param x: 傳參x # > :param y: 傳參y # > :return: None # > None print(func.__doc__) # > 這個函數(shù)什么也不做 # > :param x: 傳參x # > :param y: 傳參y # > :return: None
高階函數(shù)
指該函數(shù)的參數(shù)中傳入另一個函數(shù)
-
map()函數(shù)括袒,映射操作,將傳入的函數(shù)作用于可迭代對象的每個元素上,返回一個可以迭代的map對象
list = [1,2,3,4] def func(x): return x+1 a = map(func,list) for i in a: print(i) # > 2 # > 3 # > 4 # > 5
-
reduece()函數(shù),歸并操作,將列表的兩個值經(jīng)過函數(shù)計算后與列表中的第三個值再次進行相同計算稿茉,直到列表元素完成循環(huán)锹锰。
-
簡單的用公式表達就是這樣芥炭,f(f(f(x1,x2)恃慧,x3)园蝠,x4)....
#計算列表中所有元素的乘積 from functools import reduce def func(x,y): return x*y list = [2,3,4] print(reduce(func,list)) # > 24
-
-
filter()函數(shù),過濾操作,用于篩選列表中的元素
#篩選出列表中的偶數(shù) def func(x): if x % 2 == 0: return True else: return False list = [2,3,4] for i in filter(func,list): print(i) # > 2 # > 4
-
sorted()函數(shù)痢士,排序操作,可以使用自定義的函數(shù)進行排序
-
默認排序
list = [5,4,3,9,8] l = sorted(list) print(l) # > [3, 4, 5, 8, 9]
-
關(guān)鍵字排序
關(guān)鍵字彪薛, key = 函數(shù)名
反向排序,傳入reverse = True
#將列表的元素按絕對值大小進行排序并倒序 list = [5,-11,6,9,1] l = sorted(list, key=abs,reverse = True) print(l) # > [-11, 9, 6, 5, 1]
-
-
zip()函數(shù)怠蹂,壓縮操作陪汽,將多個傳入的列表每個下標相同的元素組成一個新的元組,再將這些元組組成一個可迭代的zip對象褥蚯,返回zip對象
- 注意 : 如果傳入列表的長度不一致挚冤,那么zip操作只會取最短的那個列表的長度,組成zip對象
l1 = [1,2,3,4] l2 = ['a','b','c','d'] l3 = ['one','two','three','four'] l = zip(l1,l2,l3) for i in l: print(i) # > (1, 'a', 'one') # > (2, 'b', 'two') # > (3, 'c', 'three') # > (4, 'd', 'four') # 如果用列表生成式會怎么樣赞庶? list = [i for i in l] print(list) # > [(1, 'a', 'one'), (2, 'b', 'two'), (3, 'c', 'three'), (4, 'd', 'four')] #長度不一致時 l4 = ['jack','bob'] l5 = zip(l1,l4) list = [i for i in l5] print(list) # > [(1, 'jack'), (2, 'bob')]
-
enumerate()函數(shù)训挡,將列表中每個引索值和其對應(yīng)的元素組成一個新的元組,再將這些元組組成一個enumerate對象歧强,返回enumerate對象
l = ['a','b','c','d'] em = enumerate(l) list = [i for i in em] print(list) # > [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]
返回函數(shù)
-
將函數(shù)作為返回結(jié)果
def hello(): def say(): print('hello') return say f = hello() print(f) # > <function hello.<locals>.say at 0x00000233A6EF8A60> f() # > hello
-
閉包,當一個函數(shù)定義在另一個函數(shù)的內(nèi)部時,使用外部函數(shù)的變量或者參數(shù),當這個內(nèi)部函數(shù)被當做返回值時,外部函數(shù)的所有參數(shù)和變量都保存在返回的函數(shù)中時,就叫做閉包
def hello(n): def say(): print(n) return say f = hello('hello') f() # > hello
-
注意:在返回函數(shù)中不能引用循環(huán)變量,如果確實需要引用循環(huán)變量時,需要在內(nèi)部函數(shù)外面再包裹一層函數(shù),該函數(shù)以參數(shù)的形式接受循環(huán)變量,內(nèi)部函數(shù)就可以安全使用循環(huán)變量
def func(): list = [] for i in range(1,4): def funb(): return i * i list.append(funb) return list list = func() print(list) # > [<function func.<locals>.funb at 0x000001F1CE5A8A60>, <function func.<locals>.funb at 0x000001F1CE5A8AE8>, <function func.<locals>.funb at 0x000001F1CE5A8B70>] for i in list: print(i()) # > 9 # > 9 # > 9 #此時可以看出,循環(huán)變量并沒有正確的引入返回函數(shù)中去. #正確的寫法應(yīng)該是使用funb將funa包裹,然后通過funb 返回fana 的返回值 def func(): def funb(i): def funa(): return i * i return funa list = [] for i in range(1,4): list.append(funb(i)) return list list = func() print(list) # > [<function func.<locals>.funb.<locals>.funa at 0x000001E2944C8AE8>, <function func.<locals>.funb.<locals>.funa at 0x000001E2944C8B70>, <function func.<locals>.funb.<locals>.funa at 0x000001E2944C8BF8>] for i in list: print(i()) # > 1 # > 4 # > 9
匿名函數(shù)
- lambda澜薄,用于自定義一個函數(shù),此函數(shù)沒有名稱摊册,比如可以向高級函數(shù)中傳遞這樣一個匿名函數(shù)肤京,而不必去定義它
#將每個元素的前面加上hello
list = ['jack','bob','luce','alice']
l = map(lambda x:'hello'+x,list)
for i in l:
print(i)
# > hellojack
# > hellobob
# > helloluce
# > helloalice
偏函數(shù)
偏函數(shù),將一個函數(shù)中的參數(shù)固定住茅特,然后創(chuàng)建一個新的函數(shù)忘分,這就是偏函數(shù)
定義偏函數(shù):
偏函數(shù)名 = functools.partial(原函數(shù),固定值)
#假設(shè)白修,我們有'jack','bob','luce','alice'妒峦,這4個人,他們的年齡都是24歲
# 此時有一個函數(shù)say,是為了介紹自己兵睛,需要傳入name和age兩個參數(shù)
# 希望在不改變say函數(shù)的情況下肯骇,簡化操作,此時我們就可以使用偏函數(shù)了
import functools
list = ['jack','bob','luce','alice']
def say(name,age):
print('My name is {0},age is {1}'.format(name,age))
say24 = functools.partial(say,age = 24)
for person in list:
say24(person)
# > My name is jack,age is 24
# > My name is bob,age is 24
# > My name is luce,age is 24
# > My name is alice,age is 24
遞歸函數(shù)
- 函數(shù)內(nèi)部自己調(diào)用自己的情況叫做遞歸函數(shù)
#遍歷一個盤符下的所有文件(包括子文件夾祖很、文件)
import os
def getFile(path):
try:
filelist = os.listdir(path) #得到該文件夾下的所有文件
for file in filelist:
file = os.path.join(path,file) #將文件名和路徑結(jié)合起來
if os.path.isdir(file):
getFile(file) #在這里如果判斷一個文件是文件夾笛丙,那么就會再次調(diào)用自己
else:
print(file)
except:
print('出錯,跳過')
getFile(r'd:/')
裝飾器
對原函數(shù)進行擴展功能但是不改變原函數(shù)
使用@+裝飾器名進行裝飾,具有固定格式
-
使用@裝飾時假颇,執(zhí)行函數(shù)時胚鸯,相當于執(zhí)行行了裝飾器函數(shù)(原函數(shù))
#首先我們思考一下,接收一個無參數(shù)的函數(shù)啊终,并且擴展功能后返回這個函數(shù) import time def printTime(f): print('Time: ', time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())) return f def hello(): print('hello') print(printTime(hello)()) # > Time: 2018-08-09 08:45:25 # > hello # > None # 這時,我們可以看到定義了一個printTime函數(shù)愧哟,并且執(zhí)行打印時間后返回原函數(shù)甘改,這可以說是一個最簡單的裝飾器了榄融。 # 為什么會返回一個None跌前?我認為是hello函數(shù)后系統(tǒng)自己添加了一個return None后導(dǎo)致的田弥,我們將hello函數(shù)手動添加return 5后試試辜妓,結(jié)果返回的是5 # 如果我們需要接收一個帶參數(shù)的函數(shù)呢? import time def printTime(f): def wrapper(*args,**kwargs): print('Time: ',time.strftime('%Y-%m-%d %H:%M:%S',time.localtime())) return f(*args,**kwargs) return wrapper @printTime def hello(): print('hello') hello() # > Time: 2018-08-08 20:21:26 # > hello # printTime函數(shù)接收一個函數(shù),返回一個wrapper函數(shù) # wrapper函數(shù)接收可變參數(shù)硫戈,然后將這些參數(shù)賦值給printTime接收到的函數(shù)释牺,最后再返回這個函數(shù)。
高級特性
切片 slice
切片操作是對一個可迭代的對象進行切割,并組成一個新的迭代對象
方式:
切片對象[開始引索:結(jié)束引索:步長]
注意:切片操作中包含開始引索验游,不包含結(jié)束引索伞鲫,如果開始引索是0,可以省略甫何,如果步長是1,也可以省略
開始引索也可以是負數(shù)霎迫,當為負數(shù)時斋枢,則從最后開始計算
list = [1,2,3,4,5,6,7,8,9,10]
#挑選出所有奇數(shù)
print(list[:9:2])
# > [1, 3, 5, 7, 9]
#取前4個數(shù)
print(list[:4])
# > [1, 2, 3, 4]
#取后2個數(shù)
print(list[-2:])
# > [9, 10]
#取3~7
print(list[2:7])
# > [3, 4, 5, 6, 7]
迭代
- 使用for進行迭代
列表生成式
- 見list列表中
generator生成器
- 存疑
類
思想
- OO面向?qū)ο?/li>
- OOA面向?qū)ο蟮姆治?/li>
- OOD面向?qū)ο蟮脑O(shè)計
- OOI面向?qū)ο蟮膶崿F(xiàn)
- OOP面向?qū)ο蟮木幊?/li>
類和對象
-
類
類是一個抽象的名詞,是共性事物
類有成員屬性女气,是表明事物的特征杏慰,可以被讀取测柠,寫入炼鞠,刪除
類有成員函數(shù)蹋砚,表明事物的功能或者動作
-
對象
對象是一個具體的名詞平匈,是一個具體事物
對象是類的實例化
說明:我們都是人拄踪,這就是類芜果;但我們有男人俐芯,也有女人量愧,每個人高矮胖瘦都不一樣柑土,我們每個人就是對象慢哈,是類的實例化
-
類和對象的對成員訪問順序
首先訪問對象中的成員
對象沒有成員的會訪問類中的成員
類中沒有成員會訪問父類中的成員
依次向上遞推
定義類
用
class 類名(繼承類):
定義類中只允許出現(xiàn)成員屬性和成員方法
定義類之后榛斯,會在內(nèi)存中專門劃分一塊地方儲存類和類的成員观游;當實例化類之后,繼承的成員會指向內(nèi)存中的這塊地方
class Person(object):
#定義屬性
name = 'NoName'
age = 0
#定義函數(shù)
def say(self):
print('say')
def eat(self):
print('eat')
def sleep():
print('sleep')
-
self
self不是一個關(guān)鍵字驮俗,可以是任何一個變量代替懂缕,表示的是當前對象本身,當調(diào)用方法時,對象會將自己傳入到方法中去
-
有self的函數(shù)稱為非綁定方法王凑,可以通過對象進行訪問
-
使用實例化對象訪問
p = Person() p.say() # > say
-
使用
類().方法
訪問Person().say() # > say
-
使用
類.方法(類())
訪問Person.say(Person()) # > say
實質(zhì)是都是需要實例化一個對象搪柑,并傳入非綁定方法中去
-
-
無self的函數(shù)稱為綁定方法,只能通過類進行訪問
p = Person() p.sleep # > TypeError: sleep() takes 0 positional arguments but 1 was given #可以看出索烹,綁定方法不可以用對象進行訪問工碾,因為方法中沒有定義傳入對象本身的參數(shù),所以出現(xiàn)了sleep函數(shù)不需要參數(shù)百姓,但傳入了一個參數(shù)渊额,傳入的參數(shù)就是對象本身 Person.sleep() # > sleep
- 如果一定要使用對象訪問,可用
對象.__class__.方法
訪問p.__class__.sleep() # > sleep
- 如果一定要使用對象訪問,可用
-
super
super也不是一個關(guān)鍵字,但他是一個類
作用是獲取MRO列表中的第一個類
可以使用
類.__mro__
獲取類的MRO列表在單繼承中旬迹,表示父類
在多繼承中焦读,代表了了MRO列表中的第一個元素代表的類
面向?qū)ο?/h2>
-
封裝,對類的成員訪問進行限制
-
public 公開
- 公開成員舱权,都可以進行訪問
-
protected 受保護
受保護成員矗晃,只能在類、子類宴倍、對象中進行訪問
定義:使用_成員
進行定義
class Person():
_name = 'NoName'
_age = 24
class Student(Person):
pass
s = Student()
print(s._name,s._age)
# > NoName 24
#可以看出张症,子類和子類的對象訪問都是沒有問題的
-
private 私有
私有成員,只能在當前類中進行訪問
注意:子類不繼承私有成員
定義:使用__成員
進行定義
class Person():
__name = 'NoName'
__age = 24
class Student(Person):
pass
p = Person()
print(p.__name, p.__age)
# > AttributeError: 'Person' object has no attribute '__name'
s = Student()
print(s.__name, s.__age)
# > AttributeError: 'Student' object has no attribute '__name'
#可以看出鸵贬,子類并沒有繼承父類中的私有屬性,而且對象也不允許使用私有成員
-
繼承
-
類成員擴充俗他,當子類繼承了父類時,就擁有了父類除私有成員以外的所有其他成員阔逼,這相當于將子類成員指向父類成員的地址兆衅,同時,還可以繼續(xù)添加相應(yīng)的屬性和函數(shù)
class Person():
def talk(self):
print('talk')
class Student(Person):
def study(self):
print('study')
s = Student()
s.talk()
# > talk
s.study()
# > study
-
子類擴充父類函數(shù)方法
-
使用self嗜浮,其中self指的是子類本身
class Person():
def talk(self):
print('talk')
class Student(Person):
def talk(self):
Person.talk(self)
print('擴充函數(shù)')
s = Student()
s.talk()
# > talk
# > 擴充函數(shù)
-
使用super羡亩,指的是父類
class Person():
def talk(self):
print('talk')
class Student(Person):
def talk(self):
super().talk()
print('擴充函數(shù)')
s = Student()
s.talk()
# > talk
# > 擴充函數(shù)
-
MRO鉆石繼承\(zhòng)菱形繼承(繼承順序)
子類永遠在父類前面
根據(jù)括號內(nèi)繼承的順序存放
繼承的多個類中,有共同的父類危融,子類只會繼承括號中第一個父類的父類
-
單繼承
單繼承隱患少畏铆,但不利于擴展功能
子類如果沒有構(gòu)造函數(shù),則會查找父類的構(gòu)造函數(shù)吉殃,如果都沒有辞居,那么就一直向上查找。按照MRO順序
class Person():
def talk(self):
print('talk')
class Student(Person):
def talk(self):
super().talk()
print('asdasd')
print(Student.mro())
# > [<class '__main__.Student'>, <class '__main__.Person'>, <class 'object'>]
#可以看出蛋勺,Student類的MRO順序為Student瓦灶、Person、object
-
多繼承
擴展類的功能方便但隱患多
繼承方式按照MRO順序
class Animal():
def sleep(self):
print('sleep')
class Person():
def talk(self):
print('talk')
class Student(Person,Animal):
pass
s = Student()
s.talk()
s.sleep()
# > talk
# > sleep
print(Student.mro())
#[<class '__main__.Student'>, <class '__main__.Person'>, <class '__main__.Animal'>, <class 'object'>]
#可以看出繼承順序遵照MRO順序
-
Mixin設(shè)計模式
我認為主要是為了避免繼承關(guān)系的混亂抱完,為了讓代碼可以進行更改的維護贼陶,已經(jīng)實現(xiàn)類中方便的功能增減
Mixin類中必須定義單一功能
子類不繼承Mixin類,只是缺少某項功能乾蛤,但不影響子類的正常使用
Mxin功能不依賴子類進行實現(xiàn)
class TalkMixin():
def talk(self):
print('talk')
class EatMixin():
def eat(self):
print('eat')
class SleepMixin():
def sleep(self):
print('sleep')
class Person(TalkMixin,EatMixin,SleepMixin):
pass
p = Person()
p.talk()
p.eat()
p.sleep()
# >talk
# >eat
# >sleep
-
多態(tài)
同一對象在不同狀態(tài)的不同功能
注意:在Python中沒有對應(yīng)的語法
類的實例化
- 方法:
變量 = 類名()
訪問類
檢查類中的所有成員每界,使用類名.__dict__
訪問類的成員屬性,使用類名.屬性
訪問類的成員函數(shù)家卖,使用類名.函數(shù)名()
類的函數(shù)
-
魔法函數(shù)(不需要自己進行調(diào)用眨层,但滿足某些特定條件時,會自動調(diào)用)
-
__init__
構(gòu)造方法
在實例化類的時候可以向其中傳遞參數(shù)
在將類實例化對象時上荡,會自動調(diào)用
此函數(shù)也可以進行擴充
class Person():
def __init__(self,name,age):
self.name = name
self.age = age
def say(self):
print('My name is {0},I am {1} years old.'.format(self.name,self.age))
p = Person('jack',24)
p.say()
# > My name is jack,I am 24 years old.
p.name = 'bob'
p.age = 18
p.say()
# > My name is bob,I am 18 years old.
-
__call__
方法
- 將對象當做函數(shù)執(zhí)行時調(diào)用
class Person():
def __init__(self,name,age):
self.name = name
self.age = age
def __call__(self, *args, **kwargs):
print('為什么要執(zhí)行我趴樱?')
p = Person('jack',24)
p()
# > 為什么要執(zhí)行我馒闷?
-
__str__
方法
- 將對象打印時,輸出的方法
class Person():
def __str__(self):
return '打印了一個Person類的實例'
p = Person()
print(p)
# > 打印了一個Person類的實例
-
實例方法
也就是非綁定方法叁征,只有當類實例化后纳账,才可以使用的方法
詳情參照self-非綁定方法
-
靜態(tài)方法
采用@staticmethod裝飾
里面沒有self參數(shù)
-
注意,這里和綁定方法有區(qū)別
綁定方法捺疼,只能通過類名.方法名()
調(diào)用疏虫,如果采用對象調(diào)用就會報錯
靜態(tài)方法,既可以通過類來調(diào)用啤呼,也可以通過對象調(diào)用
class Person():
@staticmethod
def say():
print('say')
p = Person()
Person.say()
# > say
p.say()
# > say
-
類方法
采用@classmethod裝飾
不需要實例化就可以使用
方法中傳入的是cls卧秘,也就是類對象
class Person():
@classmethod
def say(cls):
print('say')
p = Person()
Person.say()
p.say()
-
總結(jié):無論是實例方法、靜態(tài)方法官扣、類方法都可以使用對象進行調(diào)用翅敌,但是實例方法必須實例化后才可以使用;靜態(tài)方法惕蹄、類方法可以直接用類名進行調(diào)用
-
注意:靜態(tài)方法不是綁定方法
-
property
- 主要是將對函數(shù)的訪問裝飾起來變?yōu)閷傩缘脑L問
#例如蚯涮,我們需要定義一個Person類,但是需要對Person類中傳入的幾個屬性進行檢查卖陵,那么這時候property就派上用場了
class Person():
_name = 'Noname'
_age = 0
#此時遭顶,我們想對age的值進行檢查,不允許小于0
#我們就可以定義一個property的裝飾器赶促,將函數(shù)偽裝為變量進行訪問
-
調(diào)用Property裝飾器
@property
def age(self):
print('調(diào)用get')
return self._name
@age.setter
def age(self,value):
print('調(diào)用set')
if value > 0:
self._age = value
else:
print('不允許負值')
@age.deleter
def age(self):
print('調(diào)用del')
del (self._age)
p = Person()
p.age = -15
# > 調(diào)用get
# > 不允許負值
-
調(diào)用property方法屬性 = property( fget, fset, fdel, doc)
def get_age(self):
print('調(diào)用get_age')
return self._age
def set_age(self,value):
print('調(diào)用set_age')
if value > 0:
self._age = value
else:
print('不允許是負值')
def del_age(self):
print('調(diào)用del_age')
del self._age
age = property(get_age,set_age,del_age)
p = Person()
p.age = -15
# > 調(diào)用get
# > 不允許是負值
-
類的描述符
只要包含了__get__
液肌、__set__
、__del__
三個方法中的一個就是描述符
描述符的作用鸥滨,對類的屬性進行限制操作
-
__get__(self,instance,owner)
方法和__set__(self, instance, value)
方法
class Dscrip():
def __init__(self,property_name):
self.property_name = property_name
def __get__(self, instance, owner):
print('調(diào)用了get方法')
print('self:%s'%self)
print('*'*20)
print('instance:%s'%instance)
print('*' * 20)
print('owner:%s'%owner)
print('-'*20)
def __set__(self, instance, value):
print('調(diào)用了set方法')
print('self:%s' % self)
print('*' * 20)
print('instance:%s' % instance)
print('*' * 20)
print('value:%s'%value)
print('-' * 20)
class Person():
name = 'Noname'
age = Dscrip('age')
def __init__(self,name,age,sorce):
self.name = name
self.age = age
self.sorce =sorce
p = Person('jack',24,60)
p.age
print('p:%s'%p)
# > 調(diào)用了set方法
# > self:<__main__.Dscrip object at 0x000001F71AD78EF0>
# > ********************
# > instance:<__main__.Person object at 0x000001F71AD78F60>
# > ********************
# > value:24
# > --------------------
# > 調(diào)用了get方法
# > self:<__main__.Dscrip object at 0x000001F71AD78EF0>
# > ********************
# > instance:<__main__.Person object at 0x000001F71AD78F60>
# > ********************
# > owner:<class '__main__.Person'>
# > --------------------
# > p:<__main__.Person object at 0x000001F71AD78F60>
#在這里我們我們打印了get、set方法中的self谤祖、instance婿滓、owner的值
#可以看出self 指的是一個Dscrip類,在Person類中粥喜,指的就是age變量
#instance 和我們打印對象p的地址一致凸主,instance就是指的對象p
#owner 是一個名為Person的類
#value 就是我們傳入對象p中age的值
-
總結(jié):
在get和set方法中,self指的就是我們定義的類描述符的實例對象额湘,也就是類中的屬性
在get和set方法中卿吐,instance指的是包含了該實例對象的實例化類對象
在set方法中,value就是傳入該類對象的值
-
使用類的描述符進行多個類屬性檢查
#上面學習了如何使用property對屬性進行檢查
#現(xiàn)在如果我想要將Person類中新定義一個sorce锋华,并且也進行檢查嗡官,此時如果使用property就會顯得異常繁雜
#這時候就可以使用類的描述符了
class Desc():
def __init__(self, propertyname):
self.propertyname = propertyname
def __get__(self, instance, owner):
if instance is None:
return self
return instance.__dict__[self.propertyname]
def __set__(self, instance, value):
if value < 0:
print('不允許是負值')
else:
instance.__dict__[self.propertyname] = value
def __del__(self):
del self.propertyname
class Person():
age = Desc('age')
sorce = Desc('sorce')
def __init__(self, name, age, sorce):
self.name = name
self.age = age
self.sorce = sorce
p = Person('jack',18,60)
p.sorce = -5
# > 不允許是負值
#這樣就檢查了兩個屬性age、sorce,從而避免了寫多個property
-
類的常用函數(shù)
__dict__
: 獲取類和對象中的所有成員屬性
hasattr
: 檢測某類中是否有某屬性
issubclass
: 檢測某類是否是另一個類的子類
isinstance
: 檢測某個對象是否是一個類的實例
getattr
: 獲取某個對象的某個屬性值
__getattribute__
:獲取某個對象的某個屬性值
setattr
: 設(shè)置某個對象的某個屬性值
delattr
: 刪除某個對象的某個屬性
-
__slots__
: 在類的開頭定義一個slots的元組毯焕,實例化對象后衍腥,對象只能添加元組中定義的屬性
如果子類中沒有定義slots,那么子類不存在slots限制
如果子類中定義了slots,那么子類中slots的限制是子類和父類元組相加的限制
屬性和函數(shù)的動態(tài)綁定
-
對類的實例對象進行動態(tài)綁定
-
動態(tài)綁定屬性,使用對象.屬性 = 值
綁定
class Person():
pass
p = Person()
p.name = 'jack'
-
動態(tài)綁定函數(shù)婆咸,使用對象.方法名 = types.MethodType(方法名竹捉,對象)
綁定
import types
class Person():
pass
def say():
print('say')
p = Person()
p.say = types.MethodType(say, p)
注意:此時綁定的方法只對綁定的該實例對象有效,如果重新定義一個對象尚骄,此方法就失效了
-
對類進行動態(tài)綁定
-
類.方法名 = 方法名
綁定
class Person():
pass
def say():
print('say')
Person.say = say
Person.say()
-
類名.方法名 = types.MethodType(方法块差,類名)
綁定
- 用法參照對象綁定
抽象類
定義抽象類是為了讓其子類必須實現(xiàn)抽象類中的屬性或者方法,對子類進行規(guī)范化倔丈,設(shè)定子類的標準
抽象類只能被繼承使用憾儒,不可以進行實例化
定義抽象使用class 抽象類名(metaclass = abc.ABCMeta)
定義抽象方法使用@abc.abstractclassmethod
import abc
class Man(metaclass= abc.ABCMeta):
@abc.abstractmethod
def say(self):
pass
@abc.abstractmethod
def eat(self):
pass
class Person(Man):
'''
def say(self):
pass
def eat(self):
pass
'''
pass
p = Person()
# > TypeError: Can't instantiate abstract class Person with abstract methods eat, say
#如果子類中不定義抽象方法就會報錯
包
-
包的結(jié)構(gòu)
__init__.py
包的標志文件
模塊
子包
-
導(dǎo)入包
import 包名
import 包名.模塊名
-
導(dǎo)入后可以使用__init__.py
中定義的文件
__init__.py
里如果定義了__all__
,就只能使用__all__
里面定義的內(nèi)容
__init__.py
里如果沒有定義__all__
乃沙,就可以使用全部文件
-
模塊
-
定義模塊的規(guī)范
函數(shù)起趾,單一功能
類
測試代碼
if __name__ = 'main':
代表此模塊作為主線程執(zhí)行時就執(zhí)行以下內(nèi)容
-
導(dǎo)入模塊
import 模塊名
from 模塊名 import 類名
import 模塊名 as 別名
-
模塊、包的查找路徑
默認路徑警儒,可使用sys.path
查看
添加路徑训裆,sys.path.append()
,也就是向列表中添加一個新元素
-
模塊的加載順序
內(nèi)存中已經(jīng)加載好的模塊
Python中內(nèi)置的模塊
按順序查找sys.path中的內(nèi)容
異常
異常是一個類蜀铲,可以進行處理和使用
-
常見異常錯誤類
AssertErro 斷言語句失敗
AttributeErro 嘗試方問未知的對象屬性
FloatingPointErro 浮點計算錯誤
ImportErro 導(dǎo)入模塊失敗
IndexErro 下標引索值超出序列的范圍
KeyErro 字典中查找一個不存在的關(guān)鍵字
NameErro 嘗試訪問一個不存在的變量
RuntimeErro 運行錯誤
OSErro 操作系統(tǒng)產(chǎn)生異常
SynataxErro 語法錯誤
IndentationErro 縮進錯誤
TypeErro 不同類型間的無效操作
-
異常處理
try:
問題語句
except 異常類 as e: #將異常類實例化為e
print(e)
else:
不出錯執(zhí)行語句
finally:
無論是否出錯都執(zhí)行的語句
-
手動引發(fā)異常
raise 異常類
注意:推薦使用自定義異常边琉,并且標注清楚。方便別人或者自己進行查看和快速定位
-
自定義異常類
自定義異常必須是系統(tǒng)異常的子類
拋出異常時的文字提示
異常發(fā)生的行數(shù)
常用模塊
calendar 日歷模塊
calendar() 以字符串形式返回某年的日歷
isleap() 判斷某年是否是閏年
leapdays() 獲取指定年份之間的閏年個數(shù)
month() 以字符串形式返回某年某月的日歷
monthrange() 獲取某年某月第一天是周幾和某月的天數(shù)记劝,返回的是一個元組
monthcalendar() 返回某年某月以二維列表組成的矩陣变姨,其中每周組成一個列表
weekday() 獲取某年某月某日是周幾
import calendar
c = calendar.calendar(2018)
print(c)
2018
January February March
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 4 5 6 7 1 2 3 4 1 2 3 4
8 9 10 11 12 13 14 5 6 7 8 9 10 11 5 6 7 8 9 10 11
15 16 17 18 19 20 21 12 13 14 15 16 17 18 12 13 14 15 16 17 18
22 23 24 25 26 27 28 19 20 21 22 23 24 25 19 20 21 22 23 24 25
29 30 31 26 27 28 26 27 28 29 30 31
April May June
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 1 2 3 4 5 6 1 2 3
2 3 4 5 6 7 8 7 8 9 10 11 12 13 4 5 6 7 8 9 10
9 10 11 12 13 14 15 14 15 16 17 18 19 20 11 12 13 14 15 16 17
16 17 18 19 20 21 22 21 22 23 24 25 26 27 18 19 20 21 22 23 24
23 24 25 26 27 28 29 28 29 30 31 25 26 27 28 29 30
30
July August September
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 1 2 3 4 5 1 2
2 3 4 5 6 7 8 6 7 8 9 10 11 12 3 4 5 6 7 8 9
9 10 11 12 13 14 15 13 14 15 16 17 18 19 10 11 12 13 14 15 16
16 17 18 19 20 21 22 20 21 22 23 24 25 26 17 18 19 20 21 22 23
23 24 25 26 27 28 29 27 28 29 30 31 24 25 26 27 28 29 30
30 31
October November December
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 4 5 6 7 1 2 3 4 1 2
8 9 10 11 12 13 14 5 6 7 8 9 10 11 3 4 5 6 7 8 9
15 16 17 18 19 20 21 12 13 14 15 16 17 18 10 11 12 13 14 15 16
22 23 24 25 26 27 28 19 20 21 22 23 24 25 17 18 19 20 21 22 23
29 30 31 26 27 28 29 30 24 25 26 27 28 29 30
31
print(calendar.isleap(2018))
# > False
print(calendar.leapdays(1990,2018))
# > 7
m = calendar.month(2018,8)
print(m)
# > August 2018
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 29 30 31
week,day = calendar.monthrange(2018,8)
print(week)
print(day)
# > 2
# > 31
list = calendar.monthcalendar(2018,8)
for i in list:
print(i)
# > [0, 0, 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, 29, 30, 31, 0, 0]
print(calendar.weekday(2018,8,7))
# > 1
time 時間模塊
-
time() 指一個時間戳,是從1970年1月1日0時到至今所經(jīng)歷的秒數(shù)
import time
print(time.time())
# > 1533604231.9603899
時間元組厌丑,是一個包含時間內(nèi)容的元組定欧,組成由(年,月怒竿,日砍鸠,時,分耕驰,秒爷辱,周幾,年的第幾天朦肘,夏令時)
-
localtime() 獲取當前時間的元組
import time
print(time.localtime())
# > time.struct_time(tm_year=2018, tm_mon=8, tm_mday=7, tm_hour=9, tm_min=14, tm_sec=51, tm_wday=1, tm_yday=219, tm_isdst=0)
-
timezone 標準時區(qū)與當前時區(qū)相差的秒數(shù)
import time
print(time.timezone)
# > -28800
#中國是東8區(qū)饭弓,相比于國際時間,要快8小時媒抠,28800/60/60 = 8
-
asctime() 返回系統(tǒng)格式化后的時間
import time
print(time.asctime())
# > Tue Aug 7 09:20:40 2018
-
ctime() 返回系統(tǒng)格式化后的時間
import time
print(time.ctime)
# > Tue Aug 7 09:21:37 2018
-
maketime() 將時間元組變成時間戳
import time
t = time.localtime()
s = time.mktime(t)
print(s)
# > 1533605096.0
-
sleep() 使程序休眠指定秒數(shù)后繼續(xù)執(zhí)行
import time
for i in range(1,11):
time.sleep(1)
print(i)
# > 1
# > 2
# > ....
-
strftime() 自定義格式化時間弟断,作用于時間元組
%Y 完整年份
%m 月份
%d 每月中的第幾天
%H 24小時制
%M 分鐘 60
%S 秒 60
import time
t = time.localtime()
st = time.strftime('%Y-%m-%d %H:%M:%S',t)
print(st)
# > 2018-08-07 09:41:23
注意:
print(time.strftime('%Y年%m月%d日 %H時%M分%S秒',time.localtime()))
同樣方法,在windows下報錯UnicodeEncodeError: 'locale' codec can't encode character '\u5e74' in position 2: Illegal byte sequence
在ubuntu下正常執(zhí)行领舰,返回2018年08月06日 20時28分31秒
-
strptime() 將時間字符串格式化為時間元組
import time
st = '2018-8-7 12:00:00'
t = time.strptime(st,'%Y-%m-%d %H:%M:%S')
print(t)
# > time.struct_time(tm_year=2018, tm_mon=8, tm_mday=7, tm_hour=12, tm_min=0, tm_sec=0, tm_wday=1, tm_yday=219, tm_isdst=-1)
datetime 理想的日期和時間模塊
-
date類 提供一個理想的日期
year 屬性
month 屬性
day 屬性
today() 返回當前日期
fromtimestamp() 從一個時間戳中獲得日期
strftime() 自定義格式化日期
import datetime
dt = datetime.datetime(2018,8,7) #將2018.8.7實例化為datetime類
print(dt.year)
# > 2018
print(dt.month)
# > 8
print(dt.day)
# > 7
dt = datetime.datetime.today()
print(dt)
# > 2018-08-07 13:49:04.943500
import time
t = time.time() #獲取當前時間的時間戳
dt = datetime.datetime.fromtimestamp(t)
print(dt)
# > 2018-08-07 13:51:44.969500
print(dt.strftime('%Y.%m.%d'))
# > 2018.08.07
-
datetime類 提供理想的日期和時間
year 屬性
month 屬性
day 屬性
hour 屬性
minute 屬性
second 屬性
mircosecond 屬性
today() 獲取當前日期和時間
fromtimestamp() 從時間戳中獲取日期和時間
-
timedelta類 提供日期和時間的計算
可以通過days = 天數(shù) 夫嗓, hours = 小時數(shù) 迟螺, minutes = 分鐘數(shù)
進行實例化
timedelta類 + date類或者datetime類 = date類或者datetime類
date類或者datetime類 - date類或者datetime類 = timedelta類
import datetime
dt1 = datetime.date(2018,6,15)
dt2 = datetime.date(2018,8,7)
td = dt2 - dt1
print(td)
# > 53 days, 0:00:00
print(type(td))
# > <class 'datetime.timedelta'>
dt3 = datetime.datetime(2018,6,15,8,30,15)
dt4 = datetime.datetime(2018,8,7,14,4)
td = dt4 - dt3
print(td)
# > 53 days, 5:33:45
td = datetime.timedelta(days=10,hours=15,minutes=30)
dt = datetime.datetime.now()
temp = dt + td
print(type(temp))
# > <class 'datetime.datetime'>
print(temp)
# > 2018-08-18 05:37:51.464770
timeit 代碼時間測試模塊
-
timeit(smlt = 測試代碼,setup = 運行環(huán)境 舍咖,number = 重復(fù)次數(shù))
測試代碼時間
#現(xiàn)在我們測試一下列表生成式和循環(huán)加入列表中的兩個代碼誰執(zhí)行的快
import timeit
st1 = '[i for i in range(1000)]'
st2 = '''
list = []
for i in range(1000):
list.append(i)
'''
t1 = timeit.timeit(stmt = st1,number = 100000)
t2 = timeit.timeit(stmt = st2,number = 100000)
print(t1)
# > 3.6470414876165864
print(t2)
# > 9.188953135455993
#當測試帶參數(shù)的函數(shù)的寫法
import timeit
c = '''
def func(num):
for i in range(num):
print('repeat for {}'.format(i))
'''
t = timeit.timeit(stmt='func(num)', setup = c + 'num=2', number=100000)
print(t)
# > repeat for 1
# > repeat for 0
# > ....
# > 1.1565270608769294
os 系統(tǒng)操作模塊
-
絕對路徑 總是從根目錄上開始
D:\360安全瀏覽器下載\chromeinstall-8u151.exe
-
相對路徑 以當前所在工作目錄開始
\360安全瀏覽器下載\chromeinstall-8u151.exe
-
值
os.curdir
當前目錄,用‘ . ’表示
os.pardir
父親路徑矩父,用‘ .. ’表示
-
os.sep
系統(tǒng)分隔符
windows下用‘ \ ’
linux下用‘ / ’
-
os.linesep
系統(tǒng)的換行符號
windows下用‘ \r\n ’
linux下用‘ \n ’
-
os.name
系統(tǒng)名稱
windows下用‘ nt ’
linux下用‘ posix ’
-
函數(shù)
getcwd()
返回當前工作目錄
chdir()
改變工作目錄
listdir()
顯示路徑下所有文件和文件夾,返回一個列表
makedirs()
創(chuàng)建一個空文件夾
rename()
重命名文件
removedirs()
刪除空文件夾
system()
運行系統(tǒng)shell命令
getenv()
獲取當前系統(tǒng)環(huán)境變量值
putenv()
添加環(huán)境變量
exit()
退出當前程序
-
path類中的函數(shù)
abspath()
將路徑轉(zhuǎn)化為絕對路徑
basename()
獲取路徑中的文件名部分
dirname()
返回路徑中的文件夾部分
split()
將路徑切割為文件夾和文件名組成的元組
splittext()
將路徑切割為文件和后綴名組成的元組
join()
將兩個路徑拼接成一個路徑
exists()
判斷文件或文件夾是否存在
isfile()
判斷是否為文件
isdir()
判斷是否為文件夾
getsize()
返回文件大小
getatime()
返回文件或文件夾最后讀取時間
ghetmtime()
返回文件或文件夾最后修改時間
shutil 文件操作模塊
copy()
復(fù)制文件排霉,還可以將文件重命名
copy2()
盡可能保留元數(shù)據(jù)的情況下復(fù)制文件
copyfile()
講一個文件里的內(nèi)容復(fù)制到另一個文件中
copytree()
復(fù)制文件夾里所有內(nèi)容
move()
移動文件或文件夾
rmtree()
刪除文件或文件夾下的所有文件
make_archive(壓縮后的名稱窍株,壓縮類型,需要壓縮的文件)
壓縮文件攻柠,返回壓縮文件的路徑
unpack_archive(壓縮包路徑球订,解包之后的路徑)
解壓文件
collections 模塊
-
namedtuple類
是一個可以命名的元組類型
定義方式類名 = collections.namedtuple(類類型,屬性組成的列表)
import collections
Point = collections.namedtuple('Point',['x','y'])
p = Point(15,22)
print(p)
# > Point(x=15, y=22)
-
deque類
解決頻繁插入瑰钮、刪除帶來的效率問題
定義方式:對象 = collections.deque(列表)
import collections
d = collections.deque([1,2,3,4,5])
d.appendleft(10)
# > deque([10, 1, 2, 3, 4, 5])
-
defaultdict類
當讀取一個不存在的key時冒滩,返回一個默認值
-
定義方式:對象 = collections.defaultdict(帶有返回值的函數(shù))
import collections
def pr():
return '默認值'
d = collections.defaultdict(pr)
d['a'] = 1
d['b'] = 2
print(d)
# > defaultdict(<function pr at 0x028AB6F0>, {'a': 1, 'b': 2})
print(d['dd'])
# > 默認值
-
Counter類
- 主要是統(tǒng)計元素在迭代對象中出現(xiàn)的次數(shù),以元素:次數(shù)的字典形式返回
import collections
s = 'afjkasdhfklashgkjash'
dict = collections.Counter(s)
print(dict)
# > Counter({'a': 4, 'k': 3, 's': 3, 'h': 3, 'f': 2, 'j': 2, 'd': 1, 'l': 1, 'g': 1})
import collections
s = ['ss','jack','alice','bob','jack','jack','jack']
dict = collections.Counter(s)
print(dict)
# > Counter({'jack': 4, 'ss': 1, 'alice': 1, 'bob': 1})
pickle 持久化模塊
-
dump(數(shù)據(jù),句柄)
浪谴,將數(shù)據(jù)持久化到文件
import pickle
file = r'C:\Users\wudi.HAPMMAGNA\Desktop\b.txt'
l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
with open(file, 'wb') as f:
pickle.dump(l,f)
#將數(shù)據(jù)以二進制方式寫入到b.txt文件中
-
load(句柄)
开睡,將持久化的數(shù)據(jù)提取到程序中
import pickle
file = r'C:\Users\wudi.HAPMMAGNA\Desktop\b.txt'
with open(file, 'rb') as f:
l = pickle.load(f)
print(l)
# > [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
#將b.txt文件中儲存的數(shù)據(jù)讀取到程序中
shelve 持久化模塊
將數(shù)據(jù)以字典的形式寫入文件中
shelve只能允許一個句柄進行寫入,但可以允許多個句柄進行讀取
writeback = Ture
在關(guān)閉文件時苟耻,檢查更改篇恒,并將數(shù)據(jù)寫入文件
import shelve
file = r'C:\Users\wudi.HAPMMAGNA\Desktop\a'
sv = shelve.open(file,writeback= True)
sv['one'] = 1
sv['two'] = 2
sv['three'] = 3
sv.close()
# 此時桌面上出現(xiàn)了三個文件,為a.dat凶杖、a.bak胁艰、a.dir
- 讀取文件
import shelve
file = r'C:\Users\wudi.HAPMMAGNA\Desktop\a'
sv = shelve.open(file)
print(sv['one'])
sv.close()
# > 1
IO文件模塊
文件是一種長久保存信息數(shù)據(jù)的集合,保存在磁盤上
文件一旦被打開智蝠,就需要進行關(guān)閉操作腾么,否則可能造成文件信息的丟失
-
常用操作
-
讀寫模式
r
只讀,指針在文件開頭
w
只寫寻咒,指針在文件開頭
x
創(chuàng)建文件并只進行寫入哮翘,如果文件已經(jīng)存在則會報錯,指針在文件開頭
a
追加寫入毛秘,指針在文件末尾
b
以二進制方式
t
以文本方式
+
讀寫
-
open(文件地址,讀寫模式)
打開文件阻课、close()
關(guān)閉文件
file = r'C:\Users\wudi.HAPMMAGNA\Desktop\b.txt'
f = open(file)
f.close()
-
with
語句
使用上下文管理協(xié)議技術(shù)
自動關(guān)閉已經(jīng)不再使用的文件
推薦一定文件讀寫一定要使用with語句
file = r'C:\Users\wudi.HAPMMAGNA\Desktop\b.txt'
with open(file,'wb') as f:
pass
-
讀取操作
read(字符數(shù))
如果不使用字符數(shù)叫挟,那么read將會將所有字符讀取出來,如果指定字符限煞,就按照指定字符數(shù)進行讀取
readline()
按行讀取文件內(nèi)容
list(句柄)
將文件所有內(nèi)容讀取出來抹恳,以列表形式進行保存
使用while 數(shù)據(jù)
進行讀取,當數(shù)據(jù)不為空時署驻,就會一直循環(huán)下去奋献,如果數(shù)據(jù)為空時健霹,當前循環(huán)就會停止
# b.txt中有以下內(nèi)容
# 關(guān)雎
# 關(guān)關(guān)雎鳩,在河之洲瓶蚂。窈窕淑女糖埋,君子好逑。
# 參差荇菜窃这,左右流之瞳别。窈窕淑女,寤寐求之杭攻。
# 求之不得祟敛,寤寐思服。悠哉悠哉兆解,輾轉(zhuǎn)反側(cè)馆铁。
# 參差荇菜,左右采之锅睛。窈窕淑女埠巨,琴瑟友之。
# 參差荇菜乖订,左右芼之。窈窕淑女具练,鐘鼓樂之乍构。
file = r'C:\Users\wudi.HAPMMAGNA\Desktop\b.txt'
with open(file, 'r') as f:
data = f.read(1024)
while data:
print(data)
data = f.read(1024)
# > 關(guān)雎
# > 關(guān)關(guān)雎鳩,在河之洲扛点。窈窕淑女哥遮,君子好逑。
# > 參差荇菜陵究,左右流之眠饮。窈窕淑女,寤寐求之铜邮。
# > 求之不得仪召,寤寐思服。悠哉悠哉松蒜,輾轉(zhuǎn)反側(cè)扔茅。
# > 參差荇菜,左右采之秸苗。窈窕淑女召娜,琴瑟友之。
# > 參差荇菜惊楼,左右芼之玖瘸。窈窕淑女腹鹉,鐘鼓樂之哮肚。
with open(file, 'r') as f:
data = f.readline()
while data:
print(data)
data = f.readline()
# > 關(guān)雎
# >
# > 關(guān)關(guān)雎鳩岛抄,在河之洲挨队。窈窕淑女,君子好逑屯断。
# >
# > 參差荇菜文虏,左右流之。窈窕淑女殖演,寤寐求之氧秘。
# >
# > 求之不得,寤寐思服趴久。悠哉悠哉丸相,輾轉(zhuǎn)反側(cè)。
# >
# > 參差荇菜彼棍,左右采之灭忠。窈窕淑女,琴瑟友之座硕。
# >
# > 參差荇菜弛作,左右芼之。窈窕淑女华匾,鐘鼓樂之映琳。
with open(file,'r') as f:
list3 = list(f)
for i in list3:
print(i)
# > 結(jié)果同readline() ,為什么會出現(xiàn)這種情況蜘拉? 使用read時萨西,中間沒有隔行,而使用其他時就會有隔行呢旭旭?
#我們來做個試驗谎脯,將所有讀取到的內(nèi)容添加到列表,看他們在列表中是如何組成的
file = r'C:\Users\wudi.HAPMMAGNA\Desktop\b.txt'
list1 = []
list2 = []
with open(file, 'r') as f:
data = f.read(1024)
while data:
list1.append(data)
data = f.read(1024)
with open(file, 'r') as f:
data = f.readline()
while data:
list2.append(data)
data = f.readline()
with open(file,'r') as f:
list3 = list(f)
print(list1)
print('@'*30)
print(list2)
print('@'*30)
print(list3)
# > ['關(guān)雎\n關(guān)關(guān)雎鳩持寄,在河之洲源梭。窈窕淑女,君子好逑稍味。\n參差荇菜咸产,左右流之。窈窕淑女仲闽,寤寐求之。\n求之不得僵朗,寤寐思服赖欣。悠哉悠哉屑彻,輾轉(zhuǎn)反側(cè)。\n參差荇菜顶吮,左右采之社牲。窈窕淑女,琴瑟友之悴了。\n參差荇菜搏恤,左右芼之。窈窕淑女湃交,鐘鼓樂之熟空。']
# > @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# > ['關(guān)雎\n', '關(guān)關(guān)雎鳩,在河之洲搞莺。窈窕淑女息罗,君子好逑。\n', '參差荇菜才沧,左右流之迈喉。窈窕淑女,寤寐求之温圆。\n', '求之不得挨摸,寤寐思服。悠哉悠哉岁歉,輾轉(zhuǎn)反側(cè)得运。\n', '參差荇菜,左右采之刨裆。窈窕淑女澈圈,琴瑟友之。\n', '參差荇菜帆啃,左右芼之瞬女。窈窕淑女,鐘鼓樂之努潘。']
# > @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# > ['關(guān)雎\n', '關(guān)關(guān)雎鳩诽偷,在河之洲。窈窕淑女疯坤,君子好逑报慕。\n', '參差荇菜,左右流之压怠。窈窕淑女眠冈,寤寐求之。\n', '求之不得,寤寐思服蜗顽。悠哉悠哉布卡,輾轉(zhuǎn)反側(cè)。\n', '參差荇菜雇盖,左右采之忿等。窈窕淑女,琴瑟友之崔挖。\n', '參差荇菜贸街,左右芼之。窈窕淑女狸相,鐘鼓樂之薛匪。']
# 可以看出,read中整個列表只有一個元素卷哩,也就是遇到'\n'時會自動進行換行蛋辈,而在其他函數(shù)中,列表中有多個元素将谊,遇到n時會換一次行冷溶,而單次打印內(nèi)容時也會換一次行。
-
寫入操作
write(數(shù)據(jù))
將單次數(shù)據(jù)寫入文件中
writelines(數(shù)據(jù)序列)
將一個可迭代的數(shù)據(jù)序列按順序?qū)懭胛募?/p>
data = '我是數(shù)據(jù)'
with open(file,'w') as f:
f.write(data)
# > 文件中的內(nèi)容是我是數(shù)據(jù)
data = ['關(guān)關(guān)雎鳩尊浓,在河之洲逞频。窈窕淑女,君子好逑栋齿。\n', '參差荇菜苗胀,左右流之。窈窕淑女瓦堵,寤寐求之基协。\n']
with open(file,'w') as f:
f.writelines(data)
# > 關(guān)關(guān)雎鳩,在河之洲菇用。窈窕淑女澜驮,君子好逑。
# > 參差荇菜惋鸥,左右流之杂穷。窈窕淑女,寤寐求之卦绣。
-
指針操作 seek(指針偏移量耐量,參照物)
-
指針偏移量
以字節(jié)byte為單位,和read函數(shù)有巨大區(qū)別滤港,read是字符為單位
不同編碼中漢字所占的字節(jié)數(shù)有所不同
-
參照物
0 表示在文件開頭
1 表示指針當前位置
2 表示在文件末尾
# b.txt中有以下內(nèi)容:阿富汗喀什的法律可攻可受的復(fù)合弓
#注意:需要保存為utf-8編碼
# 如果我們需要讀取文件末尾兩個字符廊蜒,就需要
file = r'C:\Users\wudi.HAPMMAGNA\Desktop\b.txt'
with open(file, 'rb') as f:
f.seek(-6,2)
data = f.read(1024)
while data:
print(data.decode())
data = f.read(1024)
# > 合弓
# seek中的含義為以文件末尾為指針位置,向左移動6個字節(jié)的位置,然后向后讀取
logging 日志模塊
主要是將文件運行的信息保存在磁盤文件上
logging不要頻繁進行IO讀寫劲藐,運行過程中八堡,只需要保存重要信息和錯誤信息
-
作用
程序調(diào)試
了解軟件運行狀況
分析定位問題
-
日志應(yīng)包含信息
時間
地點
級別
內(nèi)容
-
日志級別
DEBUG
INFO
WARNING
ERROR
CRITICAL
-
直接使用系統(tǒng)定制的logging
logging.debug(msg)
創(chuàng)建一條debug日志
logging. info(msg)
創(chuàng)建一條info日志
logging.warning(msg)
創(chuàng)建一條warning日志
logging.error(msg)
創(chuàng)建一條error日志
logging.critical(msg)
創(chuàng)建一條critical日志
-
logging.basicConfig(file=文件名,format=格式化字符串聘芜,level=輸出的最低級別)
配置log
level對照以上日志級別作為參數(shù),默認為warning
-
format的相應(yīng)參數(shù)
%(asctime)s
時間和日期
%(levelname)s
日志級別
%(message)s
日志內(nèi)容
%(filename)s
程序名
%(pathname)s
程序路徑
%(funcName)s
當前函數(shù)
%(lineno)d
當前行數(shù)
%(thread)s
當前線程ID
%(ThreadName)s
當前線程名
%(process)s
當前進程ID
import logging
logging.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s',level=logging.DEBUG)
logging.debug('我是一條DEBUG日志')
# > 2018-08-10 15:10:09,089 - DEBUG - 我是一條DEBUG日志
-
使用四大組件進行定制
-
Logger類 日志器 產(chǎn)生日志
getLogger(日志器名稱)
創(chuàng)建一個日志器對象
setlevel(日志級別)
設(shè)置處理日志的最低級別
addHandler(處理器對象),removeHandler()
添加、刪除一個處理器對象
addFilter(過濾器對象)缝龄,removeFilter()
添加汰现、刪除一個過濾器對象
debug()、info()叔壤、.....創(chuàng)建一條日志
-
Filter類 過濾器 存疑
- 可被Logger瞎饲、Handler使用
-
Formatter類 格式器 格式化輸出日志
可以直接實例化使用
-
Formatter(fmt,datefmt)
fmt 格式化字符串
datefmt 格式化時間和日期字符串
-
Handler類 處理器 將日志輸出到相應(yīng)位置
-
Handler是基類,不能直接使用炼绘,需要使用其子類
StreamHandler()
向控制臺輸出
FileHandler(file=文件)
向文件寫入日志
handlers.RotatingHandler(file=文件嗅战,maxBytes=大小,backupCount=日志保留個數(shù))
向文件寫入日志俺亮,如果超過指定大小驮捍,則新建日志文件
-
handlers.TimeRotatingFileHandler(file=文件, when=時間脚曾, interval=間隔东且, backupCount=保留日志個數(shù))
向文件寫入日志,按時間進行分割
-
when的參數(shù)
'S'
秒
'M'
分
'H'
時
- 'D'
天
- 'midnight'
每日午夜12:00
- 'W0-W6'
周一 ~ 周日
handlers.HTTPHandler
發(fā)送給一個HTTP服務(wù)器
handlers.SMTPHandler
發(fā)送給一個指定的郵件地址
setlevel(日志級別)
設(shè)置最低需要寫入日志的級別
setFormatter(格式器對象)
添加一個格式器對象本讥,用來控制輸出的日志格式
addFilter(過濾器對象)珊泳、removeFilter()
#定義記錄兩個日志,每天記錄一次
#一個日志all.log拷沸,所有級別的日志都被記錄色查,格式為“日期和時間 - 級別 - 內(nèi)容”
#一個日志error.log,error以上的的日志都被記錄撞芍,格式為“日期和時間 - 級別 - 文件名【:行號】 - 內(nèi)容”
import logging
import logging.handlers
import datetime
#定義Logger
logger = logging.getLogger('mylogger')
logger.setLevel(logging.DEBUG)
#定義debughandler格式器
formatter1 = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
#定義記錄所有日志的debughandler
file1 = r'C:\Users\wudi.HAPMMAGNA\Desktop\all.log'
debughandler = logging.handlers.TimedRotatingFileHandler(file1, when='midnight', interval=1, backupCount=3000)
debughandler.setFormatter(formatter1)
#定義errorhandler格式器
formatter2 = logging.Formatter('%(asctime)s - %(levelname)s - %(filename)s[:%(lineno)d] - %(message)s')
#定義記錄error以上級別的日志errorhandler
file2 = r'C:\Users\wudi.HAPMMAGNA\Desktop\error.log'
errorhandler = logging.handlers.TimedRotatingFileHandler(file2, when='midnight', interval=1, backupCount=3000)
errorhandler.setFormatter(formatter2)
errorhandler.setLevel(logging.ERROR)
#為日志器添加處理器
logger.addHandler(debughandler)
logger.addHandler(errorhandler)
logger.debug('我是debug日志')
logger.info('我是info日志')
logger.warning('我是warning日志')
logger.error('我是error日志')
logger.critical('我是critical日志')
-
總結(jié)思路
實例化一個Logger對象
依照不同的日志文件實例化不同處理方式的Handler
給每個Hadnler對象添加實例化的Formatter格式器對象
輸出
queue 同步隊列模塊
Queue類 先進先出隊列
LifoQueue 后進先出隊列
PriorityQueue 優(yōu)先級隊列
-
常用方法
qsize()
返回隊列長度
put()
將數(shù)據(jù)放入隊列中
get()
從隊列中取出數(shù)據(jù),并刪除
empty()
檢測隊列是否為空
full()
檢測隊列是否已滿
import queue
que = queue.Queue()
for i in range(1,11):
que.put(i)
print(que.get())
# > 1
print(que.empty())
# > False
threading 多線程模塊
-
首先明確幾個概念
阻塞: 程序在等待某個操作完成期間,自身無法干其他事情,處于掛起狀態(tài)
非阻塞: 程序在等待某個操作完成期間,自身不被阻塞,還可以繼續(xù)干其他事情,是為了提高程序的整體執(zhí)行效率,讓程序在IO過程中執(zhí)行其他計算任務(wù)
并行: 利用富余的資源(多核)加速完成某個任務(wù) 多進程
并發(fā): 利用有限的資源使多個任務(wù)被實時或者近似實時的執(zhí)行,讓多個任務(wù)都有機會被盡快執(zhí)行,不一定能加快進度 多線程
異步: 不同程序單元執(zhí)行過程中不需要通信也能完成某個任務(wù),高效的組織非阻塞任務(wù)的方式,異步意味著無序
同步: 不同程序單元為了完成某個任務(wù),在執(zhí)行過程中需要靠通信進行步調(diào)一致,同步就意味著有序
-
定義線程的兩種方式
-
通過傳入函數(shù)來啟動線程
import threading
def func():
while True:
pass
t = threading.Thread(target=func,args=())
t.setDaemon(True)
t.start()
print(threading.enumerate())
# > [<_MainThread(MainThread, started 7176)>, <Thread(Thread-1, started daemon 9260)>]
# > 可以看出開啟了兩個線程,一個是主線程,另一個是子線程
-
通過繼承threading.Thread
類,重寫其init和run方法定義
import threading
import time
class myThread(threading.Thread):
def __init__(self):
super().__init__()
def run(self):
print('{0} say hello'.format(self.name))
time.sleep(5)
for i in range(5):
t = myThread()
t.start()
t.join()
print('over')
# > Thread-1 say hello
# > Thread-2 say hello
# > Thread-3 say hello
# > Thread-4 say hello
# > Thread-5 say hello
# > over
注意: 主線程執(zhí)行完畢后,子線程并不會關(guān)閉,而是會等到子線程中的函數(shù)執(zhí)行完畢后再關(guān)閉
-
線程常用的方法
-
start()
啟動線程
-
join()
阻塞線程,等待該線程執(zhí)行完畢
-
active_Count()
返回當前活動的線程數(shù)量
-
current_thread()
返回當前正在活動的線程
-
enumerate()
返回當前活動的線程對象列表
-
守護線程
當A線程是B線程的守護線程時,一旦B關(guān)閉,A線程不論是否已經(jīng)完成,都會隨著B線程而關(guān)閉
setDaemon(True)
設(shè)置一個線程為守護線程
-
GIL 全局解釋器鎖
- 在多線程中,每個線程都會在執(zhí)行之前申請一把鎖,這把鎖就是GIL,但是這個鎖只有一把,也就是只有等一個線程釋放鎖之后,其他線程才能申請這個鎖,同一時間,線程只能并發(fā),卻不能并行.
-
多線程安全
在多線程中,對變量的讀操作,并不會影響線程安全
在多線程中,對變量的寫操作,很有可能會引起線程安全的問題
-
不安全線程的例子
import threading
import time
num = 0
loop = 1000000
def funa(loop):
global num
for i in range(loop):
num += 1
print('funa done')
def funb(loop):
global num
for i in range(loop):
num -= 1
print('funb done')
t1 = threading.Thread(target=funa,args=(loop,))
t2 = threading.Thread(target=funb,args=(loop,))
t1.start()
t2.start()
time.sleep(2)
print(num)
# > 281811
# > 結(jié)果并不是固定的,每次執(zhí)行都會產(chǎn)生不同的結(jié)果
這是因為有可能在線程中,多個線程可能在同時更改這個變量,造成結(jié)果錯誤
-
鎖
為了解決共享變量沖突的問題
-
Lock 類
只能執(zhí)行一次鎖定,鎖定完成后必須釋放鎖,才能進行下一次鎖定
可以使用上下文管理協(xié)議
acqurie()
上鎖
release()
解鎖
-
還是上一個例子,如果將全局變量加鎖,同一時間,只能允許一個線程進行讀寫操作,這時候結(jié)果就一定為0
import threading
import time
lock = threading.Lock()
num = 0
loop = 1000000
def funa(loop):
global num
for i in range(loop):
with lock:
num += 1
print('funa done')
def funb(loop):
global num
for i in range(loop):
lock.acquire()
num -= 1
lock.release()
print('funb done')
t1 = threading.Thread(target=funa,args=(loop,))
t2 = threading.Thread(target=funb,args=(loop,))
t1.start()
t2.start()
time.sleep(2)
print(num)
# > funa done
# > funb done
# > 0
-
Rlock 類 可重入鎖
- 與Lock相同用法,但是可以實現(xiàn)鎖內(nèi)再次上鎖
# 使用Lock 實現(xiàn)兩次上鎖
import threading
lock = threading.Lock()
def funa():
lock.acquire()
print('第一道鎖上鎖')
lock.acquire()
print('第二道鎖上鎖')
lock.release()
print('釋放第二道鎖')
lock.release()
print('釋放第一道鎖')
t = threading.Thread(target=funa,args=())
t.start()
t.join()
print('done')
# > 第一道鎖上鎖
# 可以看出,此時,一直是在等待解鎖過程中,出現(xiàn)阻塞狀態(tài),后面的代碼永遠不會執(zhí)行
# 使用Rlock 實現(xiàn)兩次上鎖
import threading
lock = threading.RLock()
def funa():
lock.acquire()
print('第一道鎖上鎖')
lock.acquire()
print('第二道鎖上鎖')
lock.release()
print('釋放第二道鎖')
lock.release()
print('釋放第一道鎖')
t = threading.Thread(target=funa,args=())
t.start()
t.join()
print('done')
# > 第一道鎖上鎖
# > 第二道鎖上鎖
# > 釋放第二道鎖
# > 釋放第一道鎖
# > done
#可以看出,程序按照預(yù)想的執(zhí)行了
-
Condition 類 條件鎖
當某一事件觸發(fā)后線程進行等待或者執(zhí)行操作
相比于Lock,Condition有一個等待池和一個鎖定池,運行時處于鎖定池中,阻塞時,處于等待池中
可使用上下文管理協(xié)議
-
常用方法
acqurie()
上鎖
release()
解鎖
notify(線程數(shù)量)
通知指定數(shù)量的線程運行
notify_all()
通知所有線程開始執(zhí)行
wait()
使本線程處于阻塞狀態(tài),等待條件
案例
import threading
import time
con = threading.Condition()
num = 0
class A(threading.Thread):
def run(self):
global num
with con:
while True:
if num >20:
print('產(chǎn)品大于20個了,我不生產(chǎn)了')
con.notify()
con.wait()
num += 1
time.sleep(0.5)
print('產(chǎn)品總數(shù)為:{0}'.format(num))
class B(threading.Thread):
def run(self):
global num
with con:
while True:
if num < 5:
print('產(chǎn)品小于5了,我不消費了')
con.notify()
con.wait()
num -= 1
time.sleep(0.5)
print('產(chǎn)品總數(shù)為:{0}'.format(num))
a = A()
b = B()
a.start()
b.start()
# > 結(jié)果太長不寫了
-
Semaphore 類 信號量
該類主要控制線程對資源的最大使用數(shù)量,當線程超過指定數(shù)量時,就變?yōu)榈却隣顟B(tài),一旦空出線程,其他線程就會接著執(zhí)行
當一個線程申請時,信號量就會-1 ,一旦變?yōu)樨撝?其他線程就不允許申請了.當一個線程被放出時,信號量就會+1,一旦不是負值,其他線程就可以申請.
import threading
import time
st = 'st'
se = threading.Semaphore(2)
class A(threading.Thread):
def run(self):
with se:
for i in range(3):
print('我是{0},我被{1}訪問了'.format(st, self.name))
time.sleep(1)
print(threading.current_thread())
for i in range(20):
t = A()
t.start()
-
Event 類 事件信號燈
相當于設(shè)置一個紅綠燈,當紅綠燈為True時,線程才會向下執(zhí)行,否則就會一直等待信號
-
常用方法
set()
設(shè)置信號燈為True
clear()
設(shè)置信號燈為False
wait()
本線程等待信號燈
import threading
import time
event = threading.Event()
class A(threading.Thread):
def run(self):
print('等待信號燈')
event.wait()
print('信號燈通過')
print('hello')
a = A()
a.start()
time.sleep(2)
event.set()
a.join()
print('done')
# > 等待信號燈
# > #2秒后
# > 信號燈通過
# > hello
# > done
-
Timer 類 定時器
Timer(間隔秒數(shù),執(zhí)行的函數(shù),函數(shù)的參數(shù))
指定多少秒后以一個線程執(zhí)行某函數(shù)
import threading
def func():
print('hello')
timer = threading.Timer(2,func)
timer .start()
# > #2秒后
# > hello
-
生產(chǎn)者消費者模型
- 生產(chǎn)者只負責向隊列中寫入任務(wù),而消費者只向隊列中拿出任務(wù)
import threading, queue, time
class Producer(threading.Thread):
def __init__(self,queue):
super().__init__()
self.queue = queue
def run(self):
num = 0
while True:
num += 1
self.queue.put(num)
print('向倉庫中放入%s'%num)
time.sleep(0.5)
class Consumer(threading.Thread):
def __init__(self,queue):
super().__init__()
self.queue = queue
def run(self):
while True:
data = self.queue.get()
print('{0}消費了{1}'.format(self.name,data))
time.sleep(1.5)
que = queue.Queue()
p = Producer(que)
p.start()
for i in range(2):
c = Consumer(que)
c.start()
# > 向倉庫中放入1
# > Thread-2消費了1
# > 向倉庫中放入2
# > Thread-3消費了2
# > 向倉庫中放入3
# > Thread-2消費了3
# > 向倉庫中放入4
# > Thread-3消費了4
# > 向倉庫中放入5
# > 向倉庫中放入6
多進程
推薦使用多進程,因為多進程中沒有GIL鎖,可以并行執(zhí)行
在使用多進程時,主函數(shù)必須在 if __name__ == '__main__:'
下執(zhí)行
-
實現(xiàn)多進程的方式
-
Process 類
-
通過實例化Process類,將函數(shù)傳入?yún)?shù)中
import multiprocessing
def func():
print('hello')
t = multiprocessing.Process(target=func,args=())
t.start()
-
通過繼承Process類,并重寫init和run方法
import multiprocessing
class A(multiprocessing.Process):
def run(self):
print('hello')
a = A()
a.start()
使用os.fork()
僅在Unix系統(tǒng)下有效
-
使用Pool 進程池
pool池可以指定并行最大進程執(zhí)行的數(shù)量,我認為和線程中的Semaphore信號量相似,同樣有一個等待池和一個工作池,當工作池中的進程空出來時,等待池的其它線程就會頂替上去執(zhí)行
可使用上下文管理協(xié)議
-
常用函數(shù)
apply(函數(shù)名,參數(shù))
向工作池提交任務(wù),阻塞的等待任務(wù)完成,并返回結(jié)果.
-
apply_async(函數(shù)名,參數(shù))
向工作池提交任務(wù),返回消息對象,等待進程池所有任務(wù)執(zhí)行完畢后,再拿回任務(wù)執(zhí)行的結(jié)果
因為apply_async是并行的,所以需要申明一個list用來保存消息對象,等待所有的任務(wù)完成后再列表中的單個消息對象返回結(jié)果
get()
返回結(jié)果
ready()
如果調(diào)用完成,則返回True
successful()
如果調(diào)用沒有引發(fā)異常秧了,返回True
wait()
等待結(jié)果執(zhí)行完畢
terminate()
立即終止該工作進程
close()
關(guān)閉進程池
join()
阻塞,直到進程池所有任務(wù)完成
terminate()
立即終止進程池進程
-
阻塞式進程池
import multiprocessing
import random
import time
def getresult(x):
return x * random.randint(1, 10)
if __name__ == '__main__':
pool = multiprocessing.Pool(2)
for i in range(1, 5):
res = pool.apply(getresult, (i,))
time.sleep(1)
print(res)
# > 4
# > 10
# > 9
# > 4
-
異步線程池
import multiprocessing
import random
def getresult(x):
return x * random.randint(1, 10)
if __name__ == '__main__':
pool = multiprocessing.Pool(2)
list = []
for i in range(1, 5):
res = pool.apply_async(getresult, (i,))
list.append(res)
p.close()
p.join()
print(list)
for i in list:
print(i.get())
# > [<multiprocessing.pool.ApplyResult object at 0x02C78630>, <multiprocessing.pool.ApplyResult object at 0x02C78690>, <multiprocessing.pool.ApplyResult object at 0x02C786F0>, <multiprocessing.pool.ApplyResult object at 0x02C78750>]
# > 7
# > 12
# > 3
# > 20
-
進程常用方法
start()
啟動進程
join()
阻塞,知道本進程執(zhí)行完畢
daemon = True
設(shè)置守護進程
terminate()
強制關(guān)閉進程
close()
關(guān)閉進程
is_alive()
返回進程是否存活
name
返回進程名稱
pid
返回進程ID
active_chrildren()
返回活動的進程列表
cpu_count()
返回電腦CPU核心數(shù)
-
進程之間的同步
多進程中,同步并不是向多線程那樣重要,因為多使用IPC通信
其用法與多線程中相同類的用法一樣
Condition類 條件變量
Event類 事件信號燈
Semaphore類 信號量
Lock 鎖
Rlock 可重入鎖
-
IPC通信 多進程之間的通信
-
源自于同一父進程
-
Queue類 先入先出隊列
put()
放入元素
get()
取出元素
qsize()
返回隊列長度
empty()
檢測隊列是否為空
full()
檢測隊列是否已滿
-
JoinableQueue隊列
每當一個任務(wù)完成后,可手動調(diào)用task_done,告訴系統(tǒng)一個任務(wù)已經(jīng)執(zhí)行完成,當所有任務(wù)執(zhí)行完成后,將取消join的阻塞,向下執(zhí)行代碼
-
常用函數(shù)
Queue隊列的其它方法
task_done()
任務(wù)已完成
join()
阻塞,直到本隊列中的所有元素被task_done
import multiprocessing,time
def func(queue):
while True:
if queue.empty():
break
data = queue.get()
print('取出%s'%data)
queue.task_done()
time.sleep(0.5)
if __name__ == '__main__':
que = multiprocessing.JoinableQueue()
for i in range(20):
que.put(i)
p = multiprocessing.Process(target=func, args=(que,))
p.start()
que.join()
print('當隊列中的元素都被取完后才會看見我')
# > 太長不打了
-
Pipe 類 管道 兩個進程之間的通信
相當于管道,實例化后返回兩個端口,默認是雙工的
send()
發(fā)送消息
recv()
接收消息
import multiprocessing,time
class A(multiprocessing.Process):
def __init__(self,con):
super().__init__()
self.con = con
def run(self):
while True:
self.con.send('hello')
time.sleep(1)
class B(multiprocessing.Process):
def __init__(self, con):
super().__init__()
self.con = con
def run(self):
while True:
data = self.con.recv()
print(data)
time.sleep(1)
if __name__ == '__main__':
con1, con2 = multiprocessing.Pipe()
a = A(con1)
b = B(con2)
a.start()
b.start()
# > hello
# > ...
-
不是源自于同一父進程
-
Value類 將值放在系統(tǒng)的共享內(nèi)存中,多個進程可以共同讀寫這塊內(nèi)存,
定義 Value(值類型,值)
-
值類型
u
unicodechar
i
signedint
f
float
d
double
value
獲取值
import multiprocessing
class A(multiprocessing.Process):
def run(self):
s = v.value
print('{0} get {1}'.format(self.name,s))
if __name__ == '__main__':
v = multiprocessing.Value('u','哈')
for i in range(5):
p = A()
p.start()
# > A-1 get 哈
# > A-2 get 哈
# > A-4 get 哈
# > A-5 get 哈
# > A-3 get 哈
-
Array類 Vaule的數(shù)組
數(shù)組中存放的變量類型需要一致
定義 Array(值類型,列表)
返回的是一個可迭代的對象
import multiprocessing
class A(multiprocessing.Process):
def run(self):
for i in arr:
print(i,end='')
if __name__ == '__main__':
list = ['哈','哈','-','我','是','A','r','r','a','y']
arr = multiprocessing.Array('u',list)
p = A()
p.start()
# > 哈哈-我是Array
-
Manager類 管理器
list 列表
dict 字典
Condition() 創(chuàng)建一個線程共享條件信號燈
Event() 創(chuàng)建一個線程共享事件信號燈
Lock() 創(chuàng)建一個線程共享鎖
Rlock() 創(chuàng)建一個線程共享可重入視頻
Queue() 創(chuàng)建一個共享先進先出隊列
Semaphore() 創(chuàng)建一個線程共享信號量
-
managers
-
BaseManager類
原理: 通過Manager啟動一個server進程監(jiān)聽socket,其他進程通過使用socket與主進程進行聯(lián)系,進行信息交換
定義 BaseManager(address=(ip,端口),authkey=秘鑰)
創(chuàng)建一個服務(wù)器Manager對象,其他客戶端Manager通過與此對象連接,進行數(shù)據(jù)交換
-
常用方法
start()
啟動服務(wù)進程
get_server()
返回一個服務(wù)對象
server_forever()
永遠執(zhí)行下去
connect()
將本地管理器連接到主服務(wù)管理器上
shuntdown()
關(guān)閉本管理器
register(對外暴露的方法名,callable=返回對象的函數(shù))
-
分布式進程 Master-Worker模式
- Master 負責分發(fā)任務(wù),并接受返回的最終結(jié)果
from multiprocessing.managers import BaseManager
import multiprocessing
import time
class Master(BaseManager):
pass
task_que = multiprocessing.Queue()
result_que = multiprocessing.Queue()
def returntaskque():
return task_que
def returnresultque():
return result_que
if __name__ == '__main__':
ip = 'XXXXXXXXXXXXXX'
port = 8888
key = b'123'
server = Master((ip,port),key)
server.register('get_task_que', callable=returntaskque)
server.register('get_result_que', callable=returnresultque)
server.start()
task = server.get_task_que()
result = server.get_result_que()
num = 0
while True:
num += 1
task.put('工作%s'%num)
time.sleep(1)
if not result.empty():
print('結(jié)果是:%s'%result.get())
- Worker 負責處理任務(wù),并返回結(jié)果
from multiprocessing.managers import BaseManager
import time
class Worker(BaseManager):
pass
if __name__ == '__main__':
ip = 'XXXXXXXXXXXXXX'
port = 8888
key = b'123'
worker = Worker((ip,port),key)
worker.register('get_task_que')
worker.register('get_result_que')
worker.connect()
task = worker.get_task_que()
result = worker.get_result_que()
while True:
if not task.empty():
data = task.get()
print('收到{0}'.format(data))
time.sleep(2)
result.put('完成{0}'.format(data))
time.sleep(1)
迭代器 Iterator
一次產(chǎn)生一個對象,可以裝下無限大的對象
可迭代 Iterable 可用于for循環(huán)的對象
迭代器一定是一個可迭代的,但是可迭代的不一定是迭代器
-
將一個可迭代對象轉(zhuǎn)換為迭代器
-
通過iter()
函數(shù)
from collections import Iterator
list = [i for i in range(5)]
print(isinstance(list, Iterator))
list = iter(list)
print(isinstance(list, Iterator))
# > False
# > True
-
通過__iter__()
函數(shù)
from collections import Iterator
list = [i for i in range(5)]
print(isinstance(list, Iterator))
list = list.__iter__()
print(isinstance(list, Iterator))
# > False
# > True
-
使用方式
-
使用for
循環(huán)
for i in list:
print(i)
-
使用next()
函數(shù),直到?jīng)]有值拋出StopIteration
異常
list = iter([i for i in range(5)])
next(list)
next(list)
....
-
使用__next__()
函數(shù),直到?jīng)]有值拋出StopIteration
異常
list = iter([i for i in range(5)])
list.__next__()
list.__next__()
....
生成器
一邊循環(huán),一邊計算下一個對象,直到遇見yield語句后停止,每次調(diào)用只返回一個值
-
滿足三個條件
每次調(diào)用都產(chǎn)生一個用于for循環(huán)遍歷的對象
元素到達最后一個后拋出StopIteration
異常
可以被next調(diào)用
-
定義生成器
-
直接使用生成器
列表生成表達式 list = [i for i in range(5)]
生成器 gen = (i for i in range(5))
-
函數(shù)中包含yield
語句
def func(n):
st = '產(chǎn)品'
num = 0
while num < n:
yield st+str(num)
num += 1
g = func(5)
print(list(g)) # 將生成器轉(zhuǎn)化為列表,方便查看,也可以使用next(g)挨個輸出值
# > ['產(chǎn)品0', '產(chǎn)品1', '產(chǎn)品2', '產(chǎn)品3', '產(chǎn)品4']
-
可使用send()
函數(shù)向生成器發(fā)送值
- 注意: 生成器每執(zhí)行一次都會在yield處停止,yield前的變量可以接收send發(fā)送的值,yield后是生成器返回的值
def func():
num = yield
print(num)
g = func()
next(g)
g.send(5)
# > 5
特別注意: 無論是next()
還是send()
,調(diào)用后都會在下一個yield語句處停止
-
yield from
相當于中間層,每當生成器生成一個元素,都由中間層將元素傳遞給主函數(shù)
包含yield from
的生成器叫做委派生成器
def func():
yield from 'asds'
g = func()
print(next(g))
print(next(g))
print(next(g))
print(next(g))
# > a
# > s
# > d
# > s
協(xié)程
非搶占式多任務(wù),協(xié)程允許不同入口點不同位置執(zhí)行程序
多線程之間的切換會消耗一定的資源,一些高并發(fā)的程序在執(zhí)行時,如果使用多線程,多線程之間的切換會消耗大量的資源和時間,但協(xié)程之間的切換卻消耗的資源少
-
協(xié)程的實現(xiàn)
使用next()
預(yù)激協(xié)程
使用yield
獲取返回值
使用send()
發(fā)送值
-
協(xié)程的四個狀態(tài)
GEN-CREATED 等待開始執(zhí)行
GEN-RUNNING 解釋器正在執(zhí)行
GEN-SUSPENED 在yield語句處暫停
GEN-CLOSED 執(zhí)行結(jié)束
-
協(xié)程終止
- 可以使用哨兵值結(jié)束
-
獲取協(xié)程的返回值
import time
def average():
sum = 0
count = 0
avrge = 0
while True:
data = yield (avrge,sum,count)
if data == None:
break
sum = sum + data
count += 1
avrge = sum / count
print('協(xié)程結(jié)束')
g = average()
next(g)
for i in range(1,20,3):
avr,sum,count = g.send(i)
print('總數(shù)為:{0} , 個數(shù)為:{1} , 平均數(shù)為{2}'.format(sum,count,avr))
time.sleep(1)
協(xié)程的消費者-生產(chǎn)者模型
import time
def Producer():
num = 0
while True:
num += 1
print('生產(chǎn)者:總產(chǎn)品為%s'%num)
num = yield num
time.sleep(0.5)
def Consumer():
num = 0
while True:
num = yield num
num -= 1
print('消費者:總產(chǎn)品為%s'%num)
time.sleep(0.5)
p = Producer()
c = Consumer()
num = next(p)
next(c)
while True:
num = c.send(num)
num = p.send(num)
結(jié)構(gòu)化文件儲存
為了解決不同設(shè)備之間的數(shù)據(jù)交換
-
xml庫
-
構(gòu)成: 處理指令,xml版本和編碼
根元素: 樹形結(jié)構(gòu)的根元素,有且只能有一個
子元素: 可以有多個
屬性: 定義在括號中
內(nèi)容: 標簽中定義的信息
注釋: 使用``
-
保留字符
轉(zhuǎn)義 保留字符需要用轉(zhuǎn)義進行代替
CDATA定義的字符不進行轉(zhuǎn)義,相當于python中的r''
, <!{CDATA[不需要進行轉(zhuǎn)義的字符]}>
-
命名空間
xmlns,是xml name space的縮寫
直接在標簽中添加相應(yīng)空間
-
SAX (Simple API for xml)
基于事件驅(qū)動
包含解析器和事件處理兩個部分
流式讀取
速度快
-
DOM (Document Object Model)
-
minidom類
parse(file)
打開xml文件,返回節(jié)點樹
documentElement
返回xml的根節(jié)點
creatElement(tag)
創(chuàng)建新節(jié)點
createAttribute(attr)
創(chuàng)建此節(jié)點的新屬性
getElementsByTagName(tag)
獲取此節(jié)點下的名為tag標簽的集合
getAttribute(attr)
返回此節(jié)點的attr屬性的值
parentNode
返回當前節(jié)點的父節(jié)點
previousSibling
返回此節(jié)點的前一個兄弟節(jié)點
nextSibling
返回此節(jié)點的下一個兄弟節(jié)點
childNodes
返回當前節(jié)點的子節(jié)點列表
firstChild
返回第一個子節(jié)點
lastChild
返回最后一個子節(jié)點
nodeName
返回此節(jié)點的標簽名
注意:節(jié)點中的漢字也是有節(jié)點的,是text節(jié)點
-
etree.ElementTree類
Element(標簽名)
創(chuàng)建一個節(jié)點
SubElement(parent,tag)
生成一個子節(jié)點,并添加到調(diào)用函數(shù)的節(jié)點
ElementTree(tag)
生成一個節(jié)點樹,將tag標簽作為根
節(jié)點樹.write(file)
將節(jié)點樹寫入文件
set(key,vlue)
修改屬性
append(子節(jié)點)
此節(jié)點最后添加子節(jié)點
remove(子節(jié)點)
刪除此節(jié)點子節(jié)點
parse(file)
打開xml文件,返回節(jié)點樹
getroot()
返回節(jié)點樹的根節(jié)點
iter(tag)
返回此節(jié)點下的所有節(jié)點,如果指定標簽名,則遍歷所有指定標簽名
find()
查找第一個匹配的節(jié)點
findall()
查找此節(jié)點下所有匹配的子節(jié)點,返回集合
tag
標簽名
text
標簽的文本值
attrib
返回標簽所有屬性的字典
# 利用etree創(chuàng)建一個xml文件
import xml.etree.ElementTree
root = xml.etree.ElementTree.Element('Root')
name = xml.etree.ElementTree.SubElement(root,'Name')
name.text = 'Jack'
age = xml.etree.ElementTree.SubElement(root,'Age')
age.text = '22'
tree = xml.etree.ElementTree.ElementTree(root)
tree.write('a.xml')
-
json庫
輕量級的數(shù)據(jù)交換工具 (JavaScripObjectNotation)
類似于字典,基于key-value形式
-
常用函數(shù)
-
以文件形式存在
dump(file)
寫入文件,轉(zhuǎn)化為json對象
load(file)
讀取文件,轉(zhuǎn)化為python對象
-
以數(shù)據(jù)形式存在
dumps(data)
寫入內(nèi)容,轉(zhuǎn)化為json對象
loads(data)
讀取內(nèi)容,轉(zhuǎn)化為python對象
import json
data = {
'name':'jack',
'age':18,
'sex':'male'
}
# 寫入json文件
with open('a.json','w')as f:
json.dump(data,f)
#讀取json文件
with open('a.json','r')as f:
data = json.load(f)
print(type(data))
print(data)
# > <class 'dict'>
# > {'name': 'jack', 'age': 18, 'sex': 'male'}
re 正則表達式模塊
-
轉(zhuǎn)義字符
-
重復(fù)限定符
.
匹配除換行符\n之外的所有字符
^
匹配字符串開頭
$
匹配字符串結(jié)尾
*
匹配前一個字符0次以上,貪婪模式
+
匹配前一個字符1次以上,貪婪模式
?
匹配前一個字符0次或1次,貪婪模式
{m,n}
匹配前一個字符至少m次,最多n次,當沒有n時則為無限次,貪婪模式
[]
字符集,匹配字符集中的任意字符,字符客單個給出,也可范圍給出
()
分組,分組從0開始
|
或者
*? +? ?? {m,n}?
非貪婪模式,盡可能少的匹配字符
import re
text = '<div>name</div><div>age</div>'
regex = re.search(r'<div>.*?</div>',text)
print(regex.group())
# > <div>name</div>
-
特殊字符集
r
原始字符串,字符串中的特殊字符不需要再進行轉(zhuǎn)義,否則則需要使用\
進行轉(zhuǎn)義
[\u4E00-\u9FA5]
漢字
\b
單詞邊界
\d
數(shù)字 [0-9]
\s
任何空白字符 [\n\t\r\f\v<空格>]
\w
匹配包括下劃線的任何字字符 [A-Za-z0-9_]
除漢字外,上述特殊集大寫為與之相反的意思
-
flags 編譯標志位
re.I
不區(qū)分大小寫
re.M
多行匹配
re.U
根據(jù)Unicode字符集解析字符
re.S
使.匹配包括換行符在內(nèi)的所有字符
-
compile(pattern)
編譯正則表達式,返回正則表達式對象
- 正則表達式對象可以直接調(diào)用以下函數(shù),也可使用re進行調(diào)用.
import re
text = 'https://docs.python.org/3/library/re.html#regular-expression-syntax'
#使用re進行調(diào)用
regex = re.search(r'\d',text)
print(regex)
# > <_sre.SRE_Match object; span=(24, 25), match='3'>
#使用compile調(diào)用
par = re.compile(r'\d')
regex = par.search(text)
print(regex)
# > <_sre.SRE_Match object; span=(24, 25), match='3'>
search(pattern,string[,flags])
查找,查找字符串的所有位置,返回一個匹配對象
match(pattern,string[,flags])
匹配,匹配字符串的開頭位置,與search不同,返回一個匹配對象
import re
text = 'https://docs.python.org/3/library/re.html#regular-expression-syntax'
regex = re.match('library',text)
print(regex)
# > None
regex = re.match('https',text)
print(regex)
# > <_sre.SRE_Match object; span=(0, 5), match='https'>
-
findall(pattern,string[,flags])
查找字符串中所有匹配正則表達式的內(nèi)容,返回一個匹配的字符串列表
import re
text = 'https://docs.python.org/3/library/re.html#regular-expression-syntax'
list = re.findall('o',text)
print(list)
# > ['o', 'o', 'o', 'o']
-
split(pattern,string[,flags])
按照正則表達式分割字符串對象,將正則表達式中的匹配選項替換為''
,并返回一個分割的字符串列表
import re
text = 'https://docs.python.org/3/library/re.html#regular-expression-syntax'
list = re.split(r'/',text)
print(list)
# > ['https:', '', 'docs.python.org', '3', 'library', 're.html#regular-expression-syntax']
-
sub(pattern,repl,string,count)
替換查找的字符串
import re
text = 'https://docs.python.org/3/library/re.html#regular-expression-syntax'
# 將所有字符替換為@
regex = re.sub(r'\W','@',text)
print(regex)
# > https@@@docs@python@org@3@library@re@html@regular@expression@syntax
-
Match 匹配對象
- 下面的regex即為一個匹配對象
import re
text = 'https://docs.python.org/3/library/re.html#regular-expression-syntax'
regex = re.search(r'\d',text)
# > <_sre.SRE_Match object; span=(24, 25), match='3'>
匹配對象的布爾值始終為True,一旦沒有匹配到的對象,則返回None
group(index)
當index沒有或者為0時,返回匹配對象的整個字符串,當index不為0時,返回正則表達式中用()括起來的字符
regex.group()
# > 3
-
groups()
返回被匹配字符串的元組
regex = re.search(r'(org).+(syntax$)',text)
# > ('org', 'syntax')
-
start()
返回匹配開始位置
regex.start()
# > 24
-
end()
返回匹配結(jié)束位置
regex.end()
# > 25
-
span()
返回包含start和end的元組
regex.span()
# > (24, 25)
封裝,對類的成員訪問進行限制
-
public 公開
- 公開成員舱权,都可以進行訪問
-
protected 受保護
受保護成員矗晃,只能在類、子類宴倍、對象中進行訪問
定義:使用
_成員
進行定義
class Person(): _name = 'NoName' _age = 24 class Student(Person): pass s = Student() print(s._name,s._age) # > NoName 24 #可以看出张症,子類和子類的對象訪問都是沒有問題的
-
private 私有
私有成員,只能在當前類中進行訪問
注意:子類不繼承私有成員
定義:使用
__成員
進行定義
class Person(): __name = 'NoName' __age = 24 class Student(Person): pass p = Person() print(p.__name, p.__age) # > AttributeError: 'Person' object has no attribute '__name' s = Student() print(s.__name, s.__age) # > AttributeError: 'Student' object has no attribute '__name' #可以看出鸵贬,子類并沒有繼承父類中的私有屬性,而且對象也不允許使用私有成員
繼承
-
類成員擴充俗他,當子類繼承了父類時,就擁有了父類除私有成員以外的所有其他成員阔逼,這相當于將子類成員指向父類成員的地址兆衅,同時,還可以繼續(xù)添加相應(yīng)的屬性和函數(shù)
class Person(): def talk(self): print('talk') class Student(Person): def study(self): print('study') s = Student() s.talk() # > talk s.study() # > study
-
子類擴充父類函數(shù)方法
-
使用self嗜浮,其中self指的是子類本身
class Person(): def talk(self): print('talk') class Student(Person): def talk(self): Person.talk(self) print('擴充函數(shù)') s = Student() s.talk() # > talk # > 擴充函數(shù)
-
使用super羡亩,指的是父類
class Person(): def talk(self): print('talk') class Student(Person): def talk(self): super().talk() print('擴充函數(shù)') s = Student() s.talk() # > talk # > 擴充函數(shù)
-
-
MRO鉆石繼承\(zhòng)菱形繼承(繼承順序)
子類永遠在父類前面
根據(jù)括號內(nèi)繼承的順序存放
繼承的多個類中,有共同的父類危融,子類只會繼承括號中第一個父類的父類
-
單繼承
單繼承隱患少畏铆,但不利于擴展功能
子類如果沒有構(gòu)造函數(shù),則會查找父類的構(gòu)造函數(shù)吉殃,如果都沒有辞居,那么就一直向上查找。按照MRO順序
class Person(): def talk(self): print('talk') class Student(Person): def talk(self): super().talk() print('asdasd') print(Student.mro()) # > [<class '__main__.Student'>, <class '__main__.Person'>, <class 'object'>] #可以看出蛋勺,Student類的MRO順序為Student瓦灶、Person、object
-
多繼承
擴展類的功能方便但隱患多
繼承方式按照MRO順序
class Animal(): def sleep(self): print('sleep') class Person(): def talk(self): print('talk') class Student(Person,Animal): pass s = Student() s.talk() s.sleep() # > talk # > sleep print(Student.mro()) #[<class '__main__.Student'>, <class '__main__.Person'>, <class '__main__.Animal'>, <class 'object'>] #可以看出繼承順序遵照MRO順序
-
Mixin設(shè)計模式
我認為主要是為了避免繼承關(guān)系的混亂抱完,為了讓代碼可以進行更改的維護贼陶,已經(jīng)實現(xiàn)類中方便的功能增減
Mixin類中必須定義單一功能
子類不繼承Mixin類,只是缺少某項功能乾蛤,但不影響子類的正常使用
Mxin功能不依賴子類進行實現(xiàn)
class TalkMixin(): def talk(self): print('talk') class EatMixin(): def eat(self): print('eat') class SleepMixin(): def sleep(self): print('sleep') class Person(TalkMixin,EatMixin,SleepMixin): pass p = Person() p.talk() p.eat() p.sleep() # >talk # >eat # >sleep
多態(tài)
同一對象在不同狀態(tài)的不同功能
注意:在Python中沒有對應(yīng)的語法
變量 = 類名()
檢查類中的所有成員每界,使用類名.__dict__
訪問類的成員屬性,使用類名.屬性
訪問類的成員函數(shù)家卖,使用類名.函數(shù)名()
魔法函數(shù)(不需要自己進行調(diào)用眨层,但滿足某些特定條件時,會自動調(diào)用)
-
__init__
構(gòu)造方法在實例化類的時候可以向其中傳遞參數(shù)
在將類實例化對象時上荡,會自動調(diào)用
此函數(shù)也可以進行擴充
class Person(): def __init__(self,name,age): self.name = name self.age = age def say(self): print('My name is {0},I am {1} years old.'.format(self.name,self.age)) p = Person('jack',24) p.say() # > My name is jack,I am 24 years old. p.name = 'bob' p.age = 18 p.say() # > My name is bob,I am 18 years old.
-
__call__
方法- 將對象當做函數(shù)執(zhí)行時調(diào)用
class Person(): def __init__(self,name,age): self.name = name self.age = age def __call__(self, *args, **kwargs): print('為什么要執(zhí)行我趴樱?') p = Person('jack',24) p() # > 為什么要執(zhí)行我馒闷?
-
__str__
方法- 將對象打印時,輸出的方法
class Person(): def __str__(self): return '打印了一個Person類的實例' p = Person() print(p) # > 打印了一個Person類的實例
實例方法
也就是非綁定方法叁征,只有當類實例化后纳账,才可以使用的方法
詳情參照self-非綁定方法
靜態(tài)方法
采用@staticmethod裝飾
里面沒有self參數(shù)
-
注意,這里和綁定方法有區(qū)別
綁定方法捺疼,只能通過
類名.方法名()
調(diào)用疏虫,如果采用對象調(diào)用就會報錯靜態(tài)方法,既可以通過類來調(diào)用啤呼,也可以通過對象調(diào)用
class Person():
@staticmethod
def say():
print('say')
p = Person()
Person.say()
# > say
p.say()
# > say
類方法
采用@classmethod裝飾
不需要實例化就可以使用
方法中傳入的是cls卧秘,也就是類對象
class Person():
@classmethod
def say(cls):
print('say')
p = Person()
Person.say()
p.say()
總結(jié):無論是實例方法、靜態(tài)方法官扣、類方法都可以使用對象進行調(diào)用翅敌,但是實例方法必須實例化后才可以使用;靜態(tài)方法惕蹄、類方法可以直接用類名進行調(diào)用
注意:靜態(tài)方法不是綁定方法
property
- 主要是將對函數(shù)的訪問裝飾起來變?yōu)閷傩缘脑L問
#例如蚯涮,我們需要定義一個Person類,但是需要對Person類中傳入的幾個屬性進行檢查卖陵,那么這時候property就派上用場了
class Person():
_name = 'Noname'
_age = 0
#此時遭顶,我們想對age的值進行檢查,不允許小于0
#我們就可以定義一個property的裝飾器赶促,將函數(shù)偽裝為變量進行訪問
-
調(diào)用Property裝飾器
@property def age(self): print('調(diào)用get') return self._name @age.setter def age(self,value): print('調(diào)用set') if value > 0: self._age = value else: print('不允許負值') @age.deleter def age(self): print('調(diào)用del') del (self._age) p = Person() p.age = -15 # > 調(diào)用get # > 不允許負值
-
調(diào)用property方法
屬性 = property( fget, fset, fdel, doc)
def get_age(self): print('調(diào)用get_age') return self._age def set_age(self,value): print('調(diào)用set_age') if value > 0: self._age = value else: print('不允許是負值') def del_age(self): print('調(diào)用del_age') del self._age age = property(get_age,set_age,del_age) p = Person() p.age = -15 # > 調(diào)用get # > 不允許是負值
類的描述符
只要包含了
__get__
液肌、__set__
、__del__
三個方法中的一個就是描述符描述符的作用鸥滨,對類的屬性進行限制操作
-
__get__(self,instance,owner)
方法和__set__(self, instance, value)
方法class Dscrip(): def __init__(self,property_name): self.property_name = property_name def __get__(self, instance, owner): print('調(diào)用了get方法') print('self:%s'%self) print('*'*20) print('instance:%s'%instance) print('*' * 20) print('owner:%s'%owner) print('-'*20) def __set__(self, instance, value): print('調(diào)用了set方法') print('self:%s' % self) print('*' * 20) print('instance:%s' % instance) print('*' * 20) print('value:%s'%value) print('-' * 20) class Person(): name = 'Noname' age = Dscrip('age') def __init__(self,name,age,sorce): self.name = name self.age = age self.sorce =sorce p = Person('jack',24,60) p.age print('p:%s'%p) # > 調(diào)用了set方法 # > self:<__main__.Dscrip object at 0x000001F71AD78EF0> # > ******************** # > instance:<__main__.Person object at 0x000001F71AD78F60> # > ******************** # > value:24 # > -------------------- # > 調(diào)用了get方法 # > self:<__main__.Dscrip object at 0x000001F71AD78EF0> # > ******************** # > instance:<__main__.Person object at 0x000001F71AD78F60> # > ******************** # > owner:<class '__main__.Person'> # > -------------------- # > p:<__main__.Person object at 0x000001F71AD78F60> #在這里我們我們打印了get、set方法中的self谤祖、instance婿滓、owner的值 #可以看出self 指的是一個Dscrip類,在Person類中粥喜,指的就是age變量 #instance 和我們打印對象p的地址一致凸主,instance就是指的對象p #owner 是一個名為Person的類 #value 就是我們傳入對象p中age的值
-
總結(jié):
在get和set方法中,self指的就是我們定義的類描述符的實例對象额湘,也就是類中的屬性
在get和set方法中卿吐,instance指的是包含了該實例對象的實例化類對象
在set方法中,value就是傳入該類對象的值
-
使用類的描述符進行多個類屬性檢查
#上面學習了如何使用property對屬性進行檢查 #現(xiàn)在如果我想要將Person類中新定義一個sorce锋华,并且也進行檢查嗡官,此時如果使用property就會顯得異常繁雜 #這時候就可以使用類的描述符了 class Desc(): def __init__(self, propertyname): self.propertyname = propertyname def __get__(self, instance, owner): if instance is None: return self return instance.__dict__[self.propertyname] def __set__(self, instance, value): if value < 0: print('不允許是負值') else: instance.__dict__[self.propertyname] = value def __del__(self): del self.propertyname class Person(): age = Desc('age') sorce = Desc('sorce') def __init__(self, name, age, sorce): self.name = name self.age = age self.sorce = sorce p = Person('jack',18,60) p.sorce = -5 # > 不允許是負值 #這樣就檢查了兩個屬性age、sorce,從而避免了寫多個property
類的常用函數(shù)
__dict__
: 獲取類和對象中的所有成員屬性hasattr
: 檢測某類中是否有某屬性issubclass
: 檢測某類是否是另一個類的子類isinstance
: 檢測某個對象是否是一個類的實例getattr
: 獲取某個對象的某個屬性值__getattribute__
:獲取某個對象的某個屬性值setattr
: 設(shè)置某個對象的某個屬性值delattr
: 刪除某個對象的某個屬性-
__slots__
: 在類的開頭定義一個slots的元組毯焕,實例化對象后衍腥,對象只能添加元組中定義的屬性如果子類中沒有定義slots,那么子類不存在slots限制
如果子類中定義了slots,那么子類中slots的限制是子類和父類元組相加的限制
對類的實例對象進行動態(tài)綁定
-
動態(tài)綁定屬性,使用
對象.屬性 = 值
綁定class Person(): pass p = Person() p.name = 'jack'
-
動態(tài)綁定函數(shù)婆咸,使用
對象.方法名 = types.MethodType(方法名竹捉,對象)
綁定import types class Person(): pass def say(): print('say') p = Person() p.say = types.MethodType(say, p)
注意:此時綁定的方法只對綁定的該實例對象有效,如果重新定義一個對象尚骄,此方法就失效了
對類進行動態(tài)綁定
-
類.方法名 = 方法名
綁定class Person(): pass def say(): print('say') Person.say = say Person.say()
-
類名.方法名 = types.MethodType(方法块差,類名)
綁定- 用法參照對象綁定
定義抽象類是為了讓其子類必須實現(xiàn)抽象類中的屬性或者方法,對子類進行規(guī)范化倔丈,設(shè)定子類的標準
抽象類只能被繼承使用憾儒,不可以進行實例化
定義抽象使用class 抽象類名(metaclass = abc.ABCMeta)
定義抽象方法使用@abc.abstractclassmethod
import abc
class Man(metaclass= abc.ABCMeta):
@abc.abstractmethod
def say(self):
pass
@abc.abstractmethod
def eat(self):
pass
class Person(Man):
'''
def say(self):
pass
def eat(self):
pass
'''
pass
p = Person()
# > TypeError: Can't instantiate abstract class Person with abstract methods eat, say
#如果子類中不定義抽象方法就會報錯
包的結(jié)構(gòu)
__init__.py
包的標志文件模塊
子包
導(dǎo)入包
import 包名
import 包名.模塊名
-
導(dǎo)入后可以使用
__init__.py
中定義的文件__init__.py
里如果定義了__all__
,就只能使用__all__
里面定義的內(nèi)容__init__.py
里如果沒有定義__all__
乃沙,就可以使用全部文件
模塊
-
定義模塊的規(guī)范
函數(shù)起趾,單一功能
類
測試代碼
if __name__ = 'main':
代表此模塊作為主線程執(zhí)行時就執(zhí)行以下內(nèi)容
-
導(dǎo)入模塊
import 模塊名
from 模塊名 import 類名
import 模塊名 as 別名
-
模塊、包的查找路徑
默認路徑警儒,可使用
sys.path
查看添加路徑训裆,
sys.path.append()
,也就是向列表中添加一個新元素
-
模塊的加載順序
內(nèi)存中已經(jīng)加載好的模塊
Python中內(nèi)置的模塊
按順序查找sys.path中的內(nèi)容
異常是一個類蜀铲,可以進行處理和使用
常見異常錯誤類
AssertErro 斷言語句失敗
AttributeErro 嘗試方問未知的對象屬性
FloatingPointErro 浮點計算錯誤
ImportErro 導(dǎo)入模塊失敗
IndexErro 下標引索值超出序列的范圍
KeyErro 字典中查找一個不存在的關(guān)鍵字
NameErro 嘗試訪問一個不存在的變量
RuntimeErro 運行錯誤
OSErro 操作系統(tǒng)產(chǎn)生異常
SynataxErro 語法錯誤
IndentationErro 縮進錯誤
TypeErro 不同類型間的無效操作
異常處理
try:
問題語句
except 異常類 as e: #將異常類實例化為e
print(e)
else:
不出錯執(zhí)行語句
finally:
無論是否出錯都執(zhí)行的語句
手動引發(fā)異常
raise 異常類
注意:推薦使用自定義異常边琉,并且標注清楚。方便別人或者自己進行查看和快速定位
自定義異常類
自定義異常必須是系統(tǒng)異常的子類
拋出異常時的文字提示
異常發(fā)生的行數(shù)
calendar() 以字符串形式返回某年的日歷
isleap() 判斷某年是否是閏年
leapdays() 獲取指定年份之間的閏年個數(shù)
month() 以字符串形式返回某年某月的日歷
monthrange() 獲取某年某月第一天是周幾和某月的天數(shù)记劝,返回的是一個元組
monthcalendar() 返回某年某月以二維列表組成的矩陣变姨,其中每周組成一個列表
weekday() 獲取某年某月某日是周幾
import calendar
c = calendar.calendar(2018)
print(c)
2018
January February March
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 4 5 6 7 1 2 3 4 1 2 3 4
8 9 10 11 12 13 14 5 6 7 8 9 10 11 5 6 7 8 9 10 11
15 16 17 18 19 20 21 12 13 14 15 16 17 18 12 13 14 15 16 17 18
22 23 24 25 26 27 28 19 20 21 22 23 24 25 19 20 21 22 23 24 25
29 30 31 26 27 28 26 27 28 29 30 31
April May June
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 1 2 3 4 5 6 1 2 3
2 3 4 5 6 7 8 7 8 9 10 11 12 13 4 5 6 7 8 9 10
9 10 11 12 13 14 15 14 15 16 17 18 19 20 11 12 13 14 15 16 17
16 17 18 19 20 21 22 21 22 23 24 25 26 27 18 19 20 21 22 23 24
23 24 25 26 27 28 29 28 29 30 31 25 26 27 28 29 30
30
July August September
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 1 2 3 4 5 1 2
2 3 4 5 6 7 8 6 7 8 9 10 11 12 3 4 5 6 7 8 9
9 10 11 12 13 14 15 13 14 15 16 17 18 19 10 11 12 13 14 15 16
16 17 18 19 20 21 22 20 21 22 23 24 25 26 17 18 19 20 21 22 23
23 24 25 26 27 28 29 27 28 29 30 31 24 25 26 27 28 29 30
30 31
October November December
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 4 5 6 7 1 2 3 4 1 2
8 9 10 11 12 13 14 5 6 7 8 9 10 11 3 4 5 6 7 8 9
15 16 17 18 19 20 21 12 13 14 15 16 17 18 10 11 12 13 14 15 16
22 23 24 25 26 27 28 19 20 21 22 23 24 25 17 18 19 20 21 22 23
29 30 31 26 27 28 29 30 24 25 26 27 28 29 30
31
print(calendar.isleap(2018))
# > False
print(calendar.leapdays(1990,2018))
# > 7
m = calendar.month(2018,8)
print(m)
# > August 2018
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 29 30 31
week,day = calendar.monthrange(2018,8)
print(week)
print(day)
# > 2
# > 31
list = calendar.monthcalendar(2018,8)
for i in list:
print(i)
# > [0, 0, 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, 29, 30, 31, 0, 0]
print(calendar.weekday(2018,8,7))
# > 1
time() 指一個時間戳,是從1970年1月1日0時到至今所經(jīng)歷的秒數(shù)
import time
print(time.time())
# > 1533604231.9603899
時間元組厌丑,是一個包含時間內(nèi)容的元組定欧,組成由(年,月怒竿,日砍鸠,時,分耕驰,秒爷辱,周幾,年的第幾天朦肘,夏令時)
localtime() 獲取當前時間的元組
import time
print(time.localtime())
# > time.struct_time(tm_year=2018, tm_mon=8, tm_mday=7, tm_hour=9, tm_min=14, tm_sec=51, tm_wday=1, tm_yday=219, tm_isdst=0)
timezone 標準時區(qū)與當前時區(qū)相差的秒數(shù)
import time
print(time.timezone)
# > -28800
#中國是東8區(qū)饭弓,相比于國際時間,要快8小時媒抠,28800/60/60 = 8
asctime() 返回系統(tǒng)格式化后的時間
import time
print(time.asctime())
# > Tue Aug 7 09:20:40 2018
ctime() 返回系統(tǒng)格式化后的時間
import time
print(time.ctime)
# > Tue Aug 7 09:21:37 2018
maketime() 將時間元組變成時間戳
import time
t = time.localtime()
s = time.mktime(t)
print(s)
# > 1533605096.0
sleep() 使程序休眠指定秒數(shù)后繼續(xù)執(zhí)行
import time
for i in range(1,11):
time.sleep(1)
print(i)
# > 1
# > 2
# > ....
strftime() 自定義格式化時間弟断,作用于時間元組
%Y 完整年份
%m 月份
%d 每月中的第幾天
%H 24小時制
%M 分鐘 60
%S 秒 60
import time
t = time.localtime()
st = time.strftime('%Y-%m-%d %H:%M:%S',t)
print(st)
# > 2018-08-07 09:41:23
注意:
print(time.strftime('%Y年%m月%d日 %H時%M分%S秒',time.localtime()))
同樣方法,在windows下報錯
UnicodeEncodeError: 'locale' codec can't encode character '\u5e74' in position 2: Illegal byte sequence
在ubuntu下正常執(zhí)行领舰,返回
2018年08月06日 20時28分31秒
strptime() 將時間字符串格式化為時間元組
import time
st = '2018-8-7 12:00:00'
t = time.strptime(st,'%Y-%m-%d %H:%M:%S')
print(t)
# > time.struct_time(tm_year=2018, tm_mon=8, tm_mday=7, tm_hour=12, tm_min=0, tm_sec=0, tm_wday=1, tm_yday=219, tm_isdst=-1)
date類 提供一個理想的日期
year 屬性
month 屬性
day 屬性
today() 返回當前日期
fromtimestamp() 從一個時間戳中獲得日期
strftime() 自定義格式化日期
import datetime
dt = datetime.datetime(2018,8,7) #將2018.8.7實例化為datetime類
print(dt.year)
# > 2018
print(dt.month)
# > 8
print(dt.day)
# > 7
dt = datetime.datetime.today()
print(dt)
# > 2018-08-07 13:49:04.943500
import time
t = time.time() #獲取當前時間的時間戳
dt = datetime.datetime.fromtimestamp(t)
print(dt)
# > 2018-08-07 13:51:44.969500
print(dt.strftime('%Y.%m.%d'))
# > 2018.08.07
datetime類 提供理想的日期和時間
year 屬性
month 屬性
day 屬性
hour 屬性
minute 屬性
second 屬性
mircosecond 屬性
today() 獲取當前日期和時間
fromtimestamp() 從時間戳中獲取日期和時間
timedelta類 提供日期和時間的計算
可以通過
days = 天數(shù) 夫嗓, hours = 小時數(shù) 迟螺, minutes = 分鐘數(shù)
進行實例化timedelta類 + date類或者datetime類 = date類或者datetime類
date類或者datetime類 - date類或者datetime類 = timedelta類
import datetime
dt1 = datetime.date(2018,6,15)
dt2 = datetime.date(2018,8,7)
td = dt2 - dt1
print(td)
# > 53 days, 0:00:00
print(type(td))
# > <class 'datetime.timedelta'>
dt3 = datetime.datetime(2018,6,15,8,30,15)
dt4 = datetime.datetime(2018,8,7,14,4)
td = dt4 - dt3
print(td)
# > 53 days, 5:33:45
td = datetime.timedelta(days=10,hours=15,minutes=30)
dt = datetime.datetime.now()
temp = dt + td
print(type(temp))
# > <class 'datetime.datetime'>
print(temp)
# > 2018-08-18 05:37:51.464770
timeit(smlt = 測試代碼,setup = 運行環(huán)境 舍咖,number = 重復(fù)次數(shù))
測試代碼時間
#現(xiàn)在我們測試一下列表生成式和循環(huán)加入列表中的兩個代碼誰執(zhí)行的快
import timeit
st1 = '[i for i in range(1000)]'
st2 = '''
list = []
for i in range(1000):
list.append(i)
'''
t1 = timeit.timeit(stmt = st1,number = 100000)
t2 = timeit.timeit(stmt = st2,number = 100000)
print(t1)
# > 3.6470414876165864
print(t2)
# > 9.188953135455993
#當測試帶參數(shù)的函數(shù)的寫法
import timeit
c = '''
def func(num):
for i in range(num):
print('repeat for {}'.format(i))
'''
t = timeit.timeit(stmt='func(num)', setup = c + 'num=2', number=100000)
print(t)
# > repeat for 1
# > repeat for 0
# > ....
# > 1.1565270608769294
絕對路徑 總是從根目錄上開始
D:\360安全瀏覽器下載\chromeinstall-8u151.exe
相對路徑 以當前所在工作目錄開始
\360安全瀏覽器下載\chromeinstall-8u151.exe
值
os.curdir
當前目錄,用‘ . ’表示os.pardir
父親路徑矩父,用‘ .. ’表示-
os.sep
系統(tǒng)分隔符windows下用‘ \ ’
linux下用‘ / ’
-
os.linesep
系統(tǒng)的換行符號windows下用‘ \r\n ’
linux下用‘ \n ’
-
os.name
系統(tǒng)名稱windows下用‘ nt ’
linux下用‘ posix ’
函數(shù)
getcwd()
返回當前工作目錄chdir()
改變工作目錄listdir()
顯示路徑下所有文件和文件夾,返回一個列表makedirs()
創(chuàng)建一個空文件夾rename()
重命名文件removedirs()
刪除空文件夾system()
運行系統(tǒng)shell命令getenv()
獲取當前系統(tǒng)環(huán)境變量值putenv()
添加環(huán)境變量exit()
退出當前程序
path類中的函數(shù)
abspath()
將路徑轉(zhuǎn)化為絕對路徑basename()
獲取路徑中的文件名部分dirname()
返回路徑中的文件夾部分split()
將路徑切割為文件夾和文件名組成的元組splittext()
將路徑切割為文件和后綴名組成的元組join()
將兩個路徑拼接成一個路徑exists()
判斷文件或文件夾是否存在isfile()
判斷是否為文件isdir()
判斷是否為文件夾getsize()
返回文件大小getatime()
返回文件或文件夾最后讀取時間ghetmtime()
返回文件或文件夾最后修改時間
copy()
復(fù)制文件排霉,還可以將文件重命名
copy2()
盡可能保留元數(shù)據(jù)的情況下復(fù)制文件
copyfile()
講一個文件里的內(nèi)容復(fù)制到另一個文件中
copytree()
復(fù)制文件夾里所有內(nèi)容
move()
移動文件或文件夾
rmtree()
刪除文件或文件夾下的所有文件
make_archive(壓縮后的名稱窍株,壓縮類型,需要壓縮的文件)
壓縮文件攻柠,返回壓縮文件的路徑
unpack_archive(壓縮包路徑球订,解包之后的路徑)
解壓文件
namedtuple類
是一個可以命名的元組類型
定義方式
類名 = collections.namedtuple(類類型,屬性組成的列表)
import collections
Point = collections.namedtuple('Point',['x','y'])
p = Point(15,22)
print(p)
# > Point(x=15, y=22)
deque類
解決頻繁插入瑰钮、刪除帶來的效率問題
定義方式:
對象 = collections.deque(列表)
import collections
d = collections.deque([1,2,3,4,5])
d.appendleft(10)
# > deque([10, 1, 2, 3, 4, 5])
defaultdict類
當讀取一個不存在的key時冒滩,返回一個默認值
-
定義方式:
對象 = collections.defaultdict(帶有返回值的函數(shù))
import collections def pr(): return '默認值' d = collections.defaultdict(pr) d['a'] = 1 d['b'] = 2 print(d) # > defaultdict(<function pr at 0x028AB6F0>, {'a': 1, 'b': 2}) print(d['dd']) # > 默認值
Counter類
- 主要是統(tǒng)計元素在迭代對象中出現(xiàn)的次數(shù),以元素:次數(shù)的字典形式返回
import collections
s = 'afjkasdhfklashgkjash'
dict = collections.Counter(s)
print(dict)
# > Counter({'a': 4, 'k': 3, 's': 3, 'h': 3, 'f': 2, 'j': 2, 'd': 1, 'l': 1, 'g': 1})
import collections
s = ['ss','jack','alice','bob','jack','jack','jack']
dict = collections.Counter(s)
print(dict)
# > Counter({'jack': 4, 'ss': 1, 'alice': 1, 'bob': 1})
dump(數(shù)據(jù),句柄)
浪谴,將數(shù)據(jù)持久化到文件
import pickle
file = r'C:\Users\wudi.HAPMMAGNA\Desktop\b.txt'
l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
with open(file, 'wb') as f:
pickle.dump(l,f)
#將數(shù)據(jù)以二進制方式寫入到b.txt文件中
load(句柄)
开睡,將持久化的數(shù)據(jù)提取到程序中
import pickle
file = r'C:\Users\wudi.HAPMMAGNA\Desktop\b.txt'
with open(file, 'rb') as f:
l = pickle.load(f)
print(l)
# > [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
#將b.txt文件中儲存的數(shù)據(jù)讀取到程序中
將數(shù)據(jù)以字典的形式寫入文件中
shelve只能允許一個句柄進行寫入,但可以允許多個句柄進行讀取
writeback = Ture
在關(guān)閉文件時苟耻,檢查更改篇恒,并將數(shù)據(jù)寫入文件
import shelve
file = r'C:\Users\wudi.HAPMMAGNA\Desktop\a'
sv = shelve.open(file,writeback= True)
sv['one'] = 1
sv['two'] = 2
sv['three'] = 3
sv.close()
# 此時桌面上出現(xiàn)了三個文件,為a.dat凶杖、a.bak胁艰、a.dir
import shelve
file = r'C:\Users\wudi.HAPMMAGNA\Desktop\a'
sv = shelve.open(file)
print(sv['one'])
sv.close()
# > 1
文件是一種長久保存信息數(shù)據(jù)的集合,保存在磁盤上
文件一旦被打開智蝠,就需要進行關(guān)閉操作腾么,否則可能造成文件信息的丟失
常用操作
-
讀寫模式
r
只讀,指針在文件開頭w
只寫寻咒,指針在文件開頭x
創(chuàng)建文件并只進行寫入哮翘,如果文件已經(jīng)存在則會報錯,指針在文件開頭a
追加寫入毛秘,指針在文件末尾b
以二進制方式t
以文本方式+
讀寫
-
open(文件地址,讀寫模式)
打開文件阻课、close()
關(guān)閉文件file = r'C:\Users\wudi.HAPMMAGNA\Desktop\b.txt' f = open(file) f.close()
-
with
語句使用上下文管理協(xié)議技術(shù)
自動關(guān)閉已經(jīng)不再使用的文件
推薦一定文件讀寫一定要使用with語句
file = r'C:\Users\wudi.HAPMMAGNA\Desktop\b.txt' with open(file,'wb') as f: pass
-
讀取操作
read(字符數(shù))
如果不使用字符數(shù)叫挟,那么read將會將所有字符讀取出來,如果指定字符限煞,就按照指定字符數(shù)進行讀取readline()
按行讀取文件內(nèi)容list(句柄)
將文件所有內(nèi)容讀取出來抹恳,以列表形式進行保存使用
while 數(shù)據(jù)
進行讀取,當數(shù)據(jù)不為空時署驻,就會一直循環(huán)下去奋献,如果數(shù)據(jù)為空時健霹,當前循環(huán)就會停止
# b.txt中有以下內(nèi)容 # 關(guān)雎 # 關(guān)關(guān)雎鳩,在河之洲瓶蚂。窈窕淑女糖埋,君子好逑。 # 參差荇菜窃这,左右流之瞳别。窈窕淑女,寤寐求之杭攻。 # 求之不得祟敛,寤寐思服。悠哉悠哉兆解,輾轉(zhuǎn)反側(cè)馆铁。 # 參差荇菜,左右采之锅睛。窈窕淑女埠巨,琴瑟友之。 # 參差荇菜乖订,左右芼之。窈窕淑女具练,鐘鼓樂之乍构。 file = r'C:\Users\wudi.HAPMMAGNA\Desktop\b.txt' with open(file, 'r') as f: data = f.read(1024) while data: print(data) data = f.read(1024) # > 關(guān)雎 # > 關(guān)關(guān)雎鳩,在河之洲扛点。窈窕淑女哥遮,君子好逑。 # > 參差荇菜陵究,左右流之眠饮。窈窕淑女,寤寐求之铜邮。 # > 求之不得仪召,寤寐思服。悠哉悠哉松蒜,輾轉(zhuǎn)反側(cè)扔茅。 # > 參差荇菜,左右采之秸苗。窈窕淑女召娜,琴瑟友之。 # > 參差荇菜惊楼,左右芼之玖瘸。窈窕淑女腹鹉,鐘鼓樂之哮肚。 with open(file, 'r') as f: data = f.readline() while data: print(data) data = f.readline() # > 關(guān)雎 # > # > 關(guān)關(guān)雎鳩岛抄,在河之洲挨队。窈窕淑女,君子好逑屯断。 # > # > 參差荇菜文虏,左右流之。窈窕淑女殖演,寤寐求之氧秘。 # > # > 求之不得,寤寐思服趴久。悠哉悠哉丸相,輾轉(zhuǎn)反側(cè)。 # > # > 參差荇菜彼棍,左右采之灭忠。窈窕淑女,琴瑟友之座硕。 # > # > 參差荇菜弛作,左右芼之。窈窕淑女华匾,鐘鼓樂之映琳。 with open(file,'r') as f: list3 = list(f) for i in list3: print(i) # > 結(jié)果同readline() ,為什么會出現(xiàn)這種情況蜘拉? 使用read時萨西,中間沒有隔行,而使用其他時就會有隔行呢旭旭? #我們來做個試驗谎脯,將所有讀取到的內(nèi)容添加到列表,看他們在列表中是如何組成的 file = r'C:\Users\wudi.HAPMMAGNA\Desktop\b.txt' list1 = [] list2 = [] with open(file, 'r') as f: data = f.read(1024) while data: list1.append(data) data = f.read(1024) with open(file, 'r') as f: data = f.readline() while data: list2.append(data) data = f.readline() with open(file,'r') as f: list3 = list(f) print(list1) print('@'*30) print(list2) print('@'*30) print(list3) # > ['關(guān)雎\n關(guān)關(guān)雎鳩持寄,在河之洲源梭。窈窕淑女,君子好逑稍味。\n參差荇菜咸产,左右流之。窈窕淑女仲闽,寤寐求之。\n求之不得僵朗,寤寐思服赖欣。悠哉悠哉屑彻,輾轉(zhuǎn)反側(cè)。\n參差荇菜顶吮,左右采之社牲。窈窕淑女,琴瑟友之悴了。\n參差荇菜搏恤,左右芼之。窈窕淑女湃交,鐘鼓樂之熟空。'] # > @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ # > ['關(guān)雎\n', '關(guān)關(guān)雎鳩,在河之洲搞莺。窈窕淑女息罗,君子好逑。\n', '參差荇菜才沧,左右流之迈喉。窈窕淑女,寤寐求之温圆。\n', '求之不得挨摸,寤寐思服。悠哉悠哉岁歉,輾轉(zhuǎn)反側(cè)得运。\n', '參差荇菜,左右采之刨裆。窈窕淑女澈圈,琴瑟友之。\n', '參差荇菜帆啃,左右芼之瞬女。窈窕淑女,鐘鼓樂之努潘。'] # > @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ # > ['關(guān)雎\n', '關(guān)關(guān)雎鳩诽偷,在河之洲。窈窕淑女疯坤,君子好逑报慕。\n', '參差荇菜,左右流之压怠。窈窕淑女眠冈,寤寐求之。\n', '求之不得,寤寐思服蜗顽。悠哉悠哉布卡,輾轉(zhuǎn)反側(cè)。\n', '參差荇菜雇盖,左右采之忿等。窈窕淑女,琴瑟友之崔挖。\n', '參差荇菜贸街,左右芼之。窈窕淑女狸相,鐘鼓樂之薛匪。'] # 可以看出,read中整個列表只有一個元素卷哩,也就是遇到'\n'時會自動進行換行蛋辈,而在其他函數(shù)中,列表中有多個元素将谊,遇到n時會換一次行冷溶,而單次打印內(nèi)容時也會換一次行。
-
寫入操作
write(數(shù)據(jù))
將單次數(shù)據(jù)寫入文件中writelines(數(shù)據(jù)序列)
將一個可迭代的數(shù)據(jù)序列按順序?qū)懭胛募?/p>
data = '我是數(shù)據(jù)' with open(file,'w') as f: f.write(data) # > 文件中的內(nèi)容是我是數(shù)據(jù) data = ['關(guān)關(guān)雎鳩尊浓,在河之洲逞频。窈窕淑女,君子好逑栋齿。\n', '參差荇菜苗胀,左右流之。窈窕淑女瓦堵,寤寐求之基协。\n'] with open(file,'w') as f: f.writelines(data) # > 關(guān)關(guān)雎鳩,在河之洲菇用。窈窕淑女澜驮,君子好逑。 # > 參差荇菜惋鸥,左右流之杂穷。窈窕淑女,寤寐求之卦绣。
-
指針操作
seek(指針偏移量耐量,參照物)
-
指針偏移量
以字節(jié)byte為單位,和read函數(shù)有巨大區(qū)別滤港,read是字符為單位
不同編碼中漢字所占的字節(jié)數(shù)有所不同
-
參照物
0 表示在文件開頭
1 表示指針當前位置
2 表示在文件末尾
-
# b.txt中有以下內(nèi)容:阿富汗喀什的法律可攻可受的復(fù)合弓
#注意:需要保存為utf-8編碼
# 如果我們需要讀取文件末尾兩個字符廊蜒,就需要
file = r'C:\Users\wudi.HAPMMAGNA\Desktop\b.txt'
with open(file, 'rb') as f:
f.seek(-6,2)
data = f.read(1024)
while data:
print(data.decode())
data = f.read(1024)
# > 合弓
# seek中的含義為以文件末尾為指針位置,向左移動6個字節(jié)的位置,然后向后讀取
主要是將文件運行的信息保存在磁盤文件上
logging不要頻繁進行IO讀寫劲藐,運行過程中八堡,只需要保存重要信息和錯誤信息
作用
程序調(diào)試
了解軟件運行狀況
分析定位問題
日志應(yīng)包含信息
時間
地點
級別
內(nèi)容
日志級別
DEBUG
INFO
WARNING
ERROR
CRITICAL
直接使用系統(tǒng)定制的logging
logging.debug(msg)
創(chuàng)建一條debug日志logging. info(msg)
創(chuàng)建一條info日志logging.warning(msg)
創(chuàng)建一條warning日志logging.error(msg)
創(chuàng)建一條error日志logging.critical(msg)
創(chuàng)建一條critical日志-
logging.basicConfig(file=文件名,format=格式化字符串聘芜,level=輸出的最低級別)
配置loglevel對照以上日志級別作為參數(shù),默認為warning
-
format的相應(yīng)參數(shù)
%(asctime)s
時間和日期%(levelname)s
日志級別%(message)s
日志內(nèi)容%(filename)s
程序名%(pathname)s
程序路徑%(funcName)s
當前函數(shù)%(lineno)d
當前行數(shù)%(thread)s
當前線程ID%(ThreadName)s
當前線程名%(process)s
當前進程ID
import logging logging.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s',level=logging.DEBUG) logging.debug('我是一條DEBUG日志') # > 2018-08-10 15:10:09,089 - DEBUG - 我是一條DEBUG日志
使用四大組件進行定制
-
Logger類 日志器 產(chǎn)生日志
getLogger(日志器名稱)
創(chuàng)建一個日志器對象setlevel(日志級別)
設(shè)置處理日志的最低級別addHandler(處理器對象),removeHandler()
添加、刪除一個處理器對象addFilter(過濾器對象)缝龄,removeFilter()
添加汰现、刪除一個過濾器對象debug()、info()叔壤、.....創(chuàng)建一條日志
-
Filter類 過濾器 存疑
- 可被Logger瞎饲、Handler使用
-
Formatter類 格式器 格式化輸出日志
可以直接實例化使用
-
Formatter(fmt,datefmt)
fmt 格式化字符串
datefmt 格式化時間和日期字符串
-
Handler類 處理器 將日志輸出到相應(yīng)位置
-
Handler是基類,不能直接使用炼绘,需要使用其子類
StreamHandler()
向控制臺輸出FileHandler(file=文件)
向文件寫入日志handlers.RotatingHandler(file=文件嗅战,maxBytes=大小,backupCount=日志保留個數(shù))
向文件寫入日志俺亮,如果超過指定大小驮捍,則新建日志文件-
handlers.TimeRotatingFileHandler(file=文件, when=時間脚曾, interval=間隔东且, backupCount=保留日志個數(shù))
向文件寫入日志,按時間進行分割-
when的參數(shù)
'S'
秒'M'
分'H'
時
-'D'
天
-'midnight'
每日午夜12:00
-'W0-W6'
周一 ~ 周日
-
handlers.HTTPHandler
發(fā)送給一個HTTP服務(wù)器handlers.SMTPHandler
發(fā)送給一個指定的郵件地址
-
setlevel(日志級別)
設(shè)置最低需要寫入日志的級別setFormatter(格式器對象)
添加一個格式器對象本讥,用來控制輸出的日志格式addFilter(過濾器對象)珊泳、removeFilter()
#定義記錄兩個日志,每天記錄一次
#一個日志all.log拷沸,所有級別的日志都被記錄色查,格式為“日期和時間 - 級別 - 內(nèi)容”
#一個日志error.log,error以上的的日志都被記錄撞芍,格式為“日期和時間 - 級別 - 文件名【:行號】 - 內(nèi)容”
import logging
import logging.handlers
import datetime
#定義Logger
logger = logging.getLogger('mylogger')
logger.setLevel(logging.DEBUG)
#定義debughandler格式器
formatter1 = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
#定義記錄所有日志的debughandler
file1 = r'C:\Users\wudi.HAPMMAGNA\Desktop\all.log'
debughandler = logging.handlers.TimedRotatingFileHandler(file1, when='midnight', interval=1, backupCount=3000)
debughandler.setFormatter(formatter1)
#定義errorhandler格式器
formatter2 = logging.Formatter('%(asctime)s - %(levelname)s - %(filename)s[:%(lineno)d] - %(message)s')
#定義記錄error以上級別的日志errorhandler
file2 = r'C:\Users\wudi.HAPMMAGNA\Desktop\error.log'
errorhandler = logging.handlers.TimedRotatingFileHandler(file2, when='midnight', interval=1, backupCount=3000)
errorhandler.setFormatter(formatter2)
errorhandler.setLevel(logging.ERROR)
#為日志器添加處理器
logger.addHandler(debughandler)
logger.addHandler(errorhandler)
logger.debug('我是debug日志')
logger.info('我是info日志')
logger.warning('我是warning日志')
logger.error('我是error日志')
logger.critical('我是critical日志')
-
總結(jié)思路
實例化一個Logger對象
依照不同的日志文件實例化不同處理方式的Handler
給每個Hadnler對象添加實例化的Formatter格式器對象
輸出
Queue類 先進先出隊列
LifoQueue 后進先出隊列
PriorityQueue 優(yōu)先級隊列
常用方法
qsize()
返回隊列長度put()
將數(shù)據(jù)放入隊列中get()
從隊列中取出數(shù)據(jù),并刪除empty()
檢測隊列是否為空full()
檢測隊列是否已滿
import queue
que = queue.Queue()
for i in range(1,11):
que.put(i)
print(que.get())
# > 1
print(que.empty())
# > False
首先明確幾個概念
阻塞: 程序在等待某個操作完成期間,自身無法干其他事情,處于掛起狀態(tài)
非阻塞: 程序在等待某個操作完成期間,自身不被阻塞,還可以繼續(xù)干其他事情,是為了提高程序的整體執(zhí)行效率,讓程序在IO過程中執(zhí)行其他計算任務(wù)
并行: 利用富余的資源(多核)加速完成某個任務(wù) 多進程
并發(fā): 利用有限的資源使多個任務(wù)被實時或者近似實時的執(zhí)行,讓多個任務(wù)都有機會被盡快執(zhí)行,不一定能加快進度 多線程
異步: 不同程序單元執(zhí)行過程中不需要通信也能完成某個任務(wù),高效的組織非阻塞任務(wù)的方式,異步意味著無序
同步: 不同程序單元為了完成某個任務(wù),在執(zhí)行過程中需要靠通信進行步調(diào)一致,同步就意味著有序
定義線程的兩種方式
-
通過傳入函數(shù)來啟動線程
import threading def func(): while True: pass t = threading.Thread(target=func,args=()) t.setDaemon(True) t.start() print(threading.enumerate()) # > [<_MainThread(MainThread, started 7176)>, <Thread(Thread-1, started daemon 9260)>] # > 可以看出開啟了兩個線程,一個是主線程,另一個是子線程
-
通過繼承
threading.Thread
類,重寫其init和run方法定義import threading import time class myThread(threading.Thread): def __init__(self): super().__init__() def run(self): print('{0} say hello'.format(self.name)) time.sleep(5) for i in range(5): t = myThread() t.start() t.join() print('over') # > Thread-1 say hello # > Thread-2 say hello # > Thread-3 say hello # > Thread-4 say hello # > Thread-5 say hello # > over
注意: 主線程執(zhí)行完畢后,子線程并不會關(guān)閉,而是會等到子線程中的函數(shù)執(zhí)行完畢后再關(guān)閉
線程常用的方法
-
start()
啟動線程 -
join()
阻塞線程,等待該線程執(zhí)行完畢 -
active_Count()
返回當前活動的線程數(shù)量 -
current_thread()
返回當前正在活動的線程 -
enumerate()
返回當前活動的線程對象列表
守護線程
當A線程是B線程的守護線程時,一旦B關(guān)閉,A線程不論是否已經(jīng)完成,都會隨著B線程而關(guān)閉
setDaemon(True)
設(shè)置一個線程為守護線程
GIL 全局解釋器鎖
- 在多線程中,每個線程都會在執(zhí)行之前申請一把鎖,這把鎖就是GIL,但是這個鎖只有一把,也就是只有等一個線程釋放鎖之后,其他線程才能申請這個鎖,同一時間,線程只能并發(fā),卻不能并行.
多線程安全
在多線程中,對變量的讀操作,并不會影響線程安全
在多線程中,對變量的寫操作,很有可能會引起線程安全的問題
-
不安全線程的例子
import threading import time num = 0 loop = 1000000 def funa(loop): global num for i in range(loop): num += 1 print('funa done') def funb(loop): global num for i in range(loop): num -= 1 print('funb done') t1 = threading.Thread(target=funa,args=(loop,)) t2 = threading.Thread(target=funb,args=(loop,)) t1.start() t2.start() time.sleep(2) print(num) # > 281811 # > 結(jié)果并不是固定的,每次執(zhí)行都會產(chǎn)生不同的結(jié)果
這是因為有可能在線程中,多個線程可能在同時更改這個變量,造成結(jié)果錯誤
鎖
為了解決共享變量沖突的問題
-
Lock 類
只能執(zhí)行一次鎖定,鎖定完成后必須釋放鎖,才能進行下一次鎖定
可以使用上下文管理協(xié)議
acqurie()
上鎖release()
解鎖-
還是上一個例子,如果將全局變量加鎖,同一時間,只能允許一個線程進行讀寫操作,這時候結(jié)果就一定為0
import threading import time lock = threading.Lock() num = 0 loop = 1000000 def funa(loop): global num for i in range(loop): with lock: num += 1 print('funa done') def funb(loop): global num for i in range(loop): lock.acquire() num -= 1 lock.release() print('funb done') t1 = threading.Thread(target=funa,args=(loop,)) t2 = threading.Thread(target=funb,args=(loop,)) t1.start() t2.start() time.sleep(2) print(num) # > funa done # > funb done # > 0
-
Rlock 類 可重入鎖
- 與Lock相同用法,但是可以實現(xiàn)鎖內(nèi)再次上鎖
# 使用Lock 實現(xiàn)兩次上鎖 import threading lock = threading.Lock() def funa(): lock.acquire() print('第一道鎖上鎖') lock.acquire() print('第二道鎖上鎖') lock.release() print('釋放第二道鎖') lock.release() print('釋放第一道鎖') t = threading.Thread(target=funa,args=()) t.start() t.join() print('done') # > 第一道鎖上鎖 # 可以看出,此時,一直是在等待解鎖過程中,出現(xiàn)阻塞狀態(tài),后面的代碼永遠不會執(zhí)行 # 使用Rlock 實現(xiàn)兩次上鎖 import threading lock = threading.RLock() def funa(): lock.acquire() print('第一道鎖上鎖') lock.acquire() print('第二道鎖上鎖') lock.release() print('釋放第二道鎖') lock.release() print('釋放第一道鎖') t = threading.Thread(target=funa,args=()) t.start() t.join() print('done') # > 第一道鎖上鎖 # > 第二道鎖上鎖 # > 釋放第二道鎖 # > 釋放第一道鎖 # > done #可以看出,程序按照預(yù)想的執(zhí)行了
-
Condition 類 條件鎖
當某一事件觸發(fā)后線程進行等待或者執(zhí)行操作
相比于Lock,Condition有一個等待池和一個鎖定池,運行時處于鎖定池中,阻塞時,處于等待池中
可使用上下文管理協(xié)議
-
常用方法
acqurie()
上鎖release()
解鎖notify(線程數(shù)量)
通知指定數(shù)量的線程運行notify_all()
通知所有線程開始執(zhí)行wait()
使本線程處于阻塞狀態(tài),等待條件
案例
import threading import time con = threading.Condition() num = 0 class A(threading.Thread): def run(self): global num with con: while True: if num >20: print('產(chǎn)品大于20個了,我不生產(chǎn)了') con.notify() con.wait() num += 1 time.sleep(0.5) print('產(chǎn)品總數(shù)為:{0}'.format(num)) class B(threading.Thread): def run(self): global num with con: while True: if num < 5: print('產(chǎn)品小于5了,我不消費了') con.notify() con.wait() num -= 1 time.sleep(0.5) print('產(chǎn)品總數(shù)為:{0}'.format(num)) a = A() b = B() a.start() b.start() # > 結(jié)果太長不寫了
-
Semaphore 類 信號量
該類主要控制線程對資源的最大使用數(shù)量,當線程超過指定數(shù)量時,就變?yōu)榈却隣顟B(tài),一旦空出線程,其他線程就會接著執(zhí)行
當一個線程申請時,信號量就會-1 ,一旦變?yōu)樨撝?其他線程就不允許申請了.當一個線程被放出時,信號量就會+1,一旦不是負值,其他線程就可以申請.
import threading import time st = 'st' se = threading.Semaphore(2) class A(threading.Thread): def run(self): with se: for i in range(3): print('我是{0},我被{1}訪問了'.format(st, self.name)) time.sleep(1) print(threading.current_thread()) for i in range(20): t = A() t.start()
-
Event 類 事件信號燈
相當于設(shè)置一個紅綠燈,當紅綠燈為True時,線程才會向下執(zhí)行,否則就會一直等待信號
-
常用方法
set()
設(shè)置信號燈為Trueclear()
設(shè)置信號燈為Falsewait()
本線程等待信號燈
import threading import time event = threading.Event() class A(threading.Thread): def run(self): print('等待信號燈') event.wait() print('信號燈通過') print('hello') a = A() a.start() time.sleep(2) event.set() a.join() print('done') # > 等待信號燈 # > #2秒后 # > 信號燈通過 # > hello # > done
-
Timer 類 定時器
Timer(間隔秒數(shù),執(zhí)行的函數(shù),函數(shù)的參數(shù))
指定多少秒后以一個線程執(zhí)行某函數(shù)
import threading def func(): print('hello') timer = threading.Timer(2,func) timer .start() # > #2秒后 # > hello
生產(chǎn)者消費者模型
- 生產(chǎn)者只負責向隊列中寫入任務(wù),而消費者只向隊列中拿出任務(wù)
import threading, queue, time
class Producer(threading.Thread):
def __init__(self,queue):
super().__init__()
self.queue = queue
def run(self):
num = 0
while True:
num += 1
self.queue.put(num)
print('向倉庫中放入%s'%num)
time.sleep(0.5)
class Consumer(threading.Thread):
def __init__(self,queue):
super().__init__()
self.queue = queue
def run(self):
while True:
data = self.queue.get()
print('{0}消費了{1}'.format(self.name,data))
time.sleep(1.5)
que = queue.Queue()
p = Producer(que)
p.start()
for i in range(2):
c = Consumer(que)
c.start()
# > 向倉庫中放入1
# > Thread-2消費了1
# > 向倉庫中放入2
# > Thread-3消費了2
# > 向倉庫中放入3
# > Thread-2消費了3
# > 向倉庫中放入4
# > Thread-3消費了4
# > 向倉庫中放入5
# > 向倉庫中放入6
推薦使用多進程,因為多進程中沒有GIL鎖,可以并行執(zhí)行
在使用多進程時,主函數(shù)必須在 if __name__ == '__main__:'
下執(zhí)行
實現(xiàn)多進程的方式
-
Process 類
-
通過實例化Process類,將函數(shù)傳入?yún)?shù)中
import multiprocessing def func(): print('hello') t = multiprocessing.Process(target=func,args=()) t.start()
-
通過繼承Process類,并重寫init和run方法
import multiprocessing class A(multiprocessing.Process): def run(self): print('hello') a = A() a.start()
-
使用
os.fork()
僅在Unix系統(tǒng)下有效-
使用Pool 進程池
pool池可以指定并行最大進程執(zhí)行的數(shù)量,我認為和線程中的Semaphore信號量相似,同樣有一個等待池和一個工作池,當工作池中的進程空出來時,等待池的其它線程就會頂替上去執(zhí)行
可使用上下文管理協(xié)議
-
常用函數(shù)
apply(函數(shù)名,參數(shù))
向工作池提交任務(wù),阻塞的等待任務(wù)完成,并返回結(jié)果.-
apply_async(函數(shù)名,參數(shù))
向工作池提交任務(wù),返回消息對象,等待進程池所有任務(wù)執(zhí)行完畢后,再拿回任務(wù)執(zhí)行的結(jié)果因為apply_async是并行的,所以需要申明一個list用來保存消息對象,等待所有的任務(wù)完成后再列表中的單個消息對象返回結(jié)果
get()
返回結(jié)果ready()
如果調(diào)用完成,則返回Truesuccessful()
如果調(diào)用沒有引發(fā)異常秧了,返回Truewait()
等待結(jié)果執(zhí)行完畢terminate()
立即終止該工作進程
close()
關(guān)閉進程池join()
阻塞,直到進程池所有任務(wù)完成terminate()
立即終止進程池進程
-
阻塞式進程池
import multiprocessing import random import time def getresult(x): return x * random.randint(1, 10) if __name__ == '__main__': pool = multiprocessing.Pool(2) for i in range(1, 5): res = pool.apply(getresult, (i,)) time.sleep(1) print(res) # > 4 # > 10 # > 9 # > 4
-
異步線程池
import multiprocessing import random def getresult(x): return x * random.randint(1, 10) if __name__ == '__main__': pool = multiprocessing.Pool(2) list = [] for i in range(1, 5): res = pool.apply_async(getresult, (i,)) list.append(res) p.close() p.join() print(list) for i in list: print(i.get()) # > [<multiprocessing.pool.ApplyResult object at 0x02C78630>, <multiprocessing.pool.ApplyResult object at 0x02C78690>, <multiprocessing.pool.ApplyResult object at 0x02C786F0>, <multiprocessing.pool.ApplyResult object at 0x02C78750>] # > 7 # > 12 # > 3 # > 20
進程常用方法
start()
啟動進程join()
阻塞,知道本進程執(zhí)行完畢daemon = True
設(shè)置守護進程terminate()
強制關(guān)閉進程close()
關(guān)閉進程is_alive()
返回進程是否存活name
返回進程名稱pid
返回進程IDactive_chrildren()
返回活動的進程列表cpu_count()
返回電腦CPU核心數(shù)
進程之間的同步
多進程中,同步并不是向多線程那樣重要,因為多使用IPC通信
其用法與多線程中相同類的用法一樣
Condition類 條件變量
Event類 事件信號燈
Semaphore類 信號量
Lock 鎖
Rlock 可重入鎖
IPC通信 多進程之間的通信
-
源自于同一父進程
-
Queue類 先入先出隊列
put()
放入元素get()
取出元素qsize()
返回隊列長度empty()
檢測隊列是否為空full()
檢測隊列是否已滿
-
JoinableQueue隊列
每當一個任務(wù)完成后,可手動調(diào)用task_done,告訴系統(tǒng)一個任務(wù)已經(jīng)執(zhí)行完成,當所有任務(wù)執(zhí)行完成后,將取消join的阻塞,向下執(zhí)行代碼
-
常用函數(shù)
Queue隊列的其它方法
task_done()
任務(wù)已完成join()
阻塞,直到本隊列中的所有元素被task_done
import multiprocessing,time def func(queue): while True: if queue.empty(): break data = queue.get() print('取出%s'%data) queue.task_done() time.sleep(0.5) if __name__ == '__main__': que = multiprocessing.JoinableQueue() for i in range(20): que.put(i) p = multiprocessing.Process(target=func, args=(que,)) p.start() que.join() print('當隊列中的元素都被取完后才會看見我') # > 太長不打了
-
Pipe 類 管道 兩個進程之間的通信
相當于管道,實例化后返回兩個端口,默認是雙工的
send()
發(fā)送消息recv()
接收消息
import multiprocessing,time class A(multiprocessing.Process): def __init__(self,con): super().__init__() self.con = con def run(self): while True: self.con.send('hello') time.sleep(1) class B(multiprocessing.Process): def __init__(self, con): super().__init__() self.con = con def run(self): while True: data = self.con.recv() print(data) time.sleep(1) if __name__ == '__main__': con1, con2 = multiprocessing.Pipe() a = A(con1) b = B(con2) a.start() b.start() # > hello # > ...
-
-
不是源自于同一父進程
-
Value類 將值放在系統(tǒng)的共享內(nèi)存中,多個進程可以共同讀寫這塊內(nèi)存,
定義
Value(值類型,值)
-
值類型
u
unicodechari
signedintf
floatd
double
value
獲取值
import multiprocessing class A(multiprocessing.Process): def run(self): s = v.value print('{0} get {1}'.format(self.name,s)) if __name__ == '__main__': v = multiprocessing.Value('u','哈') for i in range(5): p = A() p.start() # > A-1 get 哈 # > A-2 get 哈 # > A-4 get 哈 # > A-5 get 哈 # > A-3 get 哈
-
Array類 Vaule的數(shù)組
數(shù)組中存放的變量類型需要一致
定義
Array(值類型,列表)
返回的是一個可迭代的對象
import multiprocessing class A(multiprocessing.Process): def run(self): for i in arr: print(i,end='') if __name__ == '__main__': list = ['哈','哈','-','我','是','A','r','r','a','y'] arr = multiprocessing.Array('u',list) p = A() p.start() # > 哈哈-我是Array
-
Manager類 管理器
list 列表
dict 字典
Condition() 創(chuàng)建一個線程共享條件信號燈
Event() 創(chuàng)建一個線程共享事件信號燈
Lock() 創(chuàng)建一個線程共享鎖
Rlock() 創(chuàng)建一個線程共享可重入視頻
Queue() 創(chuàng)建一個共享先進先出隊列
Semaphore() 創(chuàng)建一個線程共享信號量
-
managers
-
BaseManager類
原理: 通過Manager啟動一個server進程監(jiān)聽socket,其他進程通過使用socket與主進程進行聯(lián)系,進行信息交換
定義
BaseManager(address=(ip,端口),authkey=秘鑰)
創(chuàng)建一個服務(wù)器Manager對象,其他客戶端Manager通過與此對象連接,進行數(shù)據(jù)交換-
常用方法
start()
啟動服務(wù)進程get_server()
返回一個服務(wù)對象server_forever()
永遠執(zhí)行下去connect()
將本地管理器連接到主服務(wù)管理器上shuntdown()
關(guān)閉本管理器register(對外暴露的方法名,callable=返回對象的函數(shù))
-
分布式進程 Master-Worker模式
- Master 負責分發(fā)任務(wù),并接受返回的最終結(jié)果
from multiprocessing.managers import BaseManager import multiprocessing import time class Master(BaseManager): pass task_que = multiprocessing.Queue() result_que = multiprocessing.Queue() def returntaskque(): return task_que def returnresultque(): return result_que if __name__ == '__main__': ip = 'XXXXXXXXXXXXXX' port = 8888 key = b'123' server = Master((ip,port),key) server.register('get_task_que', callable=returntaskque) server.register('get_result_que', callable=returnresultque) server.start() task = server.get_task_que() result = server.get_result_que() num = 0 while True: num += 1 task.put('工作%s'%num) time.sleep(1) if not result.empty(): print('結(jié)果是:%s'%result.get())
- Worker 負責處理任務(wù),并返回結(jié)果
from multiprocessing.managers import BaseManager import time class Worker(BaseManager): pass if __name__ == '__main__': ip = 'XXXXXXXXXXXXXX' port = 8888 key = b'123' worker = Worker((ip,port),key) worker.register('get_task_que') worker.register('get_result_que') worker.connect() task = worker.get_task_que() result = worker.get_result_que() while True: if not task.empty(): data = task.get() print('收到{0}'.format(data)) time.sleep(2) result.put('完成{0}'.format(data)) time.sleep(1)
-
-
一次產(chǎn)生一個對象,可以裝下無限大的對象
可迭代 Iterable 可用于for循環(huán)的對象
迭代器一定是一個可迭代的,但是可迭代的不一定是迭代器
將一個可迭代對象轉(zhuǎn)換為迭代器
-
通過
iter()
函數(shù)from collections import Iterator list = [i for i in range(5)] print(isinstance(list, Iterator)) list = iter(list) print(isinstance(list, Iterator)) # > False # > True
-
通過
__iter__()
函數(shù)from collections import Iterator list = [i for i in range(5)] print(isinstance(list, Iterator)) list = list.__iter__() print(isinstance(list, Iterator)) # > False # > True
使用方式
-
使用
for
循環(huán)for i in list: print(i)
-
使用
next()
函數(shù),直到?jīng)]有值拋出StopIteration
異常list = iter([i for i in range(5)]) next(list) next(list) ....
-
使用
__next__()
函數(shù),直到?jīng)]有值拋出StopIteration
異常list = iter([i for i in range(5)]) list.__next__() list.__next__() ....
一邊循環(huán),一邊計算下一個對象,直到遇見yield語句后停止,每次調(diào)用只返回一個值
滿足三個條件
每次調(diào)用都產(chǎn)生一個用于for循環(huán)遍歷的對象
元素到達最后一個后拋出
StopIteration
異常可以被next調(diào)用
定義生成器
-
直接使用生成器
列表生成表達式
list = [i for i in range(5)]
生成器
gen = (i for i in range(5))
-
函數(shù)中包含
yield
語句def func(n): st = '產(chǎn)品' num = 0 while num < n: yield st+str(num) num += 1 g = func(5) print(list(g)) # 將生成器轉(zhuǎn)化為列表,方便查看,也可以使用next(g)挨個輸出值 # > ['產(chǎn)品0', '產(chǎn)品1', '產(chǎn)品2', '產(chǎn)品3', '產(chǎn)品4']
-
可使用
send()
函數(shù)向生成器發(fā)送值- 注意: 生成器每執(zhí)行一次都會在yield處停止,yield前的變量可以接收send發(fā)送的值,yield后是生成器返回的值
def func(): num = yield print(num) g = func() next(g) g.send(5) # > 5
特別注意: 無論是
next()
還是send()
,調(diào)用后都會在下一個yield語句處停止
yield from
相當于中間層,每當生成器生成一個元素,都由中間層將元素傳遞給主函數(shù)
包含
yield from
的生成器叫做委派生成器
def func():
yield from 'asds'
g = func()
print(next(g))
print(next(g))
print(next(g))
print(next(g))
# > a
# > s
# > d
# > s
非搶占式多任務(wù),協(xié)程允許不同入口點不同位置執(zhí)行程序
多線程之間的切換會消耗一定的資源,一些高并發(fā)的程序在執(zhí)行時,如果使用多線程,多線程之間的切換會消耗大量的資源和時間,但協(xié)程之間的切換卻消耗的資源少
協(xié)程的實現(xiàn)
使用
next()
預(yù)激協(xié)程使用
yield
獲取返回值使用
send()
發(fā)送值
協(xié)程的四個狀態(tài)
GEN-CREATED 等待開始執(zhí)行
GEN-RUNNING 解釋器正在執(zhí)行
GEN-SUSPENED 在yield語句處暫停
GEN-CLOSED 執(zhí)行結(jié)束
協(xié)程終止
- 可以使用哨兵值結(jié)束
獲取協(xié)程的返回值
import time
def average():
sum = 0
count = 0
avrge = 0
while True:
data = yield (avrge,sum,count)
if data == None:
break
sum = sum + data
count += 1
avrge = sum / count
print('協(xié)程結(jié)束')
g = average()
next(g)
for i in range(1,20,3):
avr,sum,count = g.send(i)
print('總數(shù)為:{0} , 個數(shù)為:{1} , 平均數(shù)為{2}'.format(sum,count,avr))
time.sleep(1)
協(xié)程的消費者-生產(chǎn)者模型
import time
def Producer():
num = 0
while True:
num += 1
print('生產(chǎn)者:總產(chǎn)品為%s'%num)
num = yield num
time.sleep(0.5)
def Consumer():
num = 0
while True:
num = yield num
num -= 1
print('消費者:總產(chǎn)品為%s'%num)
time.sleep(0.5)
p = Producer()
c = Consumer()
num = next(p)
next(c)
while True:
num = c.send(num)
num = p.send(num)
為了解決不同設(shè)備之間的數(shù)據(jù)交換
xml庫
-
構(gòu)成: 處理指令,xml版本和編碼
根元素: 樹形結(jié)構(gòu)的根元素,有且只能有一個
子元素: 可以有多個
屬性: 定義在括號中
內(nèi)容: 標簽中定義的信息
注釋: 使用``
-
保留字符
轉(zhuǎn)義 保留字符需要用轉(zhuǎn)義進行代替
CDATA定義的字符不進行轉(zhuǎn)義,相當于python中的
r''
,<!{CDATA[不需要進行轉(zhuǎn)義的字符]}>
-
命名空間
xmlns,是xml name space的縮寫
直接在標簽中添加相應(yīng)空間
-
SAX (Simple API for xml)
基于事件驅(qū)動
包含解析器和事件處理兩個部分
流式讀取
速度快
-
DOM (Document Object Model)
-
minidom類
parse(file)
打開xml文件,返回節(jié)點樹documentElement
返回xml的根節(jié)點creatElement(tag)
創(chuàng)建新節(jié)點createAttribute(attr)
創(chuàng)建此節(jié)點的新屬性getElementsByTagName(tag)
獲取此節(jié)點下的名為tag標簽的集合getAttribute(attr)
返回此節(jié)點的attr屬性的值parentNode
返回當前節(jié)點的父節(jié)點previousSibling
返回此節(jié)點的前一個兄弟節(jié)點nextSibling
返回此節(jié)點的下一個兄弟節(jié)點childNodes
返回當前節(jié)點的子節(jié)點列表firstChild
返回第一個子節(jié)點lastChild
返回最后一個子節(jié)點nodeName
返回此節(jié)點的標簽名注意:節(jié)點中的漢字也是有節(jié)點的,是text節(jié)點
-
etree.ElementTree類
Element(標簽名)
創(chuàng)建一個節(jié)點SubElement(parent,tag)
生成一個子節(jié)點,并添加到調(diào)用函數(shù)的節(jié)點ElementTree(tag)
生成一個節(jié)點樹,將tag標簽作為根節(jié)點樹.write(file)
將節(jié)點樹寫入文件set(key,vlue)
修改屬性append(子節(jié)點)
此節(jié)點最后添加子節(jié)點remove(子節(jié)點)
刪除此節(jié)點子節(jié)點parse(file)
打開xml文件,返回節(jié)點樹getroot()
返回節(jié)點樹的根節(jié)點iter(tag)
返回此節(jié)點下的所有節(jié)點,如果指定標簽名,則遍歷所有指定標簽名find()
查找第一個匹配的節(jié)點findall()
查找此節(jié)點下所有匹配的子節(jié)點,返回集合tag
標簽名text
標簽的文本值attrib
返回標簽所有屬性的字典
-
# 利用etree創(chuàng)建一個xml文件
import xml.etree.ElementTree
root = xml.etree.ElementTree.Element('Root')
name = xml.etree.ElementTree.SubElement(root,'Name')
name.text = 'Jack'
age = xml.etree.ElementTree.SubElement(root,'Age')
age.text = '22'
tree = xml.etree.ElementTree.ElementTree(root)
tree.write('a.xml')
json庫
輕量級的數(shù)據(jù)交換工具 (JavaScripObjectNotation)
類似于字典,基于key-value形式
-
常用函數(shù)
-
以文件形式存在
dump(file)
寫入文件,轉(zhuǎn)化為json對象load(file)
讀取文件,轉(zhuǎn)化為python對象
-
以數(shù)據(jù)形式存在
dumps(data)
寫入內(nèi)容,轉(zhuǎn)化為json對象loads(data)
讀取內(nèi)容,轉(zhuǎn)化為python對象
-
import json
data = {
'name':'jack',
'age':18,
'sex':'male'
}
# 寫入json文件
with open('a.json','w')as f:
json.dump(data,f)
#讀取json文件
with open('a.json','r')as f:
data = json.load(f)
print(type(data))
print(data)
# > <class 'dict'>
# > {'name': 'jack', 'age': 18, 'sex': 'male'}
轉(zhuǎn)義字符
-
重復(fù)限定符
.
匹配除換行符\n之外的所有字符^
匹配字符串開頭$
匹配字符串結(jié)尾*
匹配前一個字符0次以上,貪婪模式+
匹配前一個字符1次以上,貪婪模式?
匹配前一個字符0次或1次,貪婪模式{m,n}
匹配前一個字符至少m次,最多n次,當沒有n時則為無限次,貪婪模式[]
字符集,匹配字符集中的任意字符,字符客單個給出,也可范圍給出()
分組,分組從0開始|
或者*? +? ?? {m,n}?
非貪婪模式,盡可能少的匹配字符import re text = '<div>name</div><div>age</div>' regex = re.search(r'<div>.*?</div>',text) print(regex.group()) # > <div>name</div>
-
特殊字符集
r
原始字符串,字符串中的特殊字符不需要再進行轉(zhuǎn)義,否則則需要使用\
進行轉(zhuǎn)義[\u4E00-\u9FA5]
漢字\b
單詞邊界\d
數(shù)字 [0-9]\s
任何空白字符 [\n\t\r\f\v<空格>]\w
匹配包括下劃線的任何字字符 [A-Za-z0-9_]除漢字外,上述特殊集大寫為與之相反的意思
flags 編譯標志位
re.I
不區(qū)分大小寫
re.M
多行匹配
re.U
根據(jù)Unicode字符集解析字符
re.S
使.匹配包括換行符在內(nèi)的所有字符
compile(pattern)
編譯正則表達式,返回正則表達式對象
- 正則表達式對象可以直接調(diào)用以下函數(shù),也可使用re進行調(diào)用.
import re
text = 'https://docs.python.org/3/library/re.html#regular-expression-syntax'
#使用re進行調(diào)用
regex = re.search(r'\d',text)
print(regex)
# > <_sre.SRE_Match object; span=(24, 25), match='3'>
#使用compile調(diào)用
par = re.compile(r'\d')
regex = par.search(text)
print(regex)
# > <_sre.SRE_Match object; span=(24, 25), match='3'>
search(pattern,string[,flags])
查找,查找字符串的所有位置,返回一個匹配對象match(pattern,string[,flags])
匹配,匹配字符串的開頭位置,與search不同,返回一個匹配對象
import re
text = 'https://docs.python.org/3/library/re.html#regular-expression-syntax'
regex = re.match('library',text)
print(regex)
# > None
regex = re.match('https',text)
print(regex)
# > <_sre.SRE_Match object; span=(0, 5), match='https'>
-
findall(pattern,string[,flags])
查找字符串中所有匹配正則表達式的內(nèi)容,返回一個匹配的字符串列表
import re
text = 'https://docs.python.org/3/library/re.html#regular-expression-syntax'
list = re.findall('o',text)
print(list)
# > ['o', 'o', 'o', 'o']
-
split(pattern,string[,flags])
按照正則表達式分割字符串對象,將正則表達式中的匹配選項替換為''
,并返回一個分割的字符串列表
import re
text = 'https://docs.python.org/3/library/re.html#regular-expression-syntax'
list = re.split(r'/',text)
print(list)
# > ['https:', '', 'docs.python.org', '3', 'library', 're.html#regular-expression-syntax']
-
sub(pattern,repl,string,count)
替換查找的字符串
import re
text = 'https://docs.python.org/3/library/re.html#regular-expression-syntax'
# 將所有字符替換為@
regex = re.sub(r'\W','@',text)
print(regex)
# > https@@@docs@python@org@3@library@re@html@regular@expression@syntax
Match 匹配對象
- 下面的regex即為一個匹配對象
import re
text = 'https://docs.python.org/3/library/re.html#regular-expression-syntax'
regex = re.search(r'\d',text)
# > <_sre.SRE_Match object; span=(24, 25), match='3'>
匹配對象的布爾值始終為True,一旦沒有匹配到的對象,則返回None
group(index)
當index沒有或者為0時,返回匹配對象的整個字符串,當index不為0時,返回正則表達式中用()括起來的字符
regex.group()
# > 3
-
groups()
返回被匹配字符串的元組
regex = re.search(r'(org).+(syntax$)',text)
# > ('org', 'syntax')
-
start()
返回匹配開始位置
regex.start()
# > 24
-
end()
返回匹配結(jié)束位置
regex.end()
# > 25
-
span()
返回包含start和end的元組
regex.span()
# > (24, 25)