Python基礎(chǔ)
介紹
輸入和輸出
- 所有的通過(guò)input獲取的數(shù)據(jù),都是字符串類(lèi)型
- print()
變量
- 程序就是用來(lái)處理數(shù)據(jù)的,而變量就是用來(lái)存儲(chǔ)數(shù)據(jù)的
- 變量在程序中就是用一個(gè)變量名表示了,變量名必須是大小寫(xiě)英文、數(shù)字和
_的組合,且不能用數(shù)字開(kāi)頭 - 可以使用type(變量的名字),來(lái)查看變量的類(lèi)型
- 在Python中,等號(hào)
=是賦值語(yǔ)句,可以把任意數(shù)據(jù)類(lèi)型賦值給變量,同一個(gè)變量可以反復(fù)賦值,而且可以是不同類(lèi)型的變量- 這種變量本身類(lèi)型不固定的語(yǔ)言稱(chēng)之為動(dòng)態(tài)語(yǔ)言,與之對(duì)應(yīng)的是靜態(tài)語(yǔ)言。靜態(tài)語(yǔ)言在定義變量時(shí)必須指定變量類(lèi)型,如果賦值的時(shí)候類(lèi)型不匹配,就會(huì)報(bào)錯(cuò)。
常量
Python中,通常用全部大寫(xiě)的變量名表示常量
- 比如常用的數(shù)學(xué)常數(shù)π就是一個(gè)常量,但事實(shí)上
PI仍然是一個(gè)變量,Python根本沒(méi)有任何機(jī)制保證PI不會(huì)被改變,所以,用全部大寫(xiě)的變量名表示常量只是一個(gè)習(xí)慣上的用法
數(shù)據(jù)類(lèi)型
可變對(duì)象與不可變對(duì)象
- 可變對(duì)象
- 列表list,字典dict,集合set
- 特點(diǎn): 這個(gè)些數(shù)據(jù)類(lèi)型,是可以直接在原對(duì)象上進(jìn)行修改數(shù)據(jù),修改完成后,并不影響原對(duì)象地址
- 不可變對(duì)象
- 數(shù)字 int,字符串 str,浮點(diǎn)數(shù) float,布爾類(lèi)型 bool,元組 tuple
- 特點(diǎn): 這些數(shù)據(jù)都是不可以直接修改的,如果在修改或賦值時(shí),都會(huì)開(kāi)辟一個(gè)新空間
- 對(duì)于不變對(duì)象來(lái)說(shuō),調(diào)用對(duì)象自身的任意方法,也不會(huì)改變?cè)搶?duì)象自身的內(nèi)容。相反,這些方法會(huì)創(chuàng)建新的對(duì)象并返回,這樣,就保證了不可變對(duì)象本身永遠(yuǎn)是不可變的。
整數(shù)int
浮點(diǎn)數(shù)float
- 浮點(diǎn)數(shù)也就是小數(shù),之所以稱(chēng)為浮點(diǎn)數(shù),是因?yàn)榘凑湛茖W(xué)記數(shù)法表示時(shí),一個(gè)浮點(diǎn)數(shù)的小數(shù)點(diǎn)位置是可變的
- 整數(shù)和浮點(diǎn)數(shù)在計(jì)算機(jī)內(nèi)部存儲(chǔ)的方式是不同的,整數(shù)運(yùn)算永遠(yuǎn)是精確的(除法難道也是精確的?是的?。?,而浮點(diǎn)數(shù)運(yùn)算則可能會(huì)有四舍五入的誤差。
字符串string
字符串是以單引號(hào)
'或雙引號(hào)"括起來(lái)的任意文本-
如果字符串內(nèi)部既包含
'又包含"怎么辦?可以用轉(zhuǎn)義字符\來(lái)標(biāo)識(shí)- 轉(zhuǎn)義字符
\可以轉(zhuǎn)義很多字符,比如\n表示換行,\t表示制表符,字符\本身也要轉(zhuǎn)義,所以\\表示的字符就是\ - Python還允許用
r''表示''內(nèi)部的字符串默認(rèn)不轉(zhuǎn)義
- 轉(zhuǎn)義字符
字符串與編碼
Unicode把所有語(yǔ)言都統(tǒng)一到一套編碼里,這樣就不會(huì)再有亂碼問(wèn)題了。
ASCII編碼是1個(gè)字節(jié),而Unicode編碼通常是2個(gè)字節(jié)。
UTF-8編碼把一個(gè)Unicode字符根據(jù)不同的數(shù)字大小編碼成1-6個(gè)字節(jié),常用的英文字母被編碼成1個(gè)字節(jié),漢字通常是3個(gè)字節(jié),只有很生僻的字符才會(huì)被編碼成4-6個(gè)字節(jié)。如果你要傳輸?shù)奈谋景罅坑⑽淖址?,用UTF-8編碼就能節(jié)省空間
在計(jì)算機(jī)內(nèi)存中,統(tǒng)一使用Unicode編碼,當(dāng)需要保存到硬盤(pán)或者需要傳輸?shù)臅r(shí)候,就轉(zhuǎn)換為UTF-8編碼。
最新的Python 3版本中,字符串是以Unicode編碼的,也就是說(shuō),Python的字符串支持多語(yǔ)言
- Python提供了
ord()函數(shù)獲取字符的整數(shù)表示, -
chr()函數(shù)把編碼轉(zhuǎn)換為對(duì)應(yīng)的字符
>>> ord('A')
65
>>> ord('中')
20013
-
Python對(duì)
bytes類(lèi)型的數(shù)據(jù)用帶b前綴的單引號(hào)或雙引號(hào)表示:x = b'ABC' 純英文的
str可以用ASCII編碼為bytes,內(nèi)容是一樣的,含有中文的str可以用UTF-8編碼為bytes,用encode()方法讀到的數(shù)據(jù)就是
bytes。要把bytes變?yōu)?code>str,就需要用decode()方法
列表,字典,集合
布爾值
- 布爾值只有
True、False兩種值
空值None
空值是Python里一個(gè)特殊的值,用None表示。None不能理解為0,因?yàn)?code>0是有意義的,而None是一個(gè)特殊的空值。
數(shù)據(jù)類(lèi)型的轉(zhuǎn)換
| 函數(shù) | 說(shuō)明 |
|---|---|
| int(x [,base ]) | 將x轉(zhuǎn)換為一個(gè)整數(shù) |
| float(x ) | 將x轉(zhuǎn)換為一個(gè)浮點(diǎn)數(shù) |
| complex(real [,imag ]) | 創(chuàng)建一個(gè)復(fù)數(shù),real為實(shí)部,imag為虛部 |
| str(x ) | 將對(duì)象 x 轉(zhuǎn)換為字符串 |
| repr(x ) | 將對(duì)象 x 轉(zhuǎn)換為表達(dá)式字符串 |
| eval(str ) | 用來(lái)計(jì)算在字符串中的有效Python表達(dá)式,并返回一個(gè)對(duì)象 |
| tuple(s ) | 將序列 s 轉(zhuǎn)換為一個(gè)元組 |
| list(s ) | 將序列 s 轉(zhuǎn)換為一個(gè)列表 |
| chr(x ) | 將一個(gè)整數(shù)轉(zhuǎn)換為一個(gè)Unicode字符 |
| ord(x ) | 將一個(gè)字符轉(zhuǎn)換為它的ASCII整數(shù)值 |
| hex(x ) | 將一個(gè)整數(shù)轉(zhuǎn)換為一個(gè)十六進(jìn)制字符串 |
| oct(x ) | 將一個(gè)整數(shù)轉(zhuǎn)換為一個(gè)八進(jìn)制字符串 |
| bin(x ) | 將一個(gè)整數(shù)轉(zhuǎn)換為一個(gè)二進(jìn)制字符串 |
運(yùn)算符
| 運(yùn)算符 | 描述 | 實(shí)例 |
|---|---|---|
| + | 加 | 兩個(gè)對(duì)象相加 a + b 輸出結(jié)果 30 |
| - | 減 | 得到負(fù)數(shù)或是一個(gè)數(shù)減去另一個(gè)數(shù) a - b 輸出結(jié)果 -10 |
| * | 乘 | 兩個(gè)數(shù)相乘或是返回一個(gè)被重復(fù)若干次的字符串 a * b 輸出結(jié)果 200 |
| / | 除 | b / a 輸出結(jié)果 2 |
| // | 取整除 | 返回商的整數(shù)部分 9//2 輸出結(jié)果 4 , 9.0//2.0 輸出結(jié)果 4.0 |
| % | 取余 | 返回除法的余數(shù) b % a 輸出結(jié)果 0 |
| ** | 指數(shù) | a**b 為10的20次方, 輸出結(jié)果 100000000000000000000 |
- 復(fù)合賦值運(yùn)算符
| 運(yùn)算符 | 描述 | 實(shí)例 |
|---|---|---|
| += | 加法賦值運(yùn)算符 | c += a 等效于 c = c + a |
| -= | 減法賦值運(yùn)算符 | c -= a 等效于 c = c - a |
| *= | 乘法賦值運(yùn)算符 | c *= a 等效于 c = c * a |
| /= | 除法賦值運(yùn)算符 | c /= a 等效于 c = c / a |
| %= | 取模賦值運(yùn)算符 | c %= a 等效于 c = c % a |
| **= | 冪賦值運(yùn)算符 | c **= a 等效于 c = c ** a |
| //= | 取整除賦值運(yùn)算符 | c //= a 等效于 c = c // a |
字符串string
字符串輸出
格式化操作符
| 格式符號(hào) | 轉(zhuǎn)換 |
|---|---|
| %c | 字符 |
| %s | 字符串 |
| %d | 有符號(hào)十進(jìn)制整數(shù) |
| %u | 無(wú)符號(hào)十進(jìn)制整數(shù) |
| %o | 八進(jìn)制整數(shù) |
| %x | 十六進(jìn)制整數(shù)(小寫(xiě)字母0x) |
| %X | 十六進(jìn)制整數(shù)(大寫(xiě)字母0X) |
| %f | 浮點(diǎn)數(shù) |
| %e | 科學(xué)計(jì)數(shù)法(小寫(xiě)'e') |
| %E | 科學(xué)計(jì)數(shù)法(大寫(xiě)“E”) |
| %g | %f和%e 的簡(jiǎn)寫(xiě) |
| %G | %f和%E的簡(jiǎn)寫(xiě) |
age = 18
name = "xiaohua"
print("我的姓名是%s, 年齡是%d" % (name, age))
f-strings
f-strings 以字母 'f' 或 'F' 為前綴, 格式化字符串使用一對(duì)單引號(hào)、雙引號(hào)、三單引號(hào)、三雙引號(hào)
name = '峰哥'
age = 33
format_string1 = f'我的名字是 {name}, 我的年齡是 {age}'
format()
使用字符串的format()方法,它會(huì)用傳入的參數(shù)依次替換字符串內(nèi)的占位符{0}、{1}……
>>> 'Hello, {0}, 成績(jī)提升了 {1:.1f}%'.format('小明', 17.125)
'Hello, 小明, 成績(jī)提升了 17.1%'
常見(jiàn)操作
如有字符串mystr = 'hello world itcast and itcastcpp'
find & rfind
檢測(cè) str 是否包含在 mystr中,如果是返回開(kāi)始的索引值,否則返回-1
mystr.find(str, start=0, end=len(mystr))
mystr.find('it', 0, 10)
index & rindex
跟find()方法一樣,只不過(guò)如果str不在 mystr中會(huì)報(bào)一個(gè)異常.
mystr.index(str, start=0, end=len(mystr))
count
返回 str在start和end之間 在 mystr里面出現(xiàn)的次數(shù)
mystr.count(str, start=0, end=len(mystr))
replace
把 mystr 中的 str1 替換成 str2,如果 count 指定,則替換不超過(guò) count 次.
mystr.replace(str1, str2, mystr.count(str1))
capitalize
把字符串的第一個(gè)字符大寫(xiě)
mystr.capitalize()
title
把字符串的每個(gè)單詞首字母大寫(xiě)
>>> a = "hello itcast"
>>> a.title()
'Hello Itcast'
lower
轉(zhuǎn)換 mystr 中所有大寫(xiě)字符為小寫(xiě)
mystr.lower()
upper
轉(zhuǎn)換 mystr 中的小寫(xiě)字母為大寫(xiě)
mystr.upper()
startswith
檢查字符串是否是以 "hello" 開(kāi)頭, 是則返回 True,否則返回 False
mystr.startswith("hello")
endswith
檢查字符串是否以"world"結(jié)束,如果是返回True,否則返回 False.
mystr.endswith("world")
ljust & rjust
返回一個(gè)原字符串左對(duì)齊,并使用空格填充至長(zhǎng)度 width 的新字符串
mystr.ljust(width)
center
返回一個(gè)原字符串居中,并使用空格填充至長(zhǎng)度 width 的新字符串
mystr.center(width)
lstrip & rstrip & strip
刪除 mystr 左邊/右邊/兩邊的空白字符或指定字符
mystr.lstrip()
mystr.lstrip(“#”)
split
以 str 為分隔符切片 mystr,如果 maxsplit有指定值,則僅分隔 maxsplit 個(gè)子字符串
mystr.split(" ", 2)
splitlines
按照行分隔,返回一個(gè)包含各行作為元素的列表
mystr.splitlines()
partition & rpartition
把mystr以str分割成三部分,str前,str和str后
mystr.partition(str)
join
alist 中每個(gè)元素用str連接,構(gòu)造出一個(gè)新的字符串
str = "_"
alist = ['1', '2', '3']
str.join(alist)
>>> ‘1_2_3’
isalpha & isdigit & isalnum & isspace
如果 mystr 所有字符都是字母/數(shù)字/字母或數(shù)字/空格 則返回 True,否則返回 False
mystr.isalpha()
列表list
Python內(nèi)置的一種數(shù)據(jù)類(lèi)型是列表:list。list是一種有序的集合,可以隨時(shí)添加和刪除其中的元素。
相關(guān)操作
添加元素
- append(),向列表末尾添加元素
- extend(),可以將另一個(gè)列表中的元素逐一添加到列表中
- insert(index, item),在指定位置index前插入元素object
修改元素
- li[i] = x,把索引為i的元素修改為x
查找元素
所謂的查找,就是看看指定的元素是否存在
python中查找的常用方法為:
- in(存在),如果存在那么結(jié)果為true,否則為false
- not in(不存在),如果不存在那么結(jié)果為true,否則false
index查找(與字符串查找相同)
>>> a = ['a', 'b', 'c', 'a', 'b']
>>> a.index('a', 1, 3) # 注意是左閉右開(kāi)區(qū)間
刪除元素
-
del:根據(jù)下標(biāo)進(jìn)行刪除
del li[i] # 刪除列表li中索引為i元素 -
pop():按索引刪除一個(gè)元素,刪除時(shí)會(huì)返回被刪除的元素
li.pop() # 刪除最后一個(gè)元素 li.pop(i) # 刪除列表li中索引為i元素 -
remove:根據(jù)元素的值進(jìn)行刪除,刪除第一個(gè)符合條件的值
>>> str=[1,2,3,4,5,2,6] >>> str.remove(2) >>> str [1, 3, 4, 5, 2, 6]
個(gè)數(shù)len()
用len()函數(shù)可以獲得list元素的個(gè)數(shù)
排序sort()
sort方法是將list按特定順序重新排列,默認(rèn)為由小到大,參數(shù)reverse=True可改為倒序,由大到小。
遍歷
-
使用for循環(huán)
- 通過(guò)for ... in ... 我們可以遍歷字符串、列表、元組、字典等
namesList = ['xiaoWang','xiaoZhang','xiaoHua'] for name in namesList: print(name) -
使用while循環(huán)
namesList = ['xiaoWang','xiaoZhang','xiaoHua'] i = 0 while i < len(namesList): print(namesList[i]) i+ = 1
元組tuple
- 另一種有序列表叫元組:tuple。tuple和list非常類(lèi)似,但是tuple一旦初始化就不能修改,元組使用小括號(hào),列表使用方括號(hào)。
- 因?yàn)閠uple不可變,所以代碼更安全。如果可能,能用tuple代替list就盡量用tuple。
- 元組只有一個(gè)元素
t = (1,)
小結(jié)
-
元組修改元素
將元組轉(zhuǎn)換為列表并更改值
-
通過(guò)現(xiàn)有字符串的片段在構(gòu)造一個(gè)新的字符串的方式來(lái)等同于更新元組操作
tuple_1=(1,2,3,"ewang","demo") #通過(guò)索引更新 tuple_1=tuple_1[0],tuple_1[2],tuple_1[4] print tuple_1 #通過(guò)切片更新 tuple_1=tuple_1[0:2] print tuple_1 # 添加元素 tuple_1 = tuple_1 + (4,)
-
列表和元組區(qū)別
- 列表是可變類(lèi)型,元組是不可變類(lèi)型,可變類(lèi)型值,值發(fā)生變化地址不變;不可變類(lèi)型指,值發(fā)生改變,地址也發(fā)生改變,值指向一個(gè)新的值
切片
切片是指對(duì)操作的對(duì)象截取其中一部分的操作。
字符串、列表、元組都支持切片操作。
語(yǔ)法
- [起始:結(jié)束:步長(zhǎng)]
- 注意:選取的區(qū)間從"起始"位開(kāi)始,到"結(jié)束"位的前一位結(jié)束(不包含結(jié)束位本身)(左閉右開(kāi)),步長(zhǎng)表示選取間隔。
使用
s = "abcdefghijk"
print(s[0:5:1])
print(s[0:5:2])
print(s[3:6]) # 默認(rèn)步長(zhǎng)可以不寫(xiě),默認(rèn)為1
print(s[:5]) # 開(kāi)始索引也可以不寫(xiě),默認(rèn)從頭開(kāi)始
print(s[5:]) # 結(jié)束也可以不寫(xiě),默認(rèn)到最后
print(s[:]) # 全默認(rèn),默認(rèn)截取整串
print(s)
print(s[10:20]) # 切片時(shí)不會(huì)出現(xiàn)下標(biāo)越界錯(cuò)誤
# 切片的下標(biāo)還可是以負(fù)數(shù)
# 負(fù)數(shù)是,是從右向左切片,起始下標(biāo)為 -1
print(s[-1:-5])
print(s[-1:-5:-1])
# 特殊需要記住的切片方式
# 使用切片實(shí)現(xiàn)字符串逆序
print(s[::-1])
字典dict
使用鍵-值(key-value)存儲(chǔ),具有極快的查找速度。
相關(guān)操作
查看元素
-
通過(guò)鍵訪問(wèn)值
di['key'] = value # 若訪問(wèn)不存在的鍵,則會(huì)報(bào)錯(cuò) -
在我們不確定字典中是否存在某個(gè)鍵而又想獲取其值時(shí),可以使用get方法,還可以設(shè)置默認(rèn)值
>>> age = info.get('age') >>> age #'age'鍵不存在,所以age為None >>> type(age) <type 'NoneType'> >>> age = info.get('age', 18) # 若info中不存在'age'這個(gè)鍵,就返回默認(rèn)值18 >>> age 18
修改元素
字典的每個(gè)元素中的數(shù)據(jù)是可以修改的,只要通過(guò)key找到,即可修改
di['a'] = x # 把鍵為a的值修改為x
添加元素
在使用 變量名['鍵'] = 數(shù)據(jù) 時(shí),這個(gè)“鍵”在字典中,不存在,那么就會(huì)新增這個(gè)元素
di['newkey'] = newvalue
刪除元素
pop('key'):按鍵刪除一個(gè)元素,刪除時(shí)會(huì)返回被刪除元素的值
del di['key']:刪除指定鍵
del di:刪除整個(gè)字典對(duì)象
-
clear():清空整個(gè)字典內(nèi)容
di.clear() >>>{}
個(gè)數(shù)len()
len(di)
keys()
返回一個(gè)包含字典所有KEY的列表
values()
返回一個(gè)包含字典所有value的列表
items()
返回一個(gè)包含所有(鍵,值)元祖的列表
di = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
di.keys()
>>> ['Michael', 'Bob', 'Tracy']
di.values()
>>> [95, 75, 85]
di.items()
>>> [('Michael', 95), ('Bob', 75), ('Tracy', 85)]
遍歷
遍歷鍵key
di = {'Michael': 95, 'Bob': 75}
for key in di.keys():
print(key)
>>>
Michael
Bob
遍歷值value
di = {'Michael': 95, 'Bob': 75}
for value in di.values():
print(value)
>>>
95
75
遍歷項(xiàng)(元素)
di = {'Michael': 95, 'Bob': 75}
for item in di.items():
print(item)
>>>
('Michael', 95)
('Bob', 75)
遍歷字典的key-value
di = {'Michael': 95, 'Bob': 75}
for key,value in di.items():
print('%s, %s'% (key,value))
>>>
Michael, 95
Bob, 75
小結(jié)
dict內(nèi)部存放的順序和key放入的順序是沒(méi)有關(guān)系的。
-
和list比較,dict有以下幾個(gè)特點(diǎn):
- 查找和插入的速度極快,不會(huì)隨著key的增加而變慢;
- 需要占用大量的內(nèi)存,內(nèi)存浪費(fèi)多。
而list相反:
- 查找和插入的時(shí)間隨著元素的增加而增加;
- 占用空間小,浪費(fèi)內(nèi)存很少。
所以,dict是用空間來(lái)?yè)Q取時(shí)間的一種方法。
-
dict的key必須是不可變對(duì)象。
- 這是因?yàn)閐ict根據(jù)key來(lái)計(jì)算value的存儲(chǔ)位置,如果每次計(jì)算相同的key得出的結(jié)果不同,那dict內(nèi)部就完全混亂了。這個(gè)通過(guò)key計(jì)算位置的算法稱(chēng)為哈希算法(Hash)。
- 要保證hash的正確性,作為key的對(duì)象就不能變。字符串、整數(shù)等都是不可變的,因此,可以放心地作為key。而list是可變的,就不能作為key
集合set
set和dict類(lèi)似,也是一組key的集合,但不存儲(chǔ)value。由于key不能重復(fù),所以,在set中,沒(méi)有重復(fù)的key。
相關(guān)操作
添加元素
通過(guò)add(key)方法可以添加元素到set中,可以重復(fù)添加,但不會(huì)有效果
s.add(key)
刪除元素
通過(guò)remove(key)方法可以刪除元素
s.remove(key)
clear()清空元素
交集(&)
交集指的是兩個(gè)不同的集合中相同的集合打印出來(lái)
>>> a = set('abc')
>>> b = set('cdef')
>>> a & b
set(['c'])
并集(|)
將兩個(gè)集合中所有元素合并到一起
>>> a = set('abc')
>>> b = set('cdef')
>>> a | b
set(['a', 'c', 'b', 'e', 'd', 'f'])
差集(-)
差集指的是兩個(gè)沒(méi)有集合中不同的元素,前面的集合為準(zhǔn)
>>> a = set('abc')
>>> b = set('cdef')
>>> a - b
set(['a', 'b'])
對(duì)稱(chēng)差集(^)
集合A與集合B中所有不屬于A∩B的元素的集合
>>> a = set('abc')
>>> b = set('cdef')
>>> a ^ b
set(['a', 'b', 'd' 'e', 'd', 'f'])
[圖片上傳失敗...(image-90cfb9-1620306245275)]
判斷語(yǔ)句
循環(huán)語(yǔ)句
break和continue
- break的作用:立刻結(jié)束break**所在的循環(huán)
- continue的作用:用來(lái)結(jié)束本次循環(huán),緊接著執(zhí)行下一次的循環(huán)
- break/continue只能用在循環(huán)中,除此以外不能單獨(dú)使用
- break/continue在嵌套循環(huán)中,只對(duì)最近的一層循環(huán)起作用
高級(jí)特性
列表生成式
>>> [x * x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
# for循環(huán)后面還可以加上if判斷,這樣我們就可以篩選出僅偶數(shù)的平方:
>>> [x * x for x in range(1, 11) if x % 2 == 0]
[4, 16, 36, 64, 100]
# 還可以使用兩層循環(huán),可以生成全排列
>>> [m + n for m in 'ABC' for n in 'XYZ']
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
# 把一個(gè)list中所有的字符串變成小寫(xiě)
>>> L = ['Hello', 'World', 'IBM', 'Apple']
>>> [s.lower() for s in L]
['hello', 'world', 'ibm', 'apple']
迭代與迭代器
迭代是訪問(wèn)集合元素的一種方式,如果給定一個(gè)list或tuple,我們可以通過(guò)for循環(huán)來(lái)遍歷這個(gè)list或tuple,這種遍歷我們稱(chēng)為迭代(Iteration)。
可以直接作用于
for循環(huán)的對(duì)象統(tǒng)稱(chēng)為可迭代對(duì)象:Iterable。可以被
next()函數(shù)調(diào)用并不斷返回下一個(gè)值的對(duì)象稱(chēng)為迭代器:Iterator。它們表示一個(gè)惰性計(jì)算的序列生成器都是
Iterator對(duì)象,但list、dict、str雖然是可迭代對(duì)象Iterable,卻不是迭代器Iterator。把
list、dict、str等Iterable變成Iterator可以使用iter()函數(shù)-
可以直接作用于
for循環(huán)的數(shù)據(jù)類(lèi)型有以下幾種:一類(lèi)是集合數(shù)據(jù)類(lèi)型,如
list、tuple、dict、set、str等;一類(lèi)是
generator,包括生成器和帶yield的generator function。這些可以直接作用于
for循環(huán)的對(duì)象統(tǒng)稱(chēng)為可迭代對(duì)象:Iterable。 可以使用
isinstance()判斷一個(gè)對(duì)象是否是Iterable對(duì)象
生成器
根據(jù)程序員制定的規(guī)則循環(huán)生成數(shù)據(jù),當(dāng)條件不成立時(shí)則生成數(shù)據(jù)結(jié)束。數(shù)據(jù)不是一次性全部生成出來(lái),而是使用一個(gè),再生成一個(gè),可以節(jié)約大量的內(nèi)存。
創(chuàng)建方式
-
生成器推導(dǎo)式
-
只要把一個(gè)列表生成式的
[]改成(),就創(chuàng)建了一個(gè)generator>>> g = (x * x for x in range(10)) >>> g <generator object <genexpr> at 0x1022ef630> >>> next(g) 0 >>> next(g) 1 …… >>> next(g) 81 >>> next(g) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration generator保存的是算法,每次調(diào)用
next(g),就計(jì)算出g的下一個(gè)元素的值,直到計(jì)算到最后一個(gè)元素,沒(méi)有更多的元素時(shí),拋出StopIteration的錯(cuò)誤。也可使用
for循環(huán),因?yàn)間enerator也是可迭代對(duì)象;我們創(chuàng)建了一個(gè)generator后,基本上永遠(yuǎn)不會(huì)調(diào)用next(),而是通過(guò)for循環(huán)來(lái)迭代它,并且不需要關(guān)心StopIteration的錯(cuò)誤。
-
-
yield 關(guān)鍵字
-
只要在def函數(shù)里面看到有 yield 關(guān)鍵字那么就是生成器
def get_value(n): for i in range(n): print('生成第一個(gè)值') # yield 關(guān)鍵字的作用是將這個(gè)函數(shù)變成一個(gè)生成器對(duì)象 # 執(zhí)行時(shí),解釋器遇到 yield 后會(huì)中斷代碼的執(zhí)行,并返回yield后的數(shù)據(jù), # 下一次再執(zhí)行時(shí),會(huì)恢復(fù)前面yield中斷的狀態(tài),繼續(xù)執(zhí)行 yield i print('第一個(gè)生成完成') g = get_value(4) value = next(g) print(value) value = next(g) print(value) 代碼執(zhí)行到 yield 會(huì)暫停,然后把結(jié)果返回出去,下次啟動(dòng)生成器會(huì)在暫停的位置繼續(xù)往下執(zhí)行
yield 就是保存當(dāng)前程序執(zhí)行狀態(tài)
-
應(yīng)用
-
斐波那契數(shù)列
def fibonacci(max): n, a, b = 0, 0, 1 while n < max: yield b a, b = b, a + b n = n + 1 return 'done' fib = fibonacci(5) # 遍歷生成的數(shù)據(jù) for value in fib: print(value)
迭代器和生成器的區(qū)別
(1)生成器:
生成器本質(zhì)上就是一個(gè)函數(shù),它記住了上一次返回時(shí)在函數(shù)體中的位置。
對(duì)生成器函數(shù)的第二次(或第n次)調(diào)用,跳轉(zhuǎn)到函數(shù)上一次掛起的位置。
而且記錄了程序執(zhí)行的上下文。
生成器不僅“記住”了它的數(shù)據(jù)狀態(tài),生成還記住了程序執(zhí)行的位置。(2)迭代器
迭代器是一種支持next()操作的對(duì)象。它包含了一組元素,當(dāng)執(zhí)行next()操作時(shí),返回其中一個(gè)元素。
當(dāng)所有元素都被返回后,再執(zhí)行next()報(bào)異?!猄topIteration
生成器一定是可迭代的,也一定是迭代器對(duì)象(3)區(qū)別:
①生成器是生成元素的,迭代器是訪問(wèn)集合元素的一中方式
②迭代輸出生成器的內(nèi)容
③迭代器是一種支持next()操作的對(duì)象
④迭代器(iterator):其中iterator對(duì)象表示的是一個(gè)數(shù)據(jù)流,可以把它看做一個(gè)有序序列,但我們不能提前知道序列的長(zhǎng)度,只有通過(guò)nex()函數(shù)實(shí)現(xiàn)需要計(jì)算的下一個(gè)數(shù)據(jù)??梢钥醋錾善鞯囊粋€(gè)子集。
函數(shù)
如果在開(kāi)發(fā)程序時(shí),需要某塊代碼多次,但是為了提高編寫(xiě)的效率以及代碼的重用,所以把具有獨(dú)立功能的代碼塊組織為一個(gè)小模塊,這就是函數(shù)
基礎(chǔ)
局部變量與全局變量
-
局部變量
- 局部變量,就是在函數(shù)內(nèi)部定義的變量
- 其作用范圍是這個(gè)函數(shù)內(nèi)部,即只能在這個(gè)函數(shù)中使用,在函數(shù)的外部是不能使用的
- 因?yàn)槠渥饔梅秶皇窃谧约旱暮瘮?shù)內(nèi)部,所以不同的函數(shù)可以定義相同名字的局部變量
- 局部變量的作用,為了臨時(shí)保存數(shù)據(jù)需要在函數(shù)中定義變量來(lái)進(jìn)行存儲(chǔ)
- 當(dāng)函數(shù)調(diào)用時(shí),局部變量被創(chuàng)建,當(dāng)函數(shù)調(diào)用完成后這個(gè)變量就不能夠使用了
-
全局變量
在函數(shù)外邊定義的變量叫做
全局變量全局變量能夠在所有的函數(shù)中進(jìn)行訪問(wèn)
當(dāng)函數(shù)內(nèi)出現(xiàn)局部變量和全局變量相同名字時(shí),函數(shù)內(nèi)部中的
變量名 = 數(shù)據(jù)此時(shí)理解為定義了一個(gè)局部變量,而不是修改全局變量的值-
如果在函數(shù)中出現(xiàn)
global 全局變量的名字那么這個(gè)函數(shù)中即使出現(xiàn)和全局變量名相同的變量名 = 數(shù)據(jù)也理解為對(duì)全局變量進(jìn)行修改,而不是定義局部變量# 可以使用一次global對(duì)多個(gè)全局變量進(jìn)行聲明 global a, b # 還可以用多次global聲明都是可以的 # global a # global b
定義函數(shù)
定義一個(gè)函數(shù)要使用def語(yǔ)句,依次寫(xiě)出函數(shù)名、括號(hào)、括號(hào)中的參數(shù)和冒號(hào):,然后,在縮進(jìn)塊中編寫(xiě)函數(shù)體,函數(shù)的返回值用return語(yǔ)句返回。
函數(shù)名也是變量
調(diào)用函數(shù)
通過(guò) 函數(shù)名() 即可完成調(diào)用
- 每次調(diào)用函數(shù)時(shí),函數(shù)都會(huì)從頭開(kāi)始執(zhí)行,當(dāng)這個(gè)函數(shù)中的代碼執(zhí)行完畢后,意味著調(diào)用結(jié)束了
- 當(dāng)然了如果函數(shù)中執(zhí)行到了return也會(huì)結(jié)束函數(shù)
- 函數(shù)名其實(shí)就是指向一個(gè)函數(shù)對(duì)象的引用,完全可以把函數(shù)名賦給一個(gè)變量,相當(dāng)于給這個(gè)函數(shù)起了一個(gè)“別名”
參數(shù)
默認(rèn)參數(shù)(缺省參數(shù))
- 在定義函數(shù)時(shí),函數(shù)中的形式參數(shù),被賦值,這個(gè)值就是默認(rèn)值
- 當(dāng)在函數(shù)調(diào)用時(shí),如果給定了值,那么就使用給定值,如果沒(méi)有給定值,那就使用默認(rèn)值
- ++注意:默認(rèn)值參數(shù)只能出現(xiàn)在參數(shù)列表的最右側(cè)**++
位置參數(shù)(實(shí)參)
- 使用位置參數(shù)時(shí),因?yàn)轭?lèi)型的原因,那么實(shí)參的順序要和形參的順序完全一致;
- 當(dāng)沒(méi)有默認(rèn)值的情況下,參數(shù)的個(gè)數(shù)和也要一致
關(guān)鍵詞參數(shù)(形參)
- 在定義形式參時(shí),每個(gè)參數(shù)都可以理解成一個(gè)key;
使用這個(gè)key,可以明確的為當(dāng)前這個(gè)參數(shù)進(jìn)行賦值;使用關(guān)鍵字參數(shù),可以忽略參數(shù)的順序問(wèn)題
不定長(zhǎng)位置參數(shù)
- *args 在參數(shù)中定義了該形參后,那可以通過(guò) *args 接收多個(gè)不確定個(gè)數(shù)的位置參數(shù)
- ++加了星號(hào)(*)的變量args會(huì)存放所有未命名的變量參數(shù),*args為元組++
不定長(zhǎng)關(guān)鍵字參數(shù)
- **kwargs 在參數(shù)中定義了該形參后,那可以通過(guò) **kwargs 接收多個(gè)不確定個(gè)數(shù)的關(guān)鍵字參數(shù)
- 加**的變量kwargs會(huì)存放命名參數(shù),即形如key=value的參數(shù), **kwargs為字典.
小結(jié)
定義時(shí)小括號(hào)中的參數(shù),用來(lái)接收參數(shù)用的,稱(chēng)為 “形參”
調(diào)用時(shí)小括號(hào)中的參數(shù),用來(lái)傳遞給函數(shù)用的,稱(chēng)為 “實(shí)參”
當(dāng)全局變量和局部變量同名時(shí),在函數(shù)內(nèi)使用變量,優(yōu)先使用局部變量;局部變量?jī)?yōu)先級(jí)高于全局變量
-
參數(shù)定義的順序必須是:必選參數(shù)、默認(rèn)參數(shù)、不定長(zhǎng)位置參數(shù)和不定長(zhǎng)關(guān)鍵字參數(shù)。
def f1(a, b, c=0, *args, **kwargs): print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw) 對(duì)于任意函數(shù),都可以通過(guò)類(lèi)似
func(*args, **kw)的形式調(diào)用它,無(wú)論它的參數(shù)是如何定義的。
高階函數(shù)
既然變量可以指向函數(shù),函數(shù)的參數(shù)能接收變量,那么一個(gè)函數(shù)就可以接收另一個(gè)函數(shù)作為參數(shù),這種函數(shù)就稱(chēng)之為高階函數(shù)。
map()函數(shù)
map()函數(shù)接收兩個(gè)參數(shù),一個(gè)是函數(shù),一個(gè)是Iterable,map將傳入的函數(shù)依次作用到序列的每個(gè)元素,并把結(jié)果作為新的Iterator返回。
>>> def f(x):
... return x * x
...
>>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> list(r)
[1, 4, 9, 16, 25, 36, 49, 64, 81]
把這個(gè)list所有數(shù)字轉(zhuǎn)為字符串:
>>> list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
['1', '2', '3', '4', '5', '6', '7', '8', '9']
reduce()函數(shù)
reduce把一個(gè)函數(shù)作用在一個(gè)序列[x1, x2, x3, ...]上,這個(gè)函數(shù)必須接收兩個(gè)參數(shù)
reduce把結(jié)果繼續(xù)和序列的下一個(gè)元素做累積計(jì)算:
import functools
my_list = [1, 2, 3, 4, 5]
def f(x1, x2):
return x1 + x2
result = functools.reduce(f, my_list)
print(result)
>>>15
當(dāng)然求和運(yùn)算可以直接用Python內(nèi)建函數(shù)sum(),沒(méi)必要?jiǎng)佑?code>reduce。
如果要把序列[1, 3, 5, 7, 9]變換成整數(shù)13579:
>>> from functools import reduce
>>> def fn(x, y):
... return x * 10 + y
...
>>> reduce(fn, [1, 3, 5, 7, 9])
13579
filter()函數(shù)
和map()類(lèi)似,filter()也接收一個(gè)函數(shù)和一個(gè)序列,不同的是,filter()把傳入的函數(shù)依次作用于每個(gè)元素,然后根據(jù)返回值是True還是False決定保留還是丟棄該元素。
例如,在一個(gè)list中,刪掉偶數(shù),只保留奇數(shù),可以這么寫(xiě):
def is_odd(n):
return n % 2 == 1
list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
# 結(jié)果: [1, 5, 9, 15]
注意到filter()函數(shù)返回的是一個(gè)Iterator,也就是一個(gè)惰性序列,所以要強(qiáng)迫filter()完成計(jì)算結(jié)果,需要用list()函數(shù)獲得所有結(jié)果并返回list。
sorted()函數(shù)
Python內(nèi)置的sorted()函數(shù)就可以對(duì)list進(jìn)行排序
此外,sorted()函數(shù)也是一個(gè)高階函數(shù),它還可以接收一個(gè)key函數(shù)來(lái)實(shí)現(xiàn)自定義的排序,例如按絕對(duì)值大小排序:
>>> sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]
給sorted傳入key函數(shù),即可實(shí)現(xiàn)忽略大小寫(xiě)的排序:
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)
['about', 'bob', 'Credit', 'Zoo']
要進(jìn)行反向排序,不必改動(dòng)key函數(shù),可以傳入第三個(gè)參數(shù)reverse=True
匿名函數(shù)lambda
定義的函數(shù)沒(méi)有名字,這樣的函數(shù)叫做匿名函數(shù).
介紹
格式:lambda [形參1], [形參2], ... : [單行表達(dá)式] 或 [函數(shù)調(diào)用]
-
lambda定義和普通函數(shù)的區(qū)別:
- lambda 沒(méi)有函數(shù)名,不必?fù)?dān)心函數(shù)名沖突
- lambda 參數(shù)列表外沒(méi)有括號(hào)
- lambda 函數(shù)體中,只能實(shí)現(xiàn)簡(jiǎn)單的表達(dá)式計(jì)算或函數(shù)調(diào)用
- lambda 函數(shù)體中,不能使用Return,if,while,for-in 這些都不行,不用寫(xiě)
return,返回值就是該表達(dá)式的結(jié)果。 - lambda 函數(shù)體中,可以使用if 實(shí)現(xiàn)的三目運(yùn)算符.
應(yīng)用
-
定義簡(jiǎn)單的單行函數(shù)
my_function = lambda a, b: a + b -
作為函數(shù)的參數(shù)進(jìn)行傳遞
解決目標(biāo): 1、提高函數(shù)的通用性 2、減少代碼量
-
例子
#現(xiàn)有字典 d={‘a(chǎn)’:24,‘g’:52,‘i’:12,‘k’:33}請(qǐng)按字典中的 value 值進(jìn)行排序? sorted(d.items(),key = lambda x:x[1]) #一句話解決階乘函數(shù) reduce(lambda x,y: x*y, range(1,n+1))
閉包
在函數(shù)嵌套的前提下,內(nèi)部函數(shù)使用了外部函數(shù)的變量,并且外部函數(shù)返回了內(nèi)部函數(shù),我們把這個(gè)使用外部函數(shù)變量的內(nèi)部函數(shù)稱(chēng)為閉包。
構(gòu)成條件
- 在函數(shù)嵌套(函數(shù)里面再定義函數(shù))的前提下
- 內(nèi)部函數(shù)使用了外部函數(shù)的變量(還包括外部函數(shù)的參數(shù))
- 外部函數(shù)返回了內(nèi)部函數(shù)
示例
# 定義一個(gè)外部函數(shù)
def func_out(num1):
# 定義一個(gè)內(nèi)部函數(shù)
def func_inner(num2):
# 內(nèi)部函數(shù)使用了外部函數(shù)的變量(num1)
result = num1 + num2
print("結(jié)果是:", result)
# 外部函數(shù)返回了內(nèi)部函數(shù),這里返回的內(nèi)部函數(shù)就是閉包
return func_inner
# 創(chuàng)建閉包實(shí)例
f = func_out(1)
# 執(zhí)行閉包
f(2)
f(3)
>>>
結(jié)果是: 3
結(jié)果是: 4
小結(jié)
閉包可以保存外部函數(shù)內(nèi)的變量,不會(huì)隨著外部函數(shù)調(diào)用完而銷(xiāo)毀。
閉包不僅可以保存外部函數(shù)的變量還可以提高代碼的可重用行。
返回閉包時(shí)牢記一點(diǎn):返回函數(shù)不要引用任何循環(huán)變量,或者后續(xù)會(huì)發(fā)生變化的變量。
-
在內(nèi)部函數(shù)中修改外部變量使用nonlocal 關(guān)鍵字
nonlocal num1 # 告訴解釋器,此處使用的是 外部變量a # 修改外部變量num1 num1 = 10
裝飾器
給已有函數(shù)增加額外功能的函數(shù),它本質(zhì)上就是一個(gè)閉包函數(shù)。
特點(diǎn)
- 不修改已有函數(shù)的源代碼
- 不修改已有函數(shù)的調(diào)用方式
- 給已有函數(shù)增加額外的功能
語(yǔ)法格式
# 裝飾器
def decorator(fn): # fn:被裝飾的目標(biāo)函數(shù).
def inner():
'''執(zhí)行函數(shù)之前'''
fn() # 執(zhí)行被裝飾的目標(biāo)函數(shù)
'''執(zhí)行函數(shù)之后'''
return inner
例子
# 添加一個(gè)登錄驗(yàn)證的功能
def check(fn):
print("裝飾器函數(shù)執(zhí)行了")
def inner():
print("請(qǐng)先登錄....")
fn()
return inner
# 使用語(yǔ)法糖方式來(lái)裝飾函數(shù)
@check
def comment():
print("發(fā)表評(píng)論")
comment()
>>>
請(qǐng)先登錄....
發(fā)表評(píng)論
裝飾帶有參數(shù)和返回值的函數(shù)
# 添加輸出日志的功能
def logging(fn):
def inner(num1, num2):
print("--正在努力計(jì)算--")
result = fn(num1, num2)
return result
return inner
# 使用裝飾器裝飾函數(shù)
@logging
def sum_num(a, b):
result = a + b
return result
result = sum_num(1, 2)
print(result)
>>>
--正在努力計(jì)算--
3
通用裝飾器
# 通用裝飾器
def logging(fn):
def inner(*args, **kwargs):
print("--正在努力計(jì)算--")
result = fn(*args, **kwargs)
return result
return inner
多個(gè)裝飾器
- 裝飾過(guò)程是: 離函數(shù)最近的裝飾器先裝飾,然后外面的裝飾器再進(jìn)行裝飾,由內(nèi)到外的裝飾過(guò)程
def make_div(func):
"""對(duì)被裝飾的函數(shù)的返回值 div標(biāo)簽"""
def inner():
return "<div>" + func() + "</div>"
return inner
def make_p(func):
"""對(duì)被裝飾的函數(shù)的返回值 p標(biāo)簽"""
def inner():
return "<p>" + func() + "</p>"
return inner
# 裝飾過(guò)程: 1 content = make_p(content) 2 content = make_div(content)
# content = make_div(make_p(content))
@make_div
@make_p
def content():
return "人生苦短"
result = content()
print(result)
>>>
<div><p>人生苦短</p></div>
帶有參數(shù)的裝飾器
使用裝飾器裝飾函數(shù)的時(shí)候可以傳入指定參數(shù),語(yǔ)法格式: @裝飾器(參數(shù),...)
-
寫(xiě)法:
在裝飾器外面再包裹上一個(gè)函數(shù),讓最外面的函數(shù)接收參數(shù),返回的是裝飾器,因?yàn)锧符號(hào)后面必須是裝飾器實(shí)例。
# 添加輸出日志的功能
def logging(flag):
def decorator(fn):
def inner(num1, num2):
if flag == "+":
print("--正在努力加法計(jì)算--")
elif flag == "-":
print("--正在努力減法計(jì)算--")
result = fn(num1, num2)
return result
return inner
# 返回裝飾器
return decorator
# 使用裝飾器裝飾函數(shù)
@logging("+")
def add(a, b):
result = a + b
return result
result = add(1, 2)
print(result)
面向?qū)ο?/h1>
面向?qū)ο缶幊獭狾bject Oriented Programming,簡(jiǎn)稱(chēng)OOP,是一種程序設(shè)計(jì)思想。OOP把對(duì)象作為程序的基本單元,一個(gè)對(duì)象包含了數(shù)據(jù)和操作數(shù)據(jù)的函數(shù)。
三大特征有:封裝性、繼承性、多態(tài)性。
類(lèi)和對(duì)象
面向?qū)ο缶幊痰?個(gè)非常重要的概念:類(lèi)和對(duì)象
類(lèi)是抽象的模板,而實(shí)例則是一個(gè)一個(gè)具體的對(duì)象,各個(gè)實(shí)例擁有的數(shù)據(jù)都互相獨(dú)立,互不影響;
-
類(lèi)的構(gòu)成
- 類(lèi)的名稱(chēng):類(lèi)名(命名規(guī)則按照"大駝峰命名法")
- 類(lèi)的屬性:一組數(shù)據(jù)
- 類(lèi)的方法:允許對(duì)進(jìn)行操作的方法 (行為)
方法就是與實(shí)例綁定的函數(shù),和普通函數(shù)不同,方法可以直接訪問(wèn)實(shí)例的數(shù)據(jù);
-
對(duì)象
- 對(duì)象名 = 類(lèi)名(參數(shù)列表....)
- 對(duì)象調(diào)用方法的格式:對(duì)象名.方法名(參數(shù)列表)
- 注意:方法中參數(shù)列表中的第一個(gè)參數(shù)self,不需要手動(dòng)傳遞,這個(gè)參數(shù)是由解釋器在執(zhí)行程序時(shí),自動(dòng)傳遞的默認(rèn)會(huì)將當(dāng)前調(diào)用方法的對(duì)象引用傳遞進(jìn)去
在方法內(nèi)通過(guò)self獲取對(duì)象屬性
class Hero(object):
"""定義了一個(gè)英雄類(lèi),可以移動(dòng)和攻擊"""
def move(self):
"""實(shí)例方法"""
print("正在前往事發(fā)地點(diǎn)...")
def attack(self):
"""實(shí)例方法"""
print("發(fā)出了一招強(qiáng)力的普通攻擊...")
def info(self):
"""在類(lèi)的實(shí)例方法中,通過(guò)self獲取該對(duì)象的屬性"""
print("英雄 %s 的生命值 :%d" % (self.name, self.hp))
print("英雄 %s 的攻擊力 :%d" % (self.name, self.atk))
print("英雄 %s 的護(hù)甲值 :%d" % (self.name, self.armor))
# 實(shí)例化了一個(gè)英雄對(duì)象 泰達(dá)米爾
taidamier = Hero()
# 給對(duì)象添加屬性,以及對(duì)應(yīng)的屬性值
taidamier.name = "泰達(dá)米爾" # 姓名
taidamier.hp = 2600 # 生命值
taidamier.atk = 450 # 攻擊力
taidamier.armor = 200 # 護(hù)甲值
# 通過(guò).成員選擇運(yùn)算符,獲取對(duì)象的實(shí)例方法
taidamier.info() # 只需要調(diào)用實(shí)例方法info(),即可獲取英雄的屬性
taidamier.move()
taidamier.attack()
_init_()方法
兩個(gè)下劃線開(kāi)始,兩個(gè)下劃線結(jié)束的方法,就是魔法方法,__init__()就是一個(gè)魔法方法,通常用來(lái)做屬性初始化 或 賦值 操作。
-
__init__()方法,在創(chuàng)建一個(gè)對(duì)象時(shí)默認(rèn)被調(diào)用,不需要手動(dòng)調(diào)用 -
__init__(self)中的self參數(shù),不需要開(kāi)發(fā)者傳遞,python解釋器會(huì)自動(dòng)把當(dāng)前的對(duì)象引用傳遞過(guò)去。如果在創(chuàng)建對(duì)象時(shí)傳遞了2個(gè)實(shí)參,那么__init__(self)中出了self作為第一個(gè)形參外還需要2個(gè)形參,例如__init__(self,x,y)
__str__()方法
用來(lái)顯示信息,該方法需要 return 一個(gè)數(shù)據(jù),并且只有self一個(gè)參數(shù),當(dāng)在類(lèi)的外部 print(對(duì)象) 則打印這個(gè)數(shù)據(jù)
def __str__(self):
return "英雄 <%s> 數(shù)據(jù): 生命值 %d" % (self.name, self.hp)
- 當(dāng)使用print輸出對(duì)象的時(shí)候,默認(rèn)打印對(duì)象的內(nèi)存地址。如果類(lèi)定義了
__str__(self)方法,那么就會(huì)打印從在這個(gè)方法中return的數(shù)據(jù) -
__str__方法通常返回一個(gè)字符串,作為這個(gè)對(duì)象的描述信息
__del__()方法
當(dāng)刪除對(duì)象時(shí),python解釋器也會(huì)默認(rèn)調(diào)用
- 當(dāng)有變量保存了一個(gè)對(duì)象的引用時(shí),此對(duì)象的引用計(jì)數(shù)就會(huì)加1;當(dāng)使用del() 刪除變量指向的對(duì)象時(shí),則會(huì)減少對(duì)象的引用計(jì)數(shù)。
- 如果對(duì)象的引用計(jì)數(shù)不為1,那么會(huì)讓這個(gè)對(duì)象的引用計(jì)數(shù)減1,當(dāng)對(duì)象的引用計(jì)數(shù)為0的時(shí)候,則對(duì)象才會(huì)被真正刪除(內(nèi)存被回收)。
小結(jié)
- 在類(lèi)內(nèi)部獲取 屬性 和 實(shí)例方法,通過(guò)self獲??;
- 在類(lèi)外部獲取 屬性 和 實(shí)例方法,通過(guò)對(duì)象名獲取。
- 如果一個(gè)類(lèi)有多個(gè)對(duì)象,每個(gè)對(duì)象的屬性是各自保存的,都有各自獨(dú)立的地址;
- 但是實(shí)例方法是所有對(duì)象共享的,只占用一份內(nèi)存空間。類(lèi)會(huì)通過(guò)self來(lái)判斷是哪個(gè)對(duì)象調(diào)用了實(shí)例方法。
封裝
意義
- 將屬性和方法放到一起做為一個(gè)整體,然后通過(guò)實(shí)例化對(duì)象來(lái)處理;
- 隱藏內(nèi)部實(shí)現(xiàn)細(xì)節(jié),只需要和對(duì)象及其屬性和方法交互就可以了;
- 對(duì)類(lèi)的屬性和方法增加 訪問(wèn)權(quán)限控制。
私有屬性和私有方法
在屬性名和方法名 前面 加上兩個(gè)下劃線 __
- 類(lèi)的私有屬性 和 私有方法,都不能通過(guò)對(duì)象直接訪問(wèn),但是可以在本類(lèi)內(nèi)部訪問(wèn);
- 類(lèi)的私有屬性 和 私有方法,都不會(huì)被子類(lèi)繼承,子類(lèi)也無(wú)法訪問(wèn);
- 私有屬性 和 私有方法 往往用來(lái)處理類(lèi)的內(nèi)部事情,不通過(guò)對(duì)象處理,起到安全作用
修改私有屬性
定義一個(gè)可以調(diào)用的公有方法,在這個(gè)公有方法內(nèi)訪問(wèn)修改。
通常會(huì)定義get_xxx()方法和set_xxx()方法來(lái)獲取和修改私有屬性值。
-
set/get方法對(duì)私有屬性操作時(shí)的好處:
- 提供精確的訪問(wèn)控制權(quán)限
- 隱藏實(shí)現(xiàn)細(xì)節(jié),讓代碼更安全
- 可以提供更加安全的數(shù)據(jù)有效性控制
class Master(object): def __init__(self): # 私有屬性,可以在類(lèi)內(nèi)部通過(guò)self調(diào)用,但不能通過(guò)對(duì)象訪問(wèn) self.__money = 10000 # 返回私有屬性的值 def get_money(self): return self.__money # 接收參數(shù),修改私有屬性的值 def set_money(self, num): self.__money = num
繼承
- 在程序中,繼承描述的是多個(gè)類(lèi)之間的所屬關(guān)系。
- 如果一個(gè)類(lèi)A里面的屬性和方法可以復(fù)用,則可以通過(guò)繼承的方式,傳遞到類(lèi)B里。
- 那么類(lèi)A就是基類(lèi),也叫做父類(lèi);類(lèi)B就是派生類(lèi),也叫做子類(lèi)。
單繼承
- 繼承的格式
class 子類(lèi)名(父類(lèi)名):
pass
當(dāng)發(fā)生繼承后,子類(lèi)會(huì)繼承父類(lèi)中的屬性和方法,可以直接 使用
在子類(lèi)中不能直接使用父類(lèi)中的私有方法;通過(guò)繼承得到的父類(lèi)的公有方法,間接 執(zhí)行父類(lèi)的私有方法
因?yàn)樽宇?lèi)提供了 init 方法后,那么在使用子類(lèi)實(shí)例對(duì)象時(shí),就會(huì)調(diào)用 子類(lèi)自己 init 方法;如果想父類(lèi)中的屬性可以得到,需要執(zhí)行父類(lèi)中的init方法
格式:父類(lèi)名.__init__(self,父類(lèi)中需要屬性參數(shù)列表)
多層繼承
子類(lèi)繼承父類(lèi),父類(lèi)繼承爺爺類(lèi),這就是多層繼承
多繼承
子類(lèi)繼承多個(gè)父類(lèi)
如果子類(lèi)和父類(lèi)的方法名和屬性名相同,則默認(rèn)使用子類(lèi)的
注意:如果多個(gè)父類(lèi)中有同名的 屬性和方法,則默認(rèn)使用第一個(gè)父類(lèi)的屬性和方法(根據(jù)類(lèi)的魔法屬性mro的順序來(lái)查找)
多繼承的初始化
在多繼承時(shí),如果繼承的多個(gè)類(lèi)同時(shí)繼承同一個(gè)父類(lèi),那么這時(shí)會(huì)出現(xiàn)初始化問(wèn)題,這個(gè)共同父類(lèi)會(huì)被初始化多次.
-
super()執(zhí)行過(guò)程:
在 self 這個(gè)對(duì)象的所屬類(lèi)中,通過(guò) mro 找到方法解析順序
在順序中,找當(dāng)前類(lèi)名的下一個(gè)類(lèi)來(lái)初始化或查找方法類(lèi)名.__mro__得到了一個(gè)元組,元組中的元素是當(dāng)前類(lèi)在繼承關(guān)系上的一個(gè)順序;這個(gè)順序不是我們確定的,是由在確定某個(gè)類(lèi)的繼承關(guān)系關(guān)系后,由解釋器來(lái)確定這個(gè)順序
-
多繼承調(diào)用指定父類(lèi)中方法
父類(lèi)名.方法() super().方法() # 方法2. super() 帶參數(shù)版本,只支持新式類(lèi) super(Prentice, self).__init__() # 執(zhí)行父類(lèi)的 __init__方法 # super(Prentice, self).make_cake() # self.make_cake() # 方法3. super()的簡(jiǎn)化版,只支持新式類(lèi) super().__init__() # 執(zhí)行父類(lèi)的 __init__方法 super().make_cake() # 執(zhí)行父類(lèi)的 實(shí)例方法 self.make_cake() # 執(zhí)行本類(lèi)的實(shí)例方法
Mixin
在設(shè)計(jì)類(lèi)的繼承關(guān)系時(shí),通常,主線都是單一繼承下來(lái)的,但是,如果需要“混入”額外的功能,通過(guò)多重繼承就可以實(shí)現(xiàn)。這種設(shè)計(jì)通常稱(chēng)之為MixIn。
MixIn的目的就是給一個(gè)類(lèi)增加多個(gè)功能,這樣,在設(shè)計(jì)類(lèi)的時(shí)候,我們優(yōu)先考慮通過(guò)多重繼承來(lái)組合多個(gè)MixIn的功能,而不是設(shè)計(jì)多層次的復(fù)雜的繼承關(guān)系。
比如,編寫(xiě)一個(gè)多進(jìn)程模式的TCP服務(wù),定義如下:
class MyTCPServer(TCPServer, ForkingMixIn):
pass
多態(tài)
在需要使用父類(lèi)對(duì)象的地方,也可以使用子類(lèi)對(duì)象, 這種情況就叫多態(tài).
比如, 在函數(shù)中,我需要調(diào)用 某一個(gè)父類(lèi)對(duì)象的方法, 那么我們也可以在這個(gè)地方調(diào)用子類(lèi)對(duì)象的方法.
類(lèi)屬性
類(lèi)屬性就是
類(lèi)對(duì)象所擁有的屬性,它被所有類(lèi)對(duì)象的實(shí)例對(duì)象所共有,類(lèi)對(duì)象和實(shí)例對(duì)象均可訪問(wèn),在內(nèi)存中只存在一個(gè)副本類(lèi)屬性可以使用實(shí)例對(duì)象來(lái)引用,但是不能修改
一般情況下:類(lèi)屬性 都只使用 類(lèi)對(duì)象 來(lái)調(diào)用class People(object): name = 'Tom' # 公有的類(lèi)屬性 __age = 12 # 私有的類(lèi)屬性 p = People() print(p.name) # 正確 print(People.name) # 正確 print(p.__age) # 錯(cuò)誤,不能在類(lèi)外通過(guò)實(shí)例對(duì)象訪問(wèn)私有的類(lèi)屬性 print(People.__age) # 錯(cuò)誤,不能在類(lèi)外通過(guò)類(lèi)對(duì)象訪問(wèn)私有的類(lèi)屬性
實(shí)例屬性(對(duì)象屬性)
由于Python是動(dòng)態(tài)語(yǔ)言,根據(jù)類(lèi)創(chuàng)建的實(shí)例可以任意綁定屬性。
給實(shí)例綁定屬性的方法是通過(guò)實(shí)例變量,或者通過(guò)self變量
class Student(object):
def __init__(self, name):
self.name = name
s = Student('Bob')
s.score = 90
- 以 對(duì)象名.xxx 的形式調(diào)用的都是實(shí)例的屬性或?qū)嵗姆椒?
- 實(shí)例屬性和實(shí)例方法只能由實(shí)例對(duì)象調(diào)用
類(lèi)方法
是類(lèi)對(duì)象所擁有的方法,需要用修飾器@classmethod來(lái)標(biāo)識(shí)其為類(lèi)方法,對(duì)于類(lèi)方法,第一個(gè)參數(shù)必須是類(lèi)對(duì)象,一般以cls作為第一個(gè)參數(shù)
定義格式:
@classmethod
def 方法名(cls,...):
pass
調(diào)用格式:
類(lèi)對(duì)象.類(lèi)方法名
注意:在類(lèi)方法中,不能使用self,但是可以使用 cls,該參數(shù)用來(lái)表示 當(dāng)前類(lèi)對(duì)象,這個(gè)參數(shù)也是自動(dòng)傳遞的
@classmethod 是一個(gè)裝飾 器,用來(lái)修飾一個(gè)方法成為類(lèi)方法,當(dāng)在執(zhí)行該 類(lèi)方法時(shí),解釋 會(huì)自動(dòng) 將類(lèi)對(duì)象傳遞到參數(shù) cls中
-
類(lèi)方法還有一個(gè)用途就是可以對(duì)類(lèi)屬性進(jìn)行修改
class People(object): country = 'china' #類(lèi)方法,用classmethod來(lái)進(jìn)行修飾 @classmethod def get_country(cls): return cls.country @classmethod def set_country(cls,country): cls.country = country
靜態(tài)方法
通過(guò)修飾器@staticmethod來(lái)進(jìn)行修飾,靜態(tài)方法不需要多定義參數(shù),可以通過(guò)對(duì)象和類(lèi)來(lái)訪問(wèn)
格式:
@staticmethod
def 方法名(參數(shù)列表....):
pass
調(diào)用方式:
同類(lèi)方法
類(lèi)對(duì)象.靜態(tài)方法名()
- 靜態(tài)方法中不需要額外定義參數(shù),因此在靜態(tài)方法中引用類(lèi)屬性的話,必須通過(guò)類(lèi)實(shí)例對(duì)象來(lái)引用
使用@property
property屬性就是負(fù)責(zé)把一個(gè)方法當(dāng)做屬性進(jìn)行使用,這樣做可以簡(jiǎn)化代碼使用。
定義property屬性有兩種方式
- 裝飾器方式
- 類(lèi)屬性方式
裝飾器方式
class Person(object):
def __init__(self):
self.__age = 0
# 裝飾器方式的property, 把a(bǔ)ge方法當(dāng)做屬性使用, 表示當(dāng)獲取屬性時(shí)會(huì)執(zhí)行下面修飾的方法
@property
def age(self):
return self.__age
# 把a(bǔ)ge方法當(dāng)做屬性使用, 表示當(dāng)設(shè)置屬性時(shí)會(huì)執(zhí)行下面修飾的方法
@age.setter
def age(self, new_age):
if new_age >= 150:
print("成精了")
else:
self.__age = new_age
# 創(chuàng)建person
p = Person()
print(p.age)
p.age = 100
print(p.age)
p.age = 1000
>>>
0
100
成精了
@property的實(shí)現(xiàn)比較復(fù)雜,我們先考察如何使用。把一個(gè)getter方法變成屬性,只需要加上@property就可以了,此時(shí),@property本身又創(chuàng)建了另一個(gè)裝飾器@age.setter,負(fù)責(zé)把一個(gè)setter方法變成屬性賦值
- @property 表示把方法當(dāng)做屬性使用, 表示當(dāng)獲取屬性時(shí)會(huì)執(zhí)行下面修飾的方法
- @方法名.setter 表示把方法當(dāng)做屬性使用,表示當(dāng)設(shè)置屬性時(shí)會(huì)執(zhí)行下面修飾的方法
- 裝飾器方式的property屬性修飾的方法名一定要一樣。
類(lèi)屬性方式
class Person(object):
def __init__(self):
self.__age = 0
def get_age(self):
"""當(dāng)獲取age屬性的時(shí)候會(huì)執(zhí)行該方法"""
return self.__age
def set_age(self, new_age):
"""當(dāng)設(shè)置age屬性的時(shí)候會(huì)執(zhí)行該方法"""
if new_age >= 150:
print("成精了")
else:
self.__age = new_age
# 類(lèi)屬性方式的property屬性
age = property(get_age, set_age)
# 創(chuàng)建person
p = Person()
print(p.age)
p.age = 100
print(p.age)
p.age = 1000
>>>
0
100
成精了
property的參數(shù)說(shuō)明:
- 第一個(gè)參數(shù)是獲取屬性時(shí)要執(zhí)行的方法
- 第二個(gè)參數(shù)是設(shè)置屬性時(shí)要執(zhí)行的方法
小結(jié)
# 數(shù)據(jù) (屬性)
# 區(qū)別: 類(lèi)的每個(gè)對(duì)象(實(shí)例) 對(duì)于這個(gè)數(shù)據(jù)是獨(dú)有的還是共享的,是不同的還是相同的
# 1. 對(duì)象屬性 (實(shí)例屬性)
# 類(lèi)的每個(gè)對(duì)象 這個(gè)名字的屬性數(shù)據(jù) 是獨(dú)有的 ,每個(gè)對(duì)象不同
# 2. 類(lèi)屬性
# 類(lèi)的每個(gè)對(duì)象 這個(gè)名字的屬性數(shù)據(jù) 是共享,每個(gè)對(duì)象都相同
# 函數(shù)(方法)
# 區(qū)別:方法中能夠直接使用的屬性數(shù)據(jù)不同
# 1. 對(duì)象方法(實(shí)例方法) 可以直接讀寫(xiě)對(duì)象屬性,可以直接讀類(lèi)屬性
# def obj_func(self):
# self.
# 2. 類(lèi)方法
# @classmethod 可以直接讀寫(xiě)類(lèi)屬性
# def class_func(cls, ..):
# cls.
# 3. 靜態(tài)方法
# @staticmethod 雖然可以通過(guò)類(lèi)名操作類(lèi)屬性,但是我們可以認(rèn)為 不是直接操作屬性
# def static_func():
# 類(lèi)名.
# 選擇:如果定義一個(gè)函數(shù),這個(gè)函數(shù)中需要使用對(duì)象屬性,定義對(duì)象方法
# 如果定義一個(gè)函數(shù),這個(gè)函數(shù)中僅需要使用類(lèi)屬性,定義類(lèi)方法
# 如果定義一個(gè)函數(shù),這個(gè)函數(shù)不需要使用類(lèi)的任何屬性,從邏輯的角度考慮 應(yīng)該是類(lèi)中的一個(gè)處理方法,此時(shí)定義靜態(tài)方法即可
總結(jié)
面向?qū)ο笈c面向過(guò)程
面向過(guò)程的程序設(shè)計(jì)把計(jì)算機(jī)程序視為一系列的命令集合,即一組函數(shù)的順序執(zhí)行。為了簡(jiǎn)化程序設(shè)計(jì),面向過(guò)程把函數(shù)繼續(xù)切分為子函數(shù),即把大塊函數(shù)通過(guò)切割成小塊函數(shù)來(lái)降低系統(tǒng)的復(fù)雜度。
而面向?qū)ο蟮某绦蛟O(shè)計(jì)把計(jì)算機(jī)程序視為一組對(duì)象的集合,而每個(gè)對(duì)象都可以接收其他對(duì)象發(fā)過(guò)來(lái)的消息,并處理這些消息,計(jì)算機(jī)程序的執(zhí)行就是一系列消息在各個(gè)對(duì)象之間傳遞。
- 對(duì)于面向過(guò)程的思想: 需要實(shí)現(xiàn)一個(gè)功能的時(shí)候,看重的是開(kāi)發(fā)的步驟和過(guò)程,每一個(gè)步驟都需要自己親力親為,需要自己編寫(xiě)代碼(自己來(lái)做)。面向過(guò)程語(yǔ)言是一種基于功能分析的、以算法為中心的程序設(shè)計(jì)方法;
- 對(duì)于面向?qū)ο?/strong>的思想:把一切都看成對(duì)象,而對(duì)象一般都由屬性+方法組成;當(dāng)需要實(shí)現(xiàn)一個(gè)功能的時(shí)候,看重的并不是過(guò)程和步驟,而是關(guān)心誰(shuí)幫我做這件事(偷懶,找人幫我做)。而面向?qū)ο笫且环N基于結(jié)構(gòu)分析的、以數(shù)據(jù)為中心的程序設(shè)計(jì)思想。三大特征有:封裝性、繼承性、多態(tài)性。
- 面向過(guò)程(手洗):脫衣服、找一個(gè)盆、加水、加洗衣粉、浸泡30分鐘、搓洗、擰衣服、倒掉水、再加水、漂洗、擰衣服、倒掉水、晾衣服。
- 面向?qū)ο螅C(jī)洗):脫衣服、放入洗衣機(jī)、按下開(kāi)關(guān)、拿出衣服晾曬。
高級(jí)
I/O編程
文件讀寫(xiě)
打開(kāi)文件
- 以文本方式打開(kāi)方式的模式
r -> read text; file = open('a.txt','r')
以文本方式打開(kāi)文件讀,文件存在,打開(kāi)成功,文件不存在,打開(kāi)失敗
w -> write text; file = open('a.txt','w')
以文本方式打開(kāi)文件寫(xiě),不管文件是否存在,都會(huì)新創(chuàng)建一個(gè)新文件
a -> append text ;file = open('a.txt','w')
以文件方式打開(kāi)文件追加,文件不存在,創(chuàng)建文件,文件存在,那么打開(kāi)文件然后將光標(biāo)移動(dòng)到文件的最后
- 以二進(jìn)制形式打開(kāi)文件的模式
rb 以二進(jìn)制形式打開(kāi)文件讀取
wb 以二進(jìn)制形式打開(kāi)文件寫(xiě)入
ab 以二進(jìn)制形式打開(kāi)文件追加
-
with語(yǔ)句
- Python提供了 with 語(yǔ)句的這種寫(xiě)法,既簡(jiǎn)單又安全,并且 with 語(yǔ)句執(zhí)行完成以后自動(dòng)調(diào)用關(guān)閉文件操作,即使出現(xiàn)異常也會(huì)自動(dòng)調(diào)用關(guān)閉文件操作**。
# 1、以寫(xiě)的方式打開(kāi)文件 with open("1.txt", "w") as f: # 2、讀取文件內(nèi)容 f.write("hello world")
讀數(shù)據(jù)
- 默認(rèn)讀取全部文件內(nèi)容;只適用于文件比較小的情況
file = open('a.txt','rt')
content = file.read()
file.close()
- 讀取多行文件的方式
while True:
# 讀取
content = file.read(4096) #從文件中讀取的數(shù)據(jù)的長(zhǎng)度(單位是字節(jié))
# 如果在文件讀取時(shí),讀取的結(jié)果為空串,說(shuō)明文件讀取完畢
# 根據(jù)這個(gè)條件 可以設(shè)置讀取文件的結(jié)束條件
if content == '':
break
print(content,end='')
# 關(guān)閉文件
file.close()
- readline()以行讀取
- readlines()以行的方式 讀取整 個(gè)文件,并且返回的是一個(gè)列表,其中每一行的數(shù)據(jù)為一個(gè)元素
寫(xiě)數(shù)據(jù)
-
write()可以完成向文件寫(xiě)入數(shù)據(jù)
f = open('test.txt', 'w') f.write('hello world, i am here!') f.close() 如果文件不存在那么創(chuàng)建
操作文件和目錄
導(dǎo)入 os 模塊
-
os.rename(需要修改的文件名, 新的文件名)
import os os.rename("畢業(yè)論文.txt", "畢業(yè)論文-最終版.txt") os.remove(待刪除的文件名)
os.mkdir("張三")創(chuàng)建文件夾;如果當(dāng)前目錄 存在,會(huì)報(bào)錯(cuò)
os.getcwd()獲取當(dāng)前目錄
os.chdir("../指定路徑")改變當(dāng)前目錄 到指定 的路徑 上去
-
os.listdir("./")獲取目錄下的文件名稱(chēng),存在列表中
file_list = os.listdir('.') print(file_list) for file in file_list: print(file) os.rmdir('路徑') 刪除一個(gè)空文件夾,當(dāng)目錄文件夾不為空,不能刪除
模塊
模塊是一組Python代碼的集合,可以使用其他模塊,也可以被其他模塊使用。
使用模塊
import
在Python中用關(guān)鍵字import來(lái)引入某個(gè)模塊,比如要引用模塊math,就可以在文件最開(kāi)始的地方用import math來(lái)引入
在調(diào)用math模塊中的函數(shù)時(shí),必須這樣引用:
模塊名.函數(shù)名
from…import
Python的from語(yǔ)句讓你從模塊中導(dǎo)入一個(gè)指定的部分到當(dāng)前命名空間中,此時(shí)可以用下面方法實(shí)現(xiàn):
from 模塊名 import 函數(shù)名1,函數(shù)名2....
- 通過(guò)這種方式引入的時(shí)候,調(diào)用函數(shù)時(shí)只能給出函數(shù)名,不能給出模塊名,但是當(dāng)兩個(gè)模塊中含有相同名稱(chēng)函數(shù)的時(shí)候,后面一次引入會(huì)覆蓋前一次引入
- 如果想一次性引入math中所有的東西,還可以通過(guò)from math import *來(lái)實(shí)現(xiàn)
- 用as給引入起別名
- 在模塊中的__all__變量就是為了限制或者指定能被導(dǎo)入到別的模塊的函數(shù),如果指定了那么只能是指定的那些可以被導(dǎo)入,沒(méi)有指定默認(rèn)就是全部可以導(dǎo)入,當(dāng)然私有屬性應(yīng)該除外。
制作模塊
編寫(xiě)一個(gè)hello的模塊:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
' a test module '
__author__ = 'Michael Liao'
import sys
def test():
args = sys.argv
if len(args)==1:
print('Hello, world!')
elif len(args)==2:
print('Hello, %s!' % args[1])
else:
print('Too many arguments!')
if __name__=='__main__':
test()
第1行和第2行是標(biāo)準(zhǔn)注釋?zhuān)?行注釋可以讓這個(gè)hello.py文件直接在Unix/Linux/Mac上運(yùn)行,第2行注釋表示.py文件本身使用標(biāo)準(zhǔn)UTF-8編碼;
第4行是一個(gè)字符串,表示模塊的文檔注釋?zhuān)魏文K代碼的第一個(gè)字符串都被視為模塊的文檔注釋?zhuān)?/p>
第6行使用__author__變量把作者寫(xiě)進(jìn)去,這樣當(dāng)你公開(kāi)源代碼后別人就可以瞻仰你的大名;
以上就是Python模塊的標(biāo)準(zhǔn)文件模板,當(dāng)然也可以全部刪掉不寫(xiě),但是,按標(biāo)準(zhǔn)辦事肯定沒(méi)錯(cuò)。
定位模塊
當(dāng)你導(dǎo)入一個(gè)模塊,Python解析器對(duì)模塊位置的搜索順序是:
- 當(dāng)前目錄
- 如果不在當(dāng)前目錄,Python則搜索在shell變量PYTHONPATH下的每個(gè)目錄。
- 如果都找不到,Python會(huì)察看默認(rèn)路徑。UNIX下,默認(rèn)路徑一般為/usr/local/lib/python/
- 模塊搜索路徑存儲(chǔ)在system模塊的sys.path變量中。變量里包含當(dāng)前目錄,PYTHONPATH和由安裝過(guò)程決定的默認(rèn)目錄。
安裝第三方模塊
在Python中,安裝第三方模塊,是通過(guò)包管理工具pip完成的。
第三方庫(kù)都會(huì)在Python官方的pypi.python.org網(wǎng)站注冊(cè),要安裝一個(gè)第三方庫(kù),必須先知道該庫(kù)的名稱(chēng),可以在官網(wǎng)或者pypi上搜索
異常
當(dāng)Python檢測(cè)到一個(gè)錯(cuò)誤時(shí),解釋器就無(wú)法繼續(xù)執(zhí)行了,反而出現(xiàn)了一些錯(cuò)誤的提示,這就是所謂的"異常"
格式
try:
可能會(huì)出現(xiàn)異常問(wèn)題的代碼
except Exception as e:
當(dāng)出現(xiàn)異常時(shí),解決異常的代碼
else:
當(dāng)沒(méi)有出現(xiàn)異常時(shí),正常執(zhí)行的代碼
finally:
無(wú)論是否出現(xiàn)異常,都會(huì)執(zhí)行這里的代碼
自定義異常
格式:
class 異常名Error(Exception):
def __init__(self,msg=''):
self.__msg = msg
def __str__(self):
return self.__msg
class CustomError(Exception):
pass
調(diào)試與測(cè)試
斷言assert
斷言就是判斷一個(gè)函數(shù)或?qū)ο蟮囊粋€(gè)方法所產(chǎn)生的結(jié)果是否符合你期望的那個(gè)結(jié)果。 python中assert斷言是聲明布爾值為真的判定,如果表達(dá)式為假會(huì)發(fā)生異常。單元測(cè)試中,一般使用assert來(lái)斷言結(jié)果。
def foo(s):
n = int(s)
assert n != 0, 'n is zero!' # 表達(dá)式為假,逗號(hào)后為自定義異常;也可不定義
return 10 / n
def main():
foo('0')
如果斷言失敗,assert語(yǔ)句本身就會(huì)拋出AssertionError:
程序中如果到處充斥著assert,和print()相比也好不到哪去。不過(guò),啟動(dòng)Python解釋器時(shí)可以用-O(是字母O)參數(shù)來(lái)關(guān)閉assert,關(guān)閉后,你可以把所有的assert語(yǔ)句當(dāng)成pass來(lái)看。:
$ python -O err.py
常用的斷言方法:
常用的斷言方法:
assertEqual 如果兩個(gè)值相等,則pass
assertNotEqual 如果兩個(gè)值不相等,則pass
assertTrue 判斷bool值為T(mén)rue,則pass
assertFalse 判斷bool值為False,則pass
assertIsNone 不存在,則pass
assertIsNotNone 存在,則pass
logging
logging模塊是Python內(nèi)置的標(biāo)準(zhǔn)模塊,主要用于輸出運(yùn)行日志,可以設(shè)置輸出日志的等級(jí)、日志保存路徑、日志文件回滾等;相比print,具備如下優(yōu)點(diǎn):
- 可以通過(guò)設(shè)置不同的日志等級(jí),默認(rèn)是warning級(jí)別,在release版本中只輸出重要信息,而不必顯示大量的調(diào)試信息;
- print將所有信息都輸出到標(biāo)準(zhǔn)輸出中,嚴(yán)重影響開(kāi)發(fā)者從標(biāo)準(zhǔn)輸出中查看其它數(shù)據(jù);logging則可以由開(kāi)發(fā)者決定將信息輸出到什么地方,以及怎么輸出;
import logging
logging.basicConfig(level=logging.INFO)
s = '0'
n = int(s)
logging.info('n = %d' % n)
print(10 / n)
-
記錄信息的級(jí)別
- debug : 打印全部的日志,詳細(xì)的信息,通常只出現(xiàn)在診斷問(wèn)題上
- info : 打印info,warning,error,critical級(jí)別的日志,確認(rèn)一切按預(yù)期運(yùn)行
- warning : 打印warning,error,critical級(jí)別的日志,一個(gè)跡象表明,一些意想不到的事情發(fā)生了,或表明一些問(wèn)題在不久的將來(lái)(例如。磁盤(pán)空間低”),這個(gè)軟件還能按預(yù)期工作
- error : 打印error,critical級(jí)別的日志,更嚴(yán)重的問(wèn)題,軟件沒(méi)能執(zhí)行一些功能
- critical : 打印critical級(jí)別,一個(gè)嚴(yán)重的錯(cuò)誤,這表明程序本身可能無(wú)法繼續(xù)運(yùn)行
-
logging.basicConfig函數(shù)各參數(shù):
filename:指定日志文件名;
filemode:和file函數(shù)意義相同,指定日志文件的打開(kāi)模式,'w'或者'a';
format:指定輸出的格式和內(nèi)容,format可以輸出很多有用的信息,
參數(shù):作用 %(levelno)s:打印日志級(jí)別的數(shù)值 %(levelname)s:打印日志級(jí)別的名稱(chēng) %(pathname)s:打印當(dāng)前執(zhí)行程序的路徑,其實(shí)就是sys.argv[0] %(filename)s:打印當(dāng)前執(zhí)行程序名 %(funcName)s:打印日志的當(dāng)前函數(shù) %(lineno)d:打印日志的當(dāng)前行號(hào) %(asctime)s:打印日志的時(shí)間 %(thread)d:打印線程ID %(threadName)s:打印線程名稱(chēng) %(process)d:打印進(jìn)程ID %(message)s:打印日志信息
-
輸出日志
import logging # 引入logging模塊 import os.path import time # 第一步,創(chuàng)建一個(gè)logger logger = logging.getLogger() logger.setLevel(logging.INFO) # Log等級(jí)總開(kāi)關(guān) # 第二步,創(chuàng)建一個(gè)handler,用于寫(xiě)入日志文件 rq = time.strftime('%Y%m%d%H%M', time.localtime(time.time())) log_path = os.path.dirname(os.getcwd()) + '/Logs/' log_name = log_path + rq + '.log' logfile = log_name fh = logging.FileHandler(logfile, mode='w') fh.setLevel(logging.DEBUG) # 輸出到file的log等級(jí)的開(kāi)關(guān) # 第三步,定義handler的輸出格式 formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s") fh.setFormatter(formatter) # 第四步,將logger添加到handler里面 logger.addHandler(fh) # 日志 logger.debug('this is a logger debug message') logger.info('this is a logger info message') logger.warning('this is a logger warning message') logger.error('this is a logger error message') logger.critical('this is a logger critical message')
單元測(cè)試
單元測(cè)試是用來(lái)對(duì)一個(gè)模塊、一個(gè)函數(shù)或者一個(gè)類(lèi)來(lái)進(jìn)行正確性檢驗(yàn)的測(cè)試工作。
import unittest
class TestClass(unittest.TestCase):
#該方法會(huì)首先執(zhí)行,相當(dāng)于做測(cè)試前的準(zhǔn)備工作
def setUp(self):
pass
#該方法會(huì)在測(cè)試代碼執(zhí)行完后執(zhí)行,相當(dāng)于做測(cè)試后的掃尾工作
def tearDown(self):
pass
#測(cè)試代碼
def test_app_exists(self):
pass
-
運(yùn)行單元測(cè)試
-
一旦編寫(xiě)好單元測(cè)試,我們就可以運(yùn)行單元測(cè)試。最簡(jiǎn)單的運(yùn)行方式是在
mydict_test.py的最后加上兩行代碼:if __name__ == '__main__': unittest.main()這樣就可以把
mydict_test.py當(dāng)做正常的python腳本運(yùn)行:$ python mydict_test.py -
另一種方法是在命令行通過(guò)參數(shù)
-m unittest直接運(yùn)行單元測(cè)試,這是推薦的做法:$ python -m unittest mydict_test ..... ---------------------------------------------------------------------- Ran 5 tests in 0.000s OK
-