開(kāi)始 Python 之旅
腳本文件
chmod +x helloworld.py
./helloworld.py
如果程序中沒(méi)有 #!/usr/bin/env python3 的話晒屎,應(yīng)該使用 python3 helloworld.py 來(lái)執(zhí)行,否則使用 ./helloworld.py 程序會(huì)被當(dāng)作 bash 腳本來(lái)執(zhí)行串稀,最終報(bào)錯(cuò)泥栖。
代碼風(fēng)格建議
使用 4 個(gè)空格來(lái)縮進(jìn)
永遠(yuǎn)不要混用空格和制表符
在函數(shù)之間空一行
在類(lèi)之間空兩行
字典区转,列表函似,元組以及參數(shù)列表中,在 , 后添加一個(gè)空格店乐。對(duì)于字典艰躺,: 后面也添加一個(gè)空格
在賦值運(yùn)算符和比較運(yùn)算符周?chē)锌崭瘢▍?shù)列表中除外),但是括號(hào)里則不加空格:a = f(1, 2) + g(3, 4)
模塊
模塊是包含了我們能復(fù)用的代碼的文件眨八,包含了不同的函數(shù)定義腺兴,變量。模塊文件通常以 .py 為擴(kuò)展名廉侧。
Python 本身在默認(rèn)安裝時(shí)就帶有大量的模塊页响。我們之后將會(huì)用到其中的一部分。在使用模塊前先導(dǎo)入它段誊。
變量和數(shù)據(jù)類(lèi)型
關(guān)鍵字和標(biāo)識(shí)符
下列的標(biāo)識(shí)符是 Python3 的關(guān)鍵字闰蚕,并且不能用于通常的標(biāo)識(shí)符。關(guān)鍵字必須完全按照下面拼寫(xiě):
False def if raise
None del import return
True elif in try
and else is while
as except lambda with
assert finally nonlocal yield
break for not
class from or
continue global pass
help()
keywords
從鍵盤(pán)讀取輸入
通常情況下连舍,Python 的代碼中是不需要從鍵盤(pán)讀取輸入的没陡。不過(guò)我們還是可以在 Python 中使用函數(shù) input() 來(lái)做到這一點(diǎn),input() 有一個(gè)用于打印在屏幕上的可選字符串參數(shù),返回用戶輸入的字符串盼玄。
從鍵盤(pán)讀取一個(gè)數(shù)字并且檢查這個(gè)數(shù)字是否小于 100染簇。
#!/usr/bin/env python3
number = int(input("Enter an integer: "))
if number <= 100:
print("Your number is less than or equal to 100")
else:
print("Your number is greater than 100")
while 是使用一個(gè)表達(dá)式作為判斷的條件,如果條件不能夠達(dá)成則停止循環(huán):
w = 20
while w > 1:
print(w)
w -= 1
計(jì)算投資:
#!/usr/bin/env python3
amount = float(input("Enter amount: ")) # 輸入數(shù)額
inrate = float(input("Enter Interest rate: ")) # 輸入利率
period = int(input("Enter period: ")) # 輸入期限
value = 0
year = 1
while year <= period:
value = amount + (inrate * amount)
print("Year {} Rs. {:.2f}".format(year, value))
amount = value
year = year + 1
Year {} Rs. {:.2f}".format(year, value) 稱為字符串格式化强岸,大括號(hào)和其中的字符會(huì)被替換成傳入 str.format() 的參數(shù),也即 year 和 value砾赔。其中 {:.2f} 的意思是替換為 2 位精度的浮點(diǎn)數(shù)蝌箍。
求 N 個(gè)數(shù)字的平均值
#!/usr/bin/env python3
N = 10
sum = 0
count = 0
print("please input 10 numbers:")
while count < N:
number = float(input())
sum = sum + number
count = count + 1
average = sum / N
print("N = {}, Sum = {}".format(N, sum))
print("Average = {:.2f}".format(average))
溫度轉(zhuǎn)換
使用公式 C = (F - 32) / 1.8 將華氏溫度轉(zhuǎn)為攝氏溫度。
#!/usr/bin/env python3
fahrenheit = 0
print("Fahrenheit Celsius")
while fahrenheit <= 250:
celsius = (fahrenheit - 32) / 1.8 # 轉(zhuǎn)換為攝氏度
print("{:5d} {:7.2f}".format(fahrenheit , celsius))
fahrenheit = fahrenheit + 25
{:5d} 的意思是替換為 5 個(gè)字符寬度的整數(shù)暴心,寬度不足則使用空格填充妓盲。 {:7.2f}的意思是替換為為 7 個(gè)字符寬度的保留兩位的小數(shù),小數(shù)點(diǎn)也算一個(gè)寬度专普,寬度不足則使用空格填充悯衬。其中7指寬度為 7,.2f指保留兩位小數(shù)檀夹。
單行定義多個(gè)變量或賦值
a, b = 45, 54
a, b = b, a
data = ("shiyanlou", "China", "Python")
name, country, language = data
運(yùn)算符和表達(dá)式
運(yùn)算符
只要有任意一個(gè)操作數(shù)是浮點(diǎn)數(shù)筋粗,結(jié)果就會(huì)是浮點(diǎn)數(shù)。
進(jìn)行除法運(yùn)算時(shí)若是除不盡炸渡,結(jié)果將會(huì)是小數(shù)娜亿,這很自然,如果要進(jìn)行整除蚌堵,使用 // 運(yùn)算符买决,它將返回商的整數(shù)部分。
#!/usr/bin/env python3
days = int(input("Enter days: "))
months = days // 30
days = days % 30
print("Months = {} Days = {}".format(months, days))
#!/usr/bin/env python3
days = int(input("Enter days: "))
print("Months = {} Days = {}".format(*divmod(days, 30)))
關(guān)系運(yùn)算符
邏輯運(yùn)算符
對(duì)于邏輯 與吼畏,或督赤,非,我們使用 and泻蚊,or躲舌,not 這幾個(gè)關(guān)鍵字。
邏輯運(yùn)算符 and 和 or 也稱作短路運(yùn)算符:它們的參數(shù)從左向右解析性雄,一旦結(jié)果可以確定就停止孽糖。例如,如果 A 和 C 為真而 B 為假毅贮,A and B and C 不會(huì)解析 C 办悟。作用于一個(gè)普通的非邏輯值時(shí),短路運(yùn)算符的返回值通常是能夠最先確定結(jié)果的那個(gè)操作數(shù)滩褥。
關(guān)系運(yùn)算可以通過(guò)邏輯運(yùn)算符 and 和 or 組合病蛉,比較的結(jié)果可以用 not 來(lái)取反意。邏輯運(yùn)算符的優(yōu)先級(jí)又低于關(guān)系運(yùn)算符,在它們之中铺然,not 具有最高的優(yōu)先級(jí)俗孝,or 優(yōu)先級(jí)最低,所以 A and not B or C 等于 (A and (notB)) or C魄健。當(dāng)然赋铝,括號(hào)也可以用于比較表達(dá)式。
>>> 5 and 4 # 首先判斷5沽瘦,肯定為true革骨,那么最終的結(jié)果就取決于 and 后面那個(gè)的布爾值,4 的布爾值為 true析恋,這樣就可以確定整個(gè)表達(dá)式的值為 true 了良哲,所以返回 4
4
>>> 0 and 4 # 首先判斷0,因?yàn)?0 的布爾值為 false助隧,那么不管 and 后面那個(gè)的布爾值是什么筑凫,整個(gè)表達(dá)式的布爾值都應(yīng)該為 false 了,這個(gè)時(shí)候就不需要判斷 4 了并村,直接返回最先確定結(jié)果的那個(gè)數(shù)也就是0
0
>>> False or 3 or 0
3
>>> 2 > 1 and not 3 > 5 or 4
True
簡(jiǎn)寫(xiě)運(yùn)算符
x op= expression 為簡(jiǎn)寫(xiě)運(yùn)算的語(yǔ)法形式巍实。其等價(jià)于 x = x op expression
#!/usr/bin/env python3
N = 100
a = 2
while a < N:
print(str(a))
a *= a
表達(dá)式
通常我們書(shū)寫(xiě)表達(dá)式的時(shí)候,會(huì)在每一個(gè)運(yùn)算符左右都放一個(gè)空格
#!/usr/bin/env python3
a = 9
b = 12
c = 3
x = a - b / 3 + c * 2 - 1
y = a - b / (3 + c) * (2 - 1)
z = a - (b / (3 + c) * 2) - 1
print("X = ", x)
print("Y = ", y)
print("Z = ", z)
類(lèi)型轉(zhuǎn)換
計(jì)算數(shù)列 1/x+1/(x+1)+1/(x+2)+ ... +1/n哩牍,我們?cè)O(shè) x = 1蔫浆,n = 10。
#!/usr/bin/env python3
sum = 0
for i in range(1, 11):
sum += 1.0 / i
print("{:2d} {:6.4f}".format(i , sum))
求解二次方程式:
#!/usr/bin/env python3
import math
a = int(input("Enter value of a: "))
b = int(input("Enter value of b: "))
c = int(input("Enter value of c: "))
d = b * b - 4 * a * c
if d < 0:
print("ROOTS are imaginary")
else:
root1 = (-b + math.sqrt(d)) / (2 * a)
root2 = (-b - math.sqrt(d)) / (2 * a)
print("Root 1 = ", root1)
print("Root 2 = ", root2)
計(jì)算一位數(shù)碼相機(jī)銷(xiāo)售人員的工資姐叁。他的基本工資是 1500瓦盛,每售出一臺(tái)相機(jī)他可以得到 200 并且獲得 2% 的抽成。程序要求輸入相機(jī)數(shù)量及單價(jià)外潜。
#!/usr/bin/env python3
basic_salary = 1500
bonus_rate = 200
commission_rate = 0.02
numberofcamera = int(input("Enter the number of inputs sold: "))
price = float(input("Enter the price of camera: "))
bonus = (bonus_rate * numberofcamera)
commission = (commission_rate * price * numberofcamera)
print("Bonus = {:6.2f}".format(bonus))
print("Commission = {:6.2f}".format(commission))
print("Gross salary = {:6.2f}".format(basic_salary + bonus + commission))
圓的面積
不要使用 input 等方法獲得輸入原环,程序不需要輸入任何參數(shù),直接輸出半徑為 2 的圓的面積:
import math
# 計(jì)算圓的面積
area = 2 * 2 * math.pi
# 格式化輸出圓的面積处窥,保留10位小數(shù)
print("{:.10f}".format(area))
控制流 If-else
接受用戶輸入的一個(gè)數(shù)并且檢查這個(gè)數(shù)是否小于 100嘱吗。
#!/usr/bin/env python3
number = int(input("Enter a number: "))
if number < 100:
print("The number is less than 100")
如果輸入數(shù)大于 100 則打印 "Greater than"。
#!/usr/bin/env python3
number = int(input("Enter a number: "))
if number < 100:
print("The number is less than 100")
else:
print("The number is greater than 100")
>>> x = int(input("Please enter an integer: "))
>>> if x < 0:
... x = 0
... print('Negative changed to zero')
... elif x == 0:
... print('Zero')
... elif x == 1:
... print('Single')
... else:
... print('More')
真值檢測(cè)
if x:
pass
循環(huán)
while 循環(huán)
>>> n = 0
>>> while n < 11:
... print(n)
... n += 1
斐波那契(Fibonacci)數(shù)列
這個(gè)數(shù)列前兩項(xiàng)為 1滔驾,之后的每一個(gè)項(xiàng)都是前兩項(xiàng)之和谒麦。所以這個(gè)數(shù)列看起來(lái)就像這樣: 1,1,2,3,5,8,13,...。
#!/usr/bin/env python3
a, b = 0, 1
while b < 100:
print(b)
a, b = b, a + b
#!/usr/bin/env python3
a, b = 0, 1
while b < 100:
print(b, end=' ')
a, b = b, a + b
print()
冪級(jí)數(shù)
e^x = 1 + x + x^2 / 2! + x^3 / 3! + ... + x^n / n! (0 < x < 1)哆致。
#!/usr/bin/env python3
x = float(input("Enter the value of x: "))
n = term = num = 1
result = 1.0
while n <= 100:
term *= x / n
result += term
n += 1
if term < 0.0001:
break
print("No of Times= {} and Sum= {}".format(n, result))
乘法表
打印 10 以內(nèi)的乘法表绕德。
#!/usr/bin/env python3
i = 1
print("-" * 50)
while i < 11:
n = 1
while n <= 10:
print("{:5d}".format(i * n), end=' ')
n += 1
print()
i += 1
print("-" * 50)
>>> 's' * 10
'ssssssssss'
>>> print("*" * 10)
**********
>>> print("#" * 20)
####################
>>> print("--" * 20)
----------------------------------------
>>> print("-" * 40)
----------------------------------------
打印星號(hào)的例子
#!/usr/bin/env python3
row = int(input("Enter the number of rows: "))
n = row
while n >= 0:
x = "*" * n
print(x)
n -= 1
#!/usr/bin/env python3
n = int(input("Enter the number of rows: "))
i = 1
while i <= n:
print("*" * i)
i += 1
#!/usr/bin/env python3
row = int(input("Enter the number of rows: "))
n = row
while n >= 0:
x = "*" * n
y = " " * (row - n)
print(y + x)
n -= 1
列表
切片并不會(huì)改變正在操作的列表,切片操作返回其子列表摊阀,這意味著下面的切片操作返回列表一個(gè)新的(棧)拷貝副本:
>>> a[:]
[1, 342, 223, 'India', 'Fedora']
切片時(shí)的索引是在兩個(gè)元素之間 耻蛇。左邊第一個(gè)元素的索引為 0踪蹬,而長(zhǎng)度為 n 的列表其最后一個(gè)元素的右界索引為 n。
Python 中有關(guān)下標(biāo)的集合都滿足左閉右開(kāi)原則臣咖,切片中也是如此跃捣,也就是說(shuō)集合左邊界值能取到,右邊界值不能取到夺蛇。
一個(gè)過(guò)大的索引值(即大于列表實(shí)際長(zhǎng)度)將被列表實(shí)際長(zhǎng)度所代替疚漆,當(dāng)上邊界比下邊界大時(shí)(即切片左值大于右值)就返回空列表。
列表也支持連接這樣的操作刁赦,它返回一個(gè)新的列表
>>> a + [36, 49, 64, 81, 100]
[1, 342, 223, 'India', 'Fedora', 36, 49, 64, 81, 100]
列表允許修改元素:
>>> cubes = [1, 8, 27, 65, 125]
>>> cubes[3] = 64
>>> cubes
[1, 8, 27, 64, 125]
也可以對(duì)切片賦值娶聘,此操作可以改變列表的尺寸,或清空它:
>>> letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> letters
['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> # 替換某些值
>>> letters[2:5] = ['C', 'D', 'E']
>>> letters
['a', 'b', 'C', 'D', 'E', 'f', 'g']
>>> # 現(xiàn)在移除他們
>>> letters[2:5] = []
>>> letters
['a', 'b', 'f', 'g']
>>> # 通過(guò)替換所有元素為空列表來(lái)清空這個(gè)列表
>>> letters[:] = []
>>> letters
[]
要檢查某個(gè)值是否存在于列表中:
>>> a = ['ShiYanLou', 'is', 'cool']
>>> 'cool' in a
True
>>> 'Linux' in a
False
要檢查列表是否為空
if list_name: # 列表不為空
pass
else: # 列表為空
pass
列表是允許嵌套的(創(chuàng)建一個(gè)包含其它列表的列表)
>>> a = ['a', 'b', 'c']
>>> n = [1, 2, 3]
>>> x = [a, n]
>>> x
[['a', 'b', 'c'], [1, 2, 3]]
>>> x[0]
['a', 'b', 'c']
>>> x[0][1]
'b'
for 循環(huán)
>>> a = ['ShiYanLou', 'is', 'powerful']
>>> for x in a:
... print(x)
>>> a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> for x in a[::2]:
... print(x)
如果你需要一個(gè)數(shù)值序列截型,內(nèi)置函數(shù) range() 會(huì)很方便,它生成一個(gè)等差數(shù)列(并不是列表):
>>> for i in range(5):
... print(i)
...
0
1
2
3
4
>>> range(1, 5)
range(1, 5)
>>> list(range(1, 5))
[1, 2, 3, 4]
>>> list(range(1, 15, 3))
[1, 4, 7, 10, 13]
>>> list(range(4, 15, 2))
[4, 6, 8, 10, 12, 14]
continue 語(yǔ)句
如同 break 儒溉,我們可以在循環(huán)中使用另一個(gè)語(yǔ)句 continue宦焦。它會(huì)跳過(guò)其后的代碼回到循環(huán)開(kāi)始處執(zhí)行。這意味著它可以幫助你跳過(guò)部分循環(huán)顿涣。
#!/usr/bin/env python3
while True:
n = int(input("Please enter an Integer: "))
if n < 0:
continue # 這會(huì)返回到循環(huán)開(kāi)始處執(zhí)行
elif n == 0:
break
print("Square is ", n ** 2)
print("Goodbye")
循環(huán)的 else 語(yǔ)句
>>> for i in range(0, 5):
... print(i)
... else:
... print("Bye bye")
棍子游戲
這里有 21 根棍子波闹,首先用戶選 1 到 4 根棍子,然后電腦選 1 到 4 根棍子涛碑。誰(shuí)選到最后一根棍子誰(shuí)就輸精堕。判斷一下用戶有贏的機(jī)會(huì)嗎?如果沒(méi)有的話蒲障,如何修改游戲規(guī)則可以使用戶有贏的機(jī)會(huì)呢歹篓?
特別說(shuō)明:用戶和電腦一次選的棍子總數(shù)只能是 5。
#!/usr/bin/env python3
sticks = 21
print("There are 21 sticks, you can take 1-4 number of sticks at a time.")
print("Whoever will take the last stick will lose")
while True:
print("Sticks left: " , sticks)
if sticks == 1:
print("You took the last stick, you lose")
break
sticks_taken = int(input("Take sticks(1-4):"))
if sticks_taken >= 5 or sticks_taken <= 0:
print("Wrong choice")
continue
print("Computer took: " , (5 - sticks_taken) , "\n")
sticks -= 5
數(shù)據(jù)結(jié)構(gòu)
列表
>>> a = [23, 45, 1, -3434, 43624356, 234]
>>> a.append(45)
>>> a
[23, 45, 1, -3434, 43624356, 234, 45]
>>> a.insert(0, 1) # 在列表索引 0 位置添加元素 1
>>> a
[1, 23, 45, 1, -3434, 43624356, 234, 45]
>>> a.insert(0, 111) # 在列表索引 0 位置添加元素 111
>>> a
[111, 1, 23, 45, 1, -3434, 43624356, 234, 45]
列表方法 count(s) 會(huì)返回列表元素中 s 的數(shù)量
>>> a.count(45)
2
>>> a.remove(234)
>>> a
[111, 1, 23, 45, 1, -3434, 43624356, 45]
>>> a.reverse()
>>> a
[45, 43624356, -3434, 1, 45, 23, 1, 111]
>>> b = [45, 56, 90]
>>> a.extend(b) # 添加 b 的元素而不是 b 本身
>>> a
[45, 43624356, -3434, 1, 45, 23, 1, 111, 45, 56, 90]
>>> a.sort()
>>> a
[-3434, 1, 1, 23, 45, 45, 45, 56, 90, 111, 43624356]
>>> del a[-1]
>>> a
[-3434, 1, 1, 23, 45, 45, 45, 56, 90, 111]
棧是一種 LIFO (Last In First Out 后進(jìn)先出)數(shù)據(jù)結(jié)構(gòu)揉阎。
>>> a = [1, 2, 3, 4, 5, 6]
>>> a
[1, 2, 3, 4, 5, 6]
>>> a.pop()
6
>>> a.pop()
5
>>> a.pop()
4
>>> a.pop()
3
>>> a
[1, 2]
>>> a.append(34)
>>> a
[1, 2, 34]
隊(duì)列 是一種在末尾追加數(shù)據(jù)以及在開(kāi)始彈出數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)庄撮,它是 FIFO (First In First Out 先進(jìn)先出)的數(shù)據(jù)結(jié)構(gòu)。
>>> a = [1, 2, 3, 4, 5]
>>> a.append(1)
>>> a
[1, 2, 3, 4, 5, 1]
>>> a.pop(0)
1
>>> a.pop(0)
2
>>> a
[3, 4, 5, 1]
>>> squares = []
>>> for x in range(10):
... squares.append(x**2)
...
>>> squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
這個(gè) for 循環(huán)中的被創(chuàng)建(或被重寫(xiě))的名為 x 的變量在循環(huán)完畢后依然存在毙籽。
squares = list(map(lambda x: x**2, range(10)))
等價(jià)于
squares = [x**2 for x in range(10)]
列表推導(dǎo)式由包含一個(gè)表達(dá)式的中括號(hào)組成洞斯,表達(dá)式后面跟隨一個(gè) for 子句,之后可以有零或多個(gè) for 或 if 子句坑赡。結(jié)果是一個(gè)列表烙如,由表達(dá)式依據(jù)其后面的 for 和 if 子句上下文計(jì)算而來(lái)的結(jié)果構(gòu)成。
>>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
>>> combs = []
>>> for x in [1,2,3]:
... for y in [3,1,4]:
... if x != y:
... combs.append((x, y))
...
>>> combs
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
>>> a=[1,2,3]
>>> z = [x + 1 for x in [x ** 2 for x in a]]
>>> z
[2, 5, 10]
元組
>>> a = 'Fedora', 'ShiYanLou', 'Kubuntu', 'Pardus'
>>> a
('Fedora', 'ShiYanLou', 'Kubuntu', 'Pardus')
>>> a[1]
'ShiYanLou'
>>> for x in a:
... print(x, end=' ')
...
Fedora ShiYanLou Kubuntu Pardus
>>> divmod(15,2)
(7, 1)
>>> x, y = divmod(15,2)
>>> x
7
>>> y
1
>>> a = (123)
>>> a
123
>>> type(a)
<class 'int'>
>>> a = (123, )
>>> b = 321,
>>> a
(123,)
>>> b
(321,)
>>> type(a)
<class 'tuple'>
>>> type(b)
<class 'tuple'>
>>> type(len)
<class 'builtin_function_or_method'>
集合
集合是一個(gè)無(wú)序不重復(fù)元素的集毅否⊙翘基本功能包括關(guān)系測(cè)試和消除重復(fù)元素。集合對(duì)象還支持 union(聯(lián)合)螟加,intersection(交)刀闷,difference(差)和 symmetric difference(對(duì)稱差集)等數(shù)學(xué)運(yùn)算熊泵。
大括號(hào)或 set() 函數(shù)可以用來(lái)創(chuàng)建集合。注意:想要?jiǎng)?chuàng)建空集合甸昏,你必須使用 set() 而不是 {}顽分。后者用于創(chuàng)建空字典。
>>> basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
>>> print(basket) # 你可以看到重復(fù)的元素被去除
{'orange', 'banana', 'pear', 'apple'}
>>> 'orange' in basket
True
>>> 'crabgrass' in basket
False
>>> # 演示對(duì)兩個(gè)單詞中的字母進(jìn)行集合操作
...
>>> a = set('abracadabra')
>>> b = set('alacazam')
>>> a # a 去重后的字母
{'a', 'r', 'b', 'c', 'd'}
>>> a - b # a 有而 b 沒(méi)有的字母
{'r', 'd', 'b'}
>>> a | b # 存在于 a 或 b 的字母
{'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'}
>>> a & b # a 和 b 都有的字母
{'a', 'c'}
>>> a ^ b # 存在于 a 或 b 但不同時(shí)存在的字母
{'r', 'd', 'b', 'm', 'z', 'l'}
>>> a = {'a','e','h','g'}
>>> a.pop() # pop 方法隨機(jī)刪除一個(gè)元素并打印
'h'
>>> a.add('c')
>>> a
{'c', 'e', 'g', 'a'}
字典
字典是是無(wú)序的鍵值對(duì)(key:value)集合施蜜,同一個(gè)字典內(nèi)的鍵必須是互不相同的卒蘸。一對(duì)大括號(hào) {} 創(chuàng)建一個(gè)空字典。初始化字典時(shí)翻默,在大括號(hào)內(nèi)放置一組逗號(hào)分隔的鍵:值對(duì)缸沃,這也是字典輸出的方式。
>>> data = {'kushal':'Fedora', 'kart_':'Debian', 'Jace':'Mac'}
>>> data
{'kushal': 'Fedora', 'Jace': 'Mac', 'kart_': 'Debian'}
>>> data['kart_']
'Debian'
>>> data['parthan'] = 'Ubuntu'
>>> data
{'kushal': 'Fedora', 'Jace': 'Mac', 'kart_': 'Debian', 'parthan': 'Ubuntu'}
>>> del data['kushal']
>>> data
{'Jace': 'Mac', 'kart_': 'Debian', 'parthan': 'Ubuntu'
>>> 'ShiYanLou' in data
False
>>> dict((('Indian','Delhi'),('Bangladesh','Dhaka')))
{'Indian': 'Delhi', 'Bangladesh': 'Dhaka'}
>>> data
{'Kushal': 'Fedora', 'Jace': 'Mac', 'kart_': 'Debian', 'parthan': 'Ubuntu'}
>>> for x, y in data.items():
... print("{} uses {}".format(x, y))
...
Kushal uses Fedora
Jace uses Mac
kart_ uses Debian
parthan uses Ubuntu
>>> data = {}
>>> data.setdefault('names', []).append('Ruby')
>>> data
{'names': ['Ruby']}
>>> data.setdefault('names', []).append('Python')
>>> data
{'names': ['Ruby', 'Python']}
>>> data.setdefault('names', []).append('C')
>>> data
{'names': ['Ruby', 'Python', 'C']}
>>> data.get('foo', 0)
0
>>> for i, j in enumerate(['a', 'b', 'c']):
... print(i, j)
...
0 a
1 b
2 c
>>> a = ['Pradeepto', 'Kushal']
>>> b = ['OpenSUSE', 'Fedora']
>>> for x, y in zip(a, b):
... print("{} uses {}".format(x, y))
...
Pradeepto uses OpenSUSE
Kushal uses Fedora
判斷學(xué)生成績(jī)是否達(dá)標(biāo)的程序修械,要求輸入學(xué)生數(shù)量趾牧,以及各個(gè)學(xué)生物理、數(shù)學(xué)肯污、歷史三科的成績(jī)翘单,如果總成績(jī)小于 120,程序打印 “failed”蹦渣,否則打印 “passed”哄芜。
#!/usr/bin/env python3
n = int(input("Enter the number of students: "))
data = {} # 用來(lái)存儲(chǔ)數(shù)據(jù)的字典變量
Subjects = ('Physics', 'Maths', 'History') # 所有科目
for i in range(0, n):
name = input('Enter the name of the student {}: '.format(i + 1)) # 獲得學(xué)生名稱
marks = []
for x in Subjects:
marks.append(int(input('Enter marks of {}: '.format(x)))) # 獲得每一科的分?jǐn)?shù)
data[name] = marks
for x, y in data.items():
total = sum(y)
print("{}'s total marks {}".format(x, total))
if total < 120:
print(x, "failed :(")
else:
print(x, "passed :)")
計(jì)算兩個(gè)矩陣的 Hadamard 乘積。要求輸入矩陣的行/列數(shù)(在這里假設(shè)我們使用的是 n × n 的矩陣)柬唯。
#!/usr/bin/env python3
n = int(input("Enter the value of n: "))
print("Enter values for the Matrix A")
a = []
for i in range(n):
a.append([int(x) for x in input().split()])
print("Enter values for the Matrix B")
b = []
for i in range(n):
b.append([int(x) for x in input().split()])
c = []
for i in range(n):
c.append([a[i][j] * b[i][j] for j in range(n)])
print("After matrix multiplication")
print("-" * 7 * n)
for x in c:
for y in x:
print(str(y).rjust(5), end=' ')
print()
print("-" * 7 * n)
字符串
>>> s = "I am Chinese"
>>> s
'I am Chinese'
>>> s = 'I am Chinese'
>>> s = "Here is a line \
... split in two lines"
>>> s
'Here is a line split in two lines'
>>> s = "Here is a line \n split in two lines"
>>> s
'Here is a line \n split in two lines'
>>> print(s)
Here is a line
split in two lines
>>> print("""\
... Usage: thingy [OPTIONS]
... -h Display this usage message
... -H hostname Hostname to connect to
... """)
Usage: thingy [OPTIONS]
-h Display this usage message
-H hostname Hostname to connect to
>>> s = "shi yan lou"
>>> s.title()
'Shi Yan Lou'
>>> z = s.upper()
>>> z
'SHI YAN LOU'
>>> z.lower()
'shi yan lou'
>>> s = "I am A pRoGraMMer"
>> s.swapcase()
'i AM a PrOgRAmmER'
>>> s = "jdwb 2323bjb"
>>> s.isalnum()
False
>>> s = "jdwb2323bjb"
>>> s.isalnum()
True
>>> s = "SankarshanSir"
>>> s.isalpha()
True
>>> s = "Sankarshan Sir"
>>> s.isalpha()
False
>>> s = "1234"
>>> s.isdigit() # 檢查字符串是否所有字符為數(shù)字
True
>>> s = "ShiYanLou is coming"
>>> s.islower() # 檢查字符串是否所有字符為小寫(xiě)
False
>>> s = "Shiyanlou Is Coming"
>>> s.istitle() # To 檢查字符串是否為標(biāo)題樣式
True
>>> s = "CHINA"
>>> s.isupper() # 檢查字符串是否所有字符為大寫(xiě)
True
>>> s = "We all love Python"
>>> s.split()
['We', 'all', 'love', 'Python']
>>> x = "shiyanlou:is:waiting"
>>> x.split(':')
['shiyanlou', 'is', 'waiting']
>>> "-".join("GNU/Linux is great".split())
'GNU/Linux-is-great'
>>> s = " a bc\n "
>>> s.strip()
'a bc'
>>> s = "www.foss.in"
>>> s.lstrip("cwsd.") #刪除在字符串左邊出現(xiàn)的'c','w','s','d','.'字符
'foss.in'
>>> s.rstrip("cnwdi.") #刪除在字符串右邊出現(xiàn)的'c','n','w','d','i','.'字符
'www.foss'
>>> s = "faulty for a reason"
>>> s.find("for")
7
>>> s.find("fora")
-1
>>> s.startswith("fa") # 檢查字符串是否以 fa 開(kāi)頭
True
>>> s.endswith("reason") # 檢查字符串是否以 reason 結(jié)尾
True
find() 能幫助你找到第一個(gè)匹配的子字符串认臊,沒(méi)有找到則返回 -1。
回文是一種無(wú)論從左還是從右讀都一樣的字符序列锄奢。比如 “madam”失晴。
#!/usr/bin/env python3
s = input("Please enter a string: ")
z = s[::-1] #把輸入的字符串s 進(jìn)行倒序處理形成新的字符串z
if s == z:
print("The string is a palindrome")
else:
print("The string is not a palindrome")
對(duì)用戶輸入的一行文本進(jìn)行單詞計(jì)數(shù)
#!/usr/bin/env python3
s = input("Enter a line: ")
print("The number of words in the line are %d" % (len(s.split(" "))))
函數(shù)
編寫(xiě)一個(gè)函數(shù)來(lái)檢查給出的字符串是否為回文,然后返回 True 或者 False拘央。
#!/usr/bin/env python3
def palindrome(s):
return s == s[::-1]
if __name__ == '__main__':
s = input("Enter a string: ")
if palindrome(s):
print("Yay a palindrome")
else:
print("Oh no, not a palindrome")
在函數(shù)內(nèi)部和函數(shù)調(diào)用的代碼中都使用同一個(gè)變量 a
#!/usr/bin/env python3
def change():
a = 90
print(a)
a = 9
print("Before the function call ", a)
print("inside change function", end=' ')
change()
print("After the function call ", a)
先定義 a师坎,在函數(shù)中使用
#!/usr/bin/env python3
a = 9
def change():
print(a)
change()
使用 global 關(guān)鍵字,對(duì)函數(shù)中的 a 標(biāo)志為全局變量堪滨,讓函數(shù)內(nèi)部使用全局變量的 a
#!/usr/bin/env python3
a = 9
def change():
global a
print(a)
a = 100
print("Before the function call ", a)
print("inside change function", end=' ')
change()
print("After the function call ", a)
#!/usr/bin/env python3
def change():
global a
a = 90
print(a)
a = 9
print("Before the function call ", a)
print("inside change function", end=' ')
change()
print("After the function call ", a)
函數(shù)的參數(shù)變量可以有默認(rèn)值吏廉,也就是說(shuō)如果我們?cè)谡{(diào)用函數(shù)時(shí)對(duì)指定的參數(shù)變量沒(méi)有給出任何值則會(huì)賦其默認(rèn)值北启。
>>> def test(a , b=-99):
... if a > b:
... return True
... else:
... return False
具有默認(rèn)值的參數(shù)后面不能再有普通參數(shù)尾菇,默認(rèn)值只被賦值一次式曲,因此如果默認(rèn)值是任何可變對(duì)象時(shí)會(huì)有所不同
>>> def f(a, data=None):
... if data is None:
... data = []
... data.append(a)
... return data
...
>>> print(f(1))
[1]
>>> print(f(2))
[2]
>>> def func(a, b=5, c=10):
... print('a is', a, 'and b is', b, 'and c is', c)
>>> def hello(*, name='User'):
... print("Hello", name)
#!/usr/bin/env python3
import math
def longest_side(a, b):
"""
Function to find the length of the longest side of a right triangle.
:arg a: Side a of the triangle
:arg b: Side b of the triangle
:return: Length of the longest side c as float
"""
return math.sqrt(a*a + b*b)
if __name__ == '__main__':
print(longest_side.__doc__)
print(longest_side(4,5))
高階函數(shù):使用一個(gè)或多個(gè)函數(shù)作為參數(shù),返回另一個(gè)函數(shù)作為輸出
# 創(chuàng)建一個(gè)函數(shù)发笔,將參數(shù)列表中每個(gè)元素都變成全大寫(xiě)
>>> def high(l):
... return [i.upper() for i in l]
...
# 創(chuàng)建高階函數(shù)盟萨,接受一個(gè)函數(shù)和一個(gè)列表作為參數(shù)
>>> def test(h, l):
... return h(l)
map 它接受一個(gè)函數(shù)和一個(gè)序列(迭代器)作為輸入,然后對(duì)序列(迭代器)的每一個(gè)值應(yīng)用這個(gè)函數(shù)了讨,返回一個(gè)序列(迭代器)捻激,其包含應(yīng)用函數(shù)后的結(jié)果制轰。
>>> lst = [1, 2, 3, 4, 5]
>>> def square(num):
... "返回所給數(shù)字的平方."
... return num * num
文件處理
使用 open() 函數(shù)打開(kāi)文件
"r",以只讀模式打開(kāi)胞谭,你只能讀取文件但不能編輯/刪除文件的任何內(nèi)容
"w"垃杖,以寫(xiě)入模式打開(kāi),如果文件存在將會(huì)刪除里面的所有內(nèi)容丈屹,然后打開(kāi)這個(gè)文件進(jìn)行寫(xiě)入
"a"调俘,以追加模式打開(kāi),寫(xiě)入到文件中的任何數(shù)據(jù)將自動(dòng)添加到末尾
打開(kāi)文件后我們應(yīng)該總是關(guān)閉文件旺垒,我們使用方法 close() 完成這個(gè)操作彩库。
>>> fobj.close()
始終確保你顯式關(guān)閉每個(gè)打開(kāi)的文件,一旦它的工作完成你沒(méi)有任何理由保持打開(kāi)文件先蒋。
文件· https://labfile.oss.aliyuncs.com/courses/596/sample.txt
>>> fobj = open("sample.txt")
>>> fobj.read()
'I love Python\nI love shiyanlou\n'
>>> fobj.close()
read(size) 有一個(gè)可選的參數(shù) size骇钦,用于指定字符串長(zhǎng)度。如果沒(méi)有指定 size 或者指定為負(fù)數(shù)竞漾,就會(huì)讀取并返回整個(gè)文件眯搭。
>>> fobj = open("sample.txt")
>>> fobj.readline()
'I love Python\n'
>>> fobj.readline()
'I love shiyanlou\n'
>>> fobj.close()
>>> fobj = open('sample.txt')
>>> fobj.readlines()
['I love Python\n', 'I love shiyanlou\n']
>>> fobj.close()
>>> fobj = open('sample.txt')
>>> for x in fobj:
... print(x, end = '')
...
I love Python
I love shiyanlou
>>> fobj.close()
接受用戶輸入的字符串作為將要讀取的文件的文件名,并且在屏幕上打印文件內(nèi)容畴蹭。
#!/usr/bin/env python3
name = input("Enter the file name: ")
fobj = open(name)
print(fobj.read())
fobj.close()
>>> fobj = open("ircnicks.txt", 'w')
>>> fobj.write('powerpork\n')
>>> fobj.write('indrag\n')
>>> fobj.write('mishti\n')
>>> fobj.write('sankarshan')
>>> fobj.close()
>>> fobj = open('ircnicks.txt')
>>> s = fobj.read()
>>> fobj.close()
>>> print(s)
拷貝給定的文本文件到另一個(gè)給定的文本文件坦仍。
#!/usr/bin/env python3
import sys
if len(sys.argv) < 3:
print("Wrong parameter")
print("./copyfile.py file1 file2")
sys.exit(1)
f1 = open(sys.argv[1])
s = f1.read()
f1.close()
f2 = open(sys.argv[2], 'w')
f2.write(s)
f2.close()
對(duì)任意給定文本文件中的制表符鳍烁、行叨襟、空格進(jìn)行計(jì)數(shù)。
#!/usr/bin/env python3
import os
import sys
def parse_file(path):
"""
分析給定文本文件幔荒,返回其空格糊闽、制表符、行的相關(guān)信息
:arg path: 要分析的文本文件的路徑
:return: 包含空格數(shù)爹梁、制表符數(shù)右犹、行數(shù)的元組
"""
fd = open(path)
i = 0
spaces = 0
tabs = 0
for i,line in enumerate(fd):
spaces += line.count(' ')
tabs += line.count('\t')
# 現(xiàn)在關(guān)閉打開(kāi)的文件
fd.close()
# 以元組形式返回結(jié)果
return spaces, tabs, i + 1
def main(path):
"""
函數(shù)用于打印文件分析結(jié)果
:arg path: 要分析的文本文件的路徑
:return: 若文件存在則為 True,否則 False
"""
if os.path.exists(path):
spaces, tabs, lines = parse_file(path)
print("Spaces {}. tabs {}. lines {}".format(spaces, tabs, lines))
return True
else:
return False
if __name__ == '__main__':
if len(sys.argv) > 1:
main(sys.argv[1])
else:
sys.exit(-1)
sys.exit(0)
在實(shí)際情況中姚垃,應(yīng)該嘗試使用 with 語(yǔ)句處理文件對(duì)象念链,它會(huì)在文件用完后會(huì)自動(dòng)關(guān)閉,就算發(fā)生異常也沒(méi)關(guān)系积糯。
>>> with open('sample.txt') as fobj:
... for line in fobj:
... print(line, end = '')
字符串操作
文件 https://labfile.oss.aliyuncs.com/courses/790/String.txt
用 open 打開(kāi)文件 /tmp/String.txt 并讀取其中的字符串
提取字符串中的所有數(shù)字掂墓,并組合成一個(gè)新的字符串,然后打印輸出
# 打開(kāi)并讀取文件里的字符串
with open('/tmp/String.txt') as f:
s = f.read()
res = ""
# 循環(huán)字符串里的每個(gè)字符看成,判斷是否為數(shù)字
for char in s:
if char.isdigit():
res += char
print(res)
異常
當(dāng)訪問(wèn)一個(gè)未定義的變量則會(huì)發(fā)生 NameError
當(dāng)操作或函數(shù)應(yīng)用于不適當(dāng)類(lèi)型的對(duì)象時(shí)引發(fā)TypeError
使用 try...except 塊來(lái)處理任意異常:
try:
statements to be inside try clause
statement2
statement3
...
except ExceptionName:
statements to evaluated in case of ExceptionName happens
>>> def get_number():
... "Returns a float number"
... number = float(input("Enter a float number: "))
... return number
...
>>>
>>> while True:
... try:
... print(get_number())
... except ValueError:
... print("You entered a wrong value.")
一個(gè)空的 except 語(yǔ)句能捕獲任何異常
>>> try:
... input() # 輸入的時(shí)候按下 Ctrl + C 產(chǎn)生 KeyboardInterrupt
... except:
... print("Unknown Exception")
使用 raise 語(yǔ)句拋出一個(gè)異常
raise ValueError("A value error happened.")
>>> try:
... raise ValueError("A value error happened.")
... except ValueError:
... print("ValueError in our code.")
try 語(yǔ)句還有另一個(gè)可選的 finally 子句君编,目的在于定義在任何情況下都一定要執(zhí)行的功能。
>>> try:
... raise KeyboardInterrupt
... finally:
... print('Goodbye, world!')
玩轉(zhuǎn)函數(shù)
實(shí)現(xiàn)一個(gè)程序川慌,將分鐘轉(zhuǎn)為小時(shí)和分鐘吃嘿。
用戶能夠通過(guò)命令行參數(shù)輸入分鐘數(shù)祠乃,不要使用 input,命令行參數(shù)可以使用 sys.argv 來(lái)提取兑燥。例如程序執(zhí)行為 python3 MinutesToHours.py 80亮瓷,傳入的參數(shù) 80 就是分鐘數(shù),程序需要打印出相應(yīng)的小時(shí)數(shù)和分鐘數(shù)贪嫂,輸出為 1H, 20M寺庄。
如果用戶輸入的是一個(gè)負(fù)值,程序需要 raise 來(lái)拋出 ValueError 異常力崇。
Hours() 函數(shù)調(diào)用的時(shí)候斗塘,需要使用 try...except 處理異常。獲取異常后亮靴,在屏幕上打印出 Parameter Error 提示用戶輸入的值有誤馍盟。
import sys
# 轉(zhuǎn)換函數(shù)
def Hours(minute):
# 如果為負(fù)數(shù)則 raise 異常
if minute < 0:
raise ValueError("Input number cannot be negative")
else:
print("{} H, {} M".format(int(minute / 60), minute % 60))
# 函數(shù)調(diào)用及異常處理邏輯
try:
Hours(int(sys.argv[1]))
except:
print("Parameter Error")
類(lèi)
在 Python 中,所有數(shù)據(jù)類(lèi)型都可以視為對(duì)象茧吊,當(dāng)然也可以自定義對(duì)象贞岭。自定義的對(duì)象數(shù)據(jù)類(lèi)型就是面向?qū)ο笾械念?lèi)(Class)的概念。
以下面這種方式定義類(lèi):
class nameoftheclass(parent_class):
statement1
statement2
statement3
_init_ 方法
類(lèi)的實(shí)例化使用函數(shù)符號(hào)搓侄。只要將類(lèi)對(duì)象看作是一個(gè)返回新的類(lèi)實(shí)例的無(wú)參數(shù)函數(shù)即可瞄桨。
x = MyClass()
很多類(lèi)都傾向于將對(duì)象創(chuàng)建為有初始狀態(tài)的。因此類(lèi)可能會(huì)定義一個(gè)名為 init() 的特殊方法讶踪,像下面這樣:
def __init__(self):
self.data = []
出于彈性的需要芯侥,init() 方法可以有參數(shù)。事實(shí)上乳讥,參數(shù)通過(guò)init() 傳遞到類(lèi)的實(shí)例化操作上柱查。例如:
>>> class Complex:
... def __init__(self, realpart, imagpart):
... self.r = realpart
... self.i = imagpart
...
>>> x = Complex(3.0, -4.5)
>>> x.r, x.i
繼承
當(dāng)一個(gè)類(lèi)繼承另一個(gè)類(lèi)時(shí),它將繼承父類(lèi)的所有功能(如變量和方法)云石。這有助于重用代碼唉工。
#!/usr/bin/env python3
class Person(object):
"""
返回具有給定名稱的 Person 對(duì)象
"""
def __init__(self, name):
self.name = name
def get_details(self):
"""
返回包含人名的字符串
"""
return self.name
class Student(Person):
"""
返回 Student 對(duì)象,采用 name, branch, year 3 個(gè)參數(shù)
"""
def __init__(self, name, branch, year):
Person.__init__(self, name)
self.branch = branch
self.year = year
def get_details(self):
"""
返回包含學(xué)生具體信息的字符串
"""
return "{} studies {} and is in {} year.".format(self.name, self.branch, self.year)
class Teacher(Person):
"""
返回 Teacher 對(duì)象汹忠,采用字符串列表作為參數(shù)
"""
def __init__(self, name, papers):
Person.__init__(self, name)
self.papers = papers
def get_details(self):
return "{} teaches {}".format(self.name, ','.join(self.papers))
person1 = Person('Sachin')
student1 = Student('Kushal', 'CSE', 2005)
teacher1 = Teacher('Prashad', ['C', 'C++'])
print(person1.get_details())
print(student1.get_details())
print(teacher1.get_details())
多繼承
一個(gè)類(lèi)可以繼承自多個(gè)類(lèi)淋硝,具有父類(lèi)的所有變量和方法
class MyClass(Parentclass1, Parentclass2,...):
def __init__(self):
Parentclass1.__init__(self)
Parentclass2.__init__(self)
...
...
刪除對(duì)象
>>> s = "I love you"
>>> del s
del 實(shí)際上使對(duì)象的引用計(jì)數(shù)減少一,當(dāng)對(duì)象的引用計(jì)數(shù)變成零的時(shí)候宽菜,垃圾回收器會(huì)刪除這個(gè)對(duì)象谣膳。
屬性(attributes)讀取方法
>>> class Student(object):
... def __init__(self, name):
... self.name = name
...
>>> std = Student("Kushal Das")
>>> print(std.name)
>>> std.name = "Python"
>>> print(std.name)
裝飾器
@property 裝飾器就是負(fù)責(zé)把一個(gè)方法變成屬性調(diào)用的。
#!/usr/bin/env python3
class Account(object):
"""賬號(hào)類(lèi),
amount 是美元金額.
"""
def __init__(self, rate):
self.__amt = 0
self.rate = rate
@property
def amount(self):
"""賬號(hào)余額(美元)"""
return self.__amt
@property
def cny(self):
"""賬號(hào)余額(人民幣)"""
return self.__amt * self.rate
@amount.setter
def amount(self, value):
if value < 0:
print("Sorry, no negative amount in the account.")
return
self.__amt = value
if __name__ == '__main__':
acc = Account(rate=6.6) # 基于課程編寫(xiě)時(shí)的匯率
acc.amount = 20
print("Dollar amount:", acc.amount)
print("In CNY:", acc.cny)
acc.amount = -100
print("Dollar amount:", acc.amount)
模塊
但是當(dāng)人們編寫(xiě)大型程序的時(shí)候他們會(huì)傾向于將代碼分為多個(gè)不同的文件以便使用赋焕,調(diào)試以及擁有更好的可讀性参歹。在 Python 中我們使用模塊來(lái)到達(dá)這些目的。模塊是包括 Python 定義和聲明的文件隆判。文件名就是模塊名加上 .py 后綴犬庇。
以由全局變量 _name_ 得到模塊的模塊名(一個(gè)字符串)僧界。
創(chuàng)建一個(gè) bars.py 文件
"""
Bars Module
============
這是一個(gè)打印不同分割線的示例模塊
"""
def starbar(num):
"""打印 * 分割線
:arg num: 線長(zhǎng)
"""
print('*' * num)
def hashbar(num):
"""打印 # 分割線
:arg num: 線長(zhǎng)
"""
print('#' * num)
def simplebar(num):
"""打印 - 分割線
:arg num: 線長(zhǎng)
"""
print('-' * num)
>>> import bars
>>> bars.hashbar(10)
>>> bars.simplebar(10)
>>> bars.starbar(10)
導(dǎo)入模塊
>>> from bars import simplebar, starbar
>>> simplebar(20)
包
含有 _init_.py 文件的目錄可以用來(lái)作為一個(gè)包,目錄里的所有 .py 文件都是這個(gè)包的子模塊臭挽。
創(chuàng)建 mymodule 目錄
cd /home/shiyanlou
mkdir mymodule
將bars.py 拷貝到 mymodule 目錄下捂襟,然后可以使用 touch 創(chuàng)建一個(gè) utils.py 文件。
使用 touch 命令創(chuàng)建一個(gè)空的 _init_.py 文件
touch mymodule/__init__.py
如果 _init_.py 文件內(nèi)有一個(gè)名為 _all_ 的列表欢峰,那么只有在列表內(nèi)列出的名字將會(huì)被公開(kāi)葬荷。
from mymodule.bars import simplebar
__all__ = [simplebar, ]
那么導(dǎo)入時(shí)將只有 simplebar 可用。
默認(rèn)模塊
使用 help() 函數(shù)查找任何模塊/類(lèi)的文檔纽帖。
>>> help(str)
os 模塊
os模塊提供了與操作系統(tǒng)相關(guān)的功能宠漩。
getuid() 函數(shù)返回當(dāng)前進(jìn)程的有效用戶 id。
>>> os.getuid()
getpid() 函數(shù)返回當(dāng)前進(jìn)程的 id懊直。getppid() 返回父進(jìn)程的 id扒吁。
>>> os.getpid()
>>> os.getppid()
uname() 函數(shù)返回識(shí)別操作系統(tǒng)的不同信息,在 Linux 中它返回的詳細(xì)信息可以從 uname -a 命令得到室囊。uname() 返回的對(duì)象是一個(gè)元組雕崩,(sysname, nodename, release, version, machine)。
>>> os.uname()
getcwd() 函數(shù)返回當(dāng)前工作目錄融撞。chdir(path) 則是更改當(dāng)前目錄到 path盼铁。
>>> os.getcwd()
>>> os.chdir('Code')
>>> os.getcwd()
使用 os 模塊提供的另一個(gè)函數(shù)來(lái)創(chuàng)建一個(gè)自己的函數(shù),它將列出給定目錄下的所有文件和目錄尝偎。
def view_dir(path='.'):
"""
這個(gè)函數(shù)打印給定目錄中的所有文件和目錄
:args path: 指定目錄饶火,默認(rèn)為當(dāng)前目錄
"""
names = os.listdir(path)
names.sort()
for name in names:
print(name, end =' ')
print()
Requests 模塊
可以使用 get() 方法獲取任意一個(gè)網(wǎng)頁(yè)。
>>> import requests
>>> req = requests.get('https://github.com')
>>> req.status_code
寫(xiě)一個(gè)能夠從指定的 URL 中下載文件的程序冬念。
#!/usr/bin/env python3
import requests
def download(url):
'''
從指定的 URL 中下載文件并存儲(chǔ)到當(dāng)前目錄
url: 要下載頁(yè)面內(nèi)容的網(wǎng)址
'''
# 檢查 URL 是否存在
try:
req = requests.get(url)
except requests.exceptions.MissingSchema:
print('Invalid URL "{}"'.format(url))
return
# 檢查是否成功訪問(wèn)了該網(wǎng)站
if req.status_code == 403:
print('You do not have the authority to access this page.')
return
filename = url.split('/')[-1]
with open(filename, 'w') as fobj:
fobj.write(req.content.decode('utf-8'))
print("Download over.")
if __name__ == '__main__':
url = input('Enter a URL: ')
download(url)
if _name_ == '_main_': 這條語(yǔ)句趁窃,它的作用是牧挣,只有在當(dāng)前模塊名為 _main_ 的時(shí)候(即作為腳本執(zhí)行的時(shí)候)才會(huì)執(zhí)行此 if 塊內(nèi)的語(yǔ)句急前。換句話說(shuō),當(dāng)此文件以模塊的形式導(dǎo)入到其它文件中時(shí)瀑构,if 塊內(nèi)的語(yǔ)句并不會(huì)執(zhí)行裆针。
argparse 命令行參數(shù)處理模塊
TAB 補(bǔ)全
先創(chuàng)建一個(gè)文件:~/.pythonrc
import rlcompleter, readline
readline.parse_and_bind('tab: complete')
history_file = os.path.expanduser('~/.python_history')
readline.read_history_file(history_file)
import atexit
atexit.register(readline.write_history_file, history_file)
在 ~/.bashrc 文件中設(shè)置 PYTHONSTARTUP 環(huán)境變量指向這個(gè)文件:
export PYTHONSTARTUP=~/.pythonrc
每當(dāng)你打開(kāi) bash shell,你將會(huì)有 TAB 補(bǔ)全和 Python 解釋器中代碼輸入的歷史記錄寺晌。
要在當(dāng)前 shell 中使用世吨,source 這個(gè) bashrc 文件。
source ~/.bashrc
Collections 模塊
Counter
Counter 是一個(gè)有助于 hashable 對(duì)象計(jì)數(shù)的 dict 子類(lèi)呻征。它是一個(gè)無(wú)序的集合耘婚,其中 hashable 對(duì)象的元素存儲(chǔ)為字典的鍵,它們的計(jì)數(shù)存儲(chǔ)為字典的值陆赋,計(jì)數(shù)可以為任意整數(shù)沐祷,包括零和負(fù)數(shù)嚷闭。
查看 Python 的 LICENSE 文件中某些單詞出現(xiàn)的次數(shù)。
>>> from collections import Counter
>>> import re
>>> path = '/usr/lib/python3.5/LICENSE.txt'
>>> words = re.findall('\w+', open(path).read().lower())
>>> Counter(words).most_common(10)
Counter 對(duì)象有一個(gè)叫做 elements() 的方法赖临,其返回的序列中胞锰,依照計(jì)數(shù)重復(fù)元素相同次數(shù),元素順序是無(wú)序的兢榨。
>>> c = Counter(a=4, b=2, c=0, d=-2)
>>> list(c.elements())
['b','b','a', 'a', 'a', 'a']
most_common() 方法返回最常見(jiàn)的元素及其計(jì)數(shù)嗅榕,順序?yàn)樽畛R?jiàn)到最少。
>>> Counter('abracadabra').most_common(3)
[('a', 5), ('r', 2), ('b', 2)]
defaultdict
defaultdict 是內(nèi)建 dict 類(lèi)的子類(lèi)吵聪,它覆寫(xiě)了一個(gè)方法并添加了一個(gè)可寫(xiě)的實(shí)例變量凌那。其余功能與字典相同。
同樣的功能使用 defaultdict 比使用 dict.setdefault 方法快吟逝。
>>> from collections import defaultdict
>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
... d[k].append(v)
...
>>> d.items()
namedtuple
命名元組有助于對(duì)元組每個(gè)位置賦予意義案怯,并且讓我們的代碼有更好的可讀性和自文檔性。你可以在任何使用元組地方使用命名元組澎办。在例子中我們會(huì)創(chuàng)建一個(gè)命名元組以展示為元組每個(gè)位置保存信息嘲碱。
>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y']) # 定義命名元組
>>> p = Point(10, y=20) # 創(chuàng)建一個(gè)對(duì)象
>>> p
Point(x=10, y=20)
>>> p.x + p.y
30
>>> p[0] + p[1] # 像普通元組那樣訪問(wèn)元素
30
>>> x, y = p # 元組拆封
>>> x
10
>>> y
20
類(lèi)和 Collection
改寫(xiě) 我們?cè)?類(lèi) 這個(gè)實(shí)驗(yàn)中 繼承 部分的 student_teacher.py 腳本,實(shí)現(xiàn)以下功能:
在 Person() 類(lèi)中增添函數(shù) get_grade()
對(duì)于教師類(lèi)局蚀,get_grade() 函數(shù)可以自動(dòng)統(tǒng)計(jì)出老師班上學(xué)生的得分情況并按照頻率的高低以 A: X, B: X, C: X, D: X 的形式打印出來(lái)
對(duì)于學(xué)生類(lèi)麦锯,get_grade() 函數(shù)則可以以 Pass: X, Fail: X 來(lái)統(tǒng)計(jì)自己的成績(jī)情況(A,B,C 為 Pass, 如果得了 D 就認(rèn)為是 Fail)。
#!/usr/bin/env python3
class Person(object):
"""
返回具有給定名稱的 Person 對(duì)象
"""
def __init__(self, name):
self.name = name
def get_details(self):
"""
返回包含人名的字符串
"""
return self.name
class Student(Person):
"""
返回 Student 對(duì)象琅绅,采用 name, branch, year 3 個(gè)參數(shù)
"""
def __init__(self, name, branch, year):
Person.__init__(self, name)
self.branch = branch
self.year = year
def get_details(self):
"""
返回包含學(xué)生具體信息的字符串
"""
return "{} studies {} and is in {} year.".format(self.name, self.branch, self.year)
class Teacher(Person):
"""
返回 Teacher 對(duì)象扶欣,采用字符串列表作為參數(shù)
"""
def __init__(self, name, papers):
Person.__init__(self, name)
self.papers = papers
def get_details(self):
return "{} teaches {}".format(self.name, ','.join(self.papers))
person1 = Person('Sachin')
student1 = Student('Kushal', 'CSE', 2005)
teacher1 = Teacher('Prashad', ['C', 'C++'])
print(person1.get_details())
print(student1.get_details())
print(teacher1.get_details())
#!/usr/bin/env python3
import sys
from collections import Counter
class Person(object):
"""
返回具有給定名稱的 Person 對(duì)象
"""
def __init__(self, name):
self.name = name
def get_details(self):
"""
返回包含人名的字符串
"""
return self.name
def get_grade(self):
return 0
class Student(Person):
"""
返回 Student 對(duì)象,采用 name, branch, year 3 個(gè)參數(shù)
"""
def __init__(self, name, branch, year,grade):
Person.__init__(self, name)
self.branch = branch
self.year = year
self.grade = grade
def get_details(self):
"""
返回包含學(xué)生具體信息的字符串
"""
return "{} studies {} and is in {} year.".format(self.name, self.branch, self.year)
def get_grade(self):
common = Counter(self.grade).most_common(4)
n1 = 0
n2 = 0
for item in common:
if item[0] != 'D':
n1 += item[1]
else:
n2 += item[1]
print("Pass: {}, Fail: {}".format(n1,n2))
class Teacher(Person):
"""
返回 Teacher 對(duì)象千扶,采用字符串列表作為參數(shù)
"""
def __init__(self, name, papers, grade):
Person.__init__(self, name)
self.papers = papers
self.grade = grade
def get_details(self):
return "{} teaches {}".format(self.name, ','.join(self.papers))
def get_grade(self):
s = []
common = Counter(self.grade).most_common(4)
for i,j in common:
s.append("{}: {}".format(i,j))
print(', '.join(s))
person1 = Person('Sachin')
if sys.argv[1] == "student":
student1 = Student('Kushal', 'CSE', 2005, sys.argv[2])
student1.get_grade()
else:
teacher1 = Teacher('Prashad', ['C', 'C++'], sys.argv[2])
teacher1.get_grade()
PEP8 代碼風(fēng)格指南
代碼排版
每層縮進(jìn)使用 4 個(gè)空格料祠。
續(xù)行要么與圓括號(hào)、中括號(hào)澎羞、花括號(hào)這樣的被包裹元素保持垂直對(duì)齊髓绽,要么放在 Python 的隱線(注:應(yīng)該是相對(duì)于 def 的內(nèi)部塊)內(nèi)部,或者使用懸掛縮進(jìn)妆绞。使用懸掛縮進(jìn)的注意事項(xiàng):第一行不能有參數(shù)顺呕,用進(jìn)一步的縮進(jìn)來(lái)把其他行區(qū)分開(kāi)。
# Aligned with opening delimiter.
foo = long_function_name(var_one, var_two,
var_three, var_four)
# More indentation included to distinguish this from the rest.
def long_function_name(
var_one, var_two, var_three,
var_four):
print(var_one)
# Hanging indents should add a level.
foo = long_function_name(
var_one, var_two,
var_three, var_four)
當(dāng) if 語(yǔ)句的條件部分足夠長(zhǎng)括饶,需要將它寫(xiě)入到多個(gè)行株茶,值得注意的是兩個(gè)連在一起的關(guān)鍵字(i.e. if),添加一個(gè)空格图焰,給后續(xù)的多行條件添加一個(gè)左括號(hào)形成自然地 4 空格縮進(jìn)启盛。如果和嵌套在 if 語(yǔ)句內(nèi)的縮進(jìn)代碼塊產(chǎn)生了視覺(jué)沖突,也應(yīng)該被自然縮進(jìn) 4 個(gè)空格。這份增強(qiáng)建議書(shū)對(duì)于怎樣(或是否)把條件行和 if 語(yǔ)句的縮進(jìn)塊在視覺(jué)上區(qū)分開(kāi)來(lái)是沒(méi)有明確規(guī)定的僵闯。
# No extra indentation.
if (this_is_one_thing and
that_is_another_thing):
do_something()
# Add a comment, which will provide some distinction in editors
# supporting syntax highlighting.
if (this_is_one_thing and
that_is_another_thing):
# Since both conditions are true, we can frobnicate.
do_something()
# Add some extra indentation on the conditional continuation line.
if (this_is_one_thing
and that_is_another_thing):
do_something()
在多行結(jié)構(gòu)中的右圓括號(hào)笤闯、右中括號(hào)、右大括號(hào)應(yīng)該放在最后一行的第一個(gè)非空白字符的正下方
my_list = [
1, 2, 3,
4, 5, 6,
]
result = some_function_that_takes_arguments(
'a', 'b', 'c',
'd', 'e', 'f',
)
或者放在多行結(jié)構(gòu)的起始行的第一個(gè)字符正下方
my_list = [
1, 2, 3,
4, 5, 6,
]
result = some_function_that_takes_arguments(
'a', 'b', 'c',
'd', 'e', 'f',
)
空格是首選的縮進(jìn)方法棍厂。
限制每行的最大長(zhǎng)度為 79 個(gè)字符颗味。
對(duì)于那些約束很少的文本結(jié)構(gòu)(文檔字符串或注釋?zhuān)┑拈L(zhǎng)塊,應(yīng)該限制每行長(zhǎng)度為 72 個(gè)字符牺弹。
限制編輯器窗口寬為 80 來(lái)避免自動(dòng)換行浦马,即使有些編輯工具在換行的時(shí)候會(huì)在最后一列放一個(gè)標(biāo)識(shí)符。
首選的換行方式是在括號(hào)(小中大)內(nèi)隱式換行(非續(xù)行符 \)张漂。長(zhǎng)行應(yīng)該在括號(hào)表達(dá)式的包裹下?lián)Q行晶默。這比反斜杠作為續(xù)行符更好。
with open('/path/to/some/file/you/want/to/read') as file_1, \
open('/path/to/some/file/being/written', 'w') as file_2:
file_2.write(file_1.read())
class Rectangle(Blob):
def __init__(self, width, height,
color='black', emphasis=None, highlight=0):
if (width == 0 and height == 0 and
color == 'red' and emphasis == 'strong' or
highlight > 100):
raise ValueError("sorry, you lose")
if width == 0 and height == 0 and (color == 'red' or
emphasis is None):
raise ValueError("I don't think so -- values are %s, %s" %
(width, height))
Blob.__init__(self, width, height,
color, emphasis, highlight)
頂級(jí)函數(shù)和類(lèi)定義上下使用兩個(gè)空行分隔航攒。
類(lèi)內(nèi)的方法定義使用一個(gè)空行分隔磺陡。
可以使用額外的空行(有節(jié)制的)來(lái)分隔相關(guān)聯(lián)的函數(shù)組。在一系列相關(guān)聯(lián)的單行代碼中空行可以省略(e.g. 一組虛擬的實(shí)現(xiàn))漠畜。
在函數(shù)中使用空白行(有節(jié)制的)來(lái)表明邏輯部分币他。
import 不同的模塊應(yīng)該獨(dú)立一行
import 語(yǔ)句應(yīng)該總是放在文件的頂部,在模塊注釋和文檔字符串之下憔狞,在模塊全局變量和常量之前蝴悉。
import 語(yǔ)句分組順序如下:
導(dǎo)入標(biāo)準(zhǔn)庫(kù)模塊
導(dǎo)入相關(guān)第三方庫(kù)模塊
導(dǎo)入當(dāng)前應(yīng)用程序 / 庫(kù)模塊
每組之間應(yīng)該用空行分開(kāi)。
然后用 _all_ 聲明本文件內(nèi)的模塊瘾敢。
絕對(duì)導(dǎo)入是推薦的拍冠,它們通常是更可讀的,并且在錯(cuò)誤的包系統(tǒng)配置(如一個(gè)目錄包含一個(gè)以 os.path 結(jié)尾的包)下有良好的行為傾向(至少有更清晰的錯(cuò)誤消息)
import mypkg.sibling
from mypkg import sibling
from mypkg.sibling import example
相對(duì)于絕對(duì)導(dǎo)入簇抵,相對(duì)導(dǎo)入是個(gè)可選替代庆杜,特別是處理復(fù)雜的包結(jié)構(gòu)時(shí),絕對(duì)導(dǎo)入會(huì)有不必要的冗余:
from . import sibling
from .sibling import example
標(biāo)準(zhǔn)庫(kù)代碼應(yīng)該避免復(fù)雜的包結(jié)構(gòu)碟摆,并且永遠(yuǎn)使用絕對(duì)導(dǎo)入晃财。
應(yīng)該避免通配符導(dǎo)入(from import *),這會(huì)使名稱空間里存在的名稱變得不清晰焦履,迷惑讀者和自動(dòng)化工具拓劝。
字符串引號(hào)
單引號(hào)字符串和雙引號(hào)字符串是相同的雏逾。
一個(gè)字符串同時(shí)包含單引號(hào)和雙引號(hào)字符時(shí)嘉裤,用另外一種來(lái)包裹字符串,而不是使用反斜杠來(lái)轉(zhuǎn)義栖博,以提高可讀性屑宠。
表達(dá)式和語(yǔ)句中的空格
避免在下列情況中使用多余的空格:
與括號(hào)保持緊湊(小括號(hào)、中括號(hào)仇让、大括號(hào))
spam(ham[1], {eggs: 2})
與后面的逗號(hào)典奉、分號(hào)或冒號(hào)保持緊湊
if x == 4: print x, y; x, y = y, x
切片內(nèi)的冒號(hào)就像二元操作符一樣躺翻,任意一側(cè)應(yīng)該被等同對(duì)待(把它當(dāng)做一個(gè)極低優(yōu)先級(jí)的操作)。在一個(gè)可擴(kuò)展的切片中卫玖,冒號(hào)兩側(cè)必須有相同的空格數(shù)量公你。
ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3], ham[1:9:]
ham[lower:upper], ham[lower:upper:], ham[lower::step]
ham[lower+offset : upper+offset]
ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)]
ham[lower + offset : upper + offset]
函數(shù)名與其后參數(shù)列表的左括號(hào)應(yīng)該保持緊湊
spam(1)
與切片或索引的左括號(hào)保持緊湊
dct['key'] = lst[index]
在賦值操作符(或其它)的兩側(cè)保持多余一個(gè)的空格
x = 1
y = 2
long_variable = 3
總是在這些二元操作符的兩側(cè)加入一個(gè)空格:賦值(=),增量賦值(+=假瞬,-=陕靠,...),比較(==脱茉,<剪芥,>,!=琴许,<>税肪,<=,>=榜田,in益兄,not in,is箭券,is not)偏塞,布爾運(yùn)算(and,or邦鲫,not)灸叼。
在不同優(yōu)先級(jí)之間,考慮在更低優(yōu)先級(jí)的操作符兩側(cè)插入空格庆捺。用你自己的判斷力古今;但不要使用超過(guò)一個(gè)空格,并且在二元操作符的兩側(cè)有相同的空格數(shù)滔以。
i = i + 1
submitted += 1
x = x*2 - 1
hypot2 = x*x + y*y
c = (a+b) * (a-b)
不要在關(guān)鍵值參數(shù)或默認(rèn)值參數(shù)的等號(hào)兩邊加入空格捉腥。
def complex(real, imag=0.0):
return magic(r=real, i=imag)
帶注釋的函數(shù)定義中的等號(hào)兩側(cè)要各插入空格。此外你画,在冒號(hào)后用一個(gè)單獨(dú)的空格抵碟,也要在表明函數(shù)返回值類(lèi)型的 -> 左右各插入一個(gè)空格。
def munge(input: AnyStr):
def munge(sep: AnyStr = None):
def munge() -> AnyStr:
def munge(input: AnyStr, sep: AnyStr = None, limit=1000):
打消使用復(fù)合語(yǔ)句(多條語(yǔ)句在同一行)的念頭坏匪。
if foo == 'blah':
do_blah_thing()
do_one()
do_two()
do_three()
有時(shí)候把 if/for/while 和一個(gè)小的主體放在同一行也是可行的拟逮,千萬(wàn)不要在有多條語(yǔ)句的情況下這樣做。此外适滓,還要避免折疊敦迄,例如長(zhǎng)行。
注釋
注釋總是隨著代碼的變更而更新。
注釋?xiě)?yīng)該是完整的句子罚屋。如果注釋是一個(gè)短語(yǔ)或語(yǔ)句苦囱,第一個(gè)單詞應(yīng)該大寫(xiě),除非是一個(gè)開(kāi)頭是小寫(xiě)的標(biāo)識(shí)符(從不改變標(biāo)識(shí)符的大小寫(xiě))脾猛。
塊注釋通常用來(lái)說(shuō)明跟隨在其后的代碼撕彤,應(yīng)該與那些代碼有相同的縮進(jìn)層次。塊注釋每一行以#起頭猛拴,并且#后要跟一個(gè)空格(除非是注釋內(nèi)的縮進(jìn)文本)喉刘。
一個(gè)行內(nèi)注釋與語(yǔ)句在同一行。行內(nèi)注釋?xiě)?yīng)該至少與語(yǔ)句相隔兩個(gè)空格漆弄。以#打頭睦裳,#后接一個(gè)空格。
文檔字符串:為所有的公共模塊撼唾、函數(shù)廉邑、類(lèi)和方法編寫(xiě)文檔字符串。對(duì)于非公共的方法倒谷,文檔字符串是不必要的蛛蒙,但是也應(yīng)該有注釋來(lái)說(shuō)明代碼是干什么的。這個(gè)注釋?xiě)?yīng)該放在方法聲明的下面渤愁。
版本注記
如果必須要 Subversion牵祟,CVS 或 RCS 標(biāo)記在你的源文件里,像這樣做:
__version__ = "$Revision$"
# $Source$
命名約定
API 里對(duì)用戶可見(jiàn)的公共部分應(yīng)該遵循約定抖格,反映的是使用而不是實(shí)現(xiàn)诺苹。
永遠(yuǎn)不要使用單個(gè)字符l(小寫(xiě)字母 el),O(大寫(xiě)字母 oh)雹拄,或I(大寫(xiě)字母 eye)作為變量名收奔。在一些字體中,這些字符是無(wú)法和數(shù)字1和0區(qū)分開(kāi)的滓玖。試圖使用l時(shí)用L代替坪哄。
模塊名應(yīng)該短,且全小寫(xiě)势篡。如果能改善可讀性翩肌,可以使用下劃線。Python 的包名也應(yīng)該短禁悠,全部小寫(xiě)念祭,但是不推薦使用下劃線。
類(lèi)名通常使用 CapWords 約定绷蹲。注意和內(nèi)建名稱的區(qū)分開(kāi):大多數(shù)內(nèi)建名稱是一個(gè)單獨(dú)的單詞(或兩個(gè)單詞一起)棒卷,CapWords 約定只被用在異常名和內(nèi)建常量上顾孽。
應(yīng)該用Error作為你的異常名的后綴(異常實(shí)際上是一個(gè)錯(cuò)誤)祝钢。
若被設(shè)計(jì)的模塊可以通過(guò)from M import *來(lái)使用比规,它應(yīng)該使用all機(jī)制來(lái)表明那些可以可導(dǎo)出的全局變量,或者使用下劃線前綴的全局變量表明其是模塊私有的拦英。
函數(shù)名應(yīng)該是小寫(xiě)的蜒什,有必要的話用下劃線來(lái)分隔單詞提高可讀性。
總是使用 self 作為實(shí)例方法的第一個(gè)參數(shù)疤估≡殖#總是使用 cls 作為類(lèi)方法的第一個(gè)參數(shù)。
用函數(shù)名的命名規(guī)則:全部小寫(xiě)铃拇,用下劃線分隔單詞提高可讀性钞瀑。用一個(gè)且有一個(gè)前導(dǎo)的下劃線來(lái)表明非公有的方法和實(shí)例變量。為了避免與子類(lèi)變量或方法的命名沖突慷荔,用兩個(gè)前導(dǎo)下劃線來(lái)調(diào)用 Python 的命名改編規(guī)則雕什。
常量通常是模塊級(jí)的定義,全部大寫(xiě)显晶,單詞之間以下劃線分隔贷岸。例如MAX_OVERFLOW和TOTAL。
總是決定一個(gè)類(lèi)的方法和變量(屬性)是應(yīng)該公有還是非公有磷雇。如果有疑問(wèn)偿警,選擇非公有;相比把共有屬性變非公有唯笙,非公有屬性變公有會(huì)容易得多螟蒸。
公有屬性是你期望給那些與你的類(lèi)無(wú)關(guān)的客戶端使用的桥狡,你應(yīng)該保證不會(huì)出現(xiàn)不向后兼容的改變盆均。非公有的屬性是你不打算給其它第三方使用的欢搜;你不需要保證非公有的屬性不會(huì)改變甚至被移除也是可以的介劫。
另一種屬性的分類(lèi)是“子類(lèi) API”的一部分(通常在其它語(yǔ)言里叫做“Protected”)祟剔。一些類(lèi)被設(shè)計(jì)成被繼承的搓彻,要么擴(kuò)展要么修改類(lèi)的某方面行為空扎。設(shè)計(jì)這樣一個(gè)類(lèi)的時(shí)候浅缸,務(wù)必做出明確的決定枉疼,哪些是公有的皮假,其將會(huì)成為子類(lèi) API 的一部分,哪些僅僅是用于你的基類(lèi)的骂维。
公共和內(nèi)部接口
保證所有公有接口的向后兼容性惹资。
文檔化的接口考慮公有,除非文檔明確的說(shuō)明它們是暫時(shí)的航闺,或者內(nèi)部接口不保證其的向后兼容性褪测。所有的非文檔化的應(yīng)該被假設(shè)為非公開(kāi)的猴誊。
為了更好的支持內(nèi)省,模塊應(yīng)該用 _all_ 屬性來(lái)明確規(guī)定公有 API 的名字侮措。設(shè)置 _all_ 為空 list 表明模塊沒(méi)有公有 API懈叹。
被認(rèn)為是內(nèi)部的接口,其包含的任何名稱空間(包分扎、模塊或類(lèi))也被認(rèn)為是內(nèi)部的澄成。
迭代器、生成器畏吓、裝飾器
迭代器
_iter_()墨状,返回迭代器對(duì)象自身。這用在 for 和 in 語(yǔ)句中菲饼。
_next_()肾砂,返回迭代器的下一個(gè)值。如果沒(méi)有下一個(gè)值可以返回宏悦,那么應(yīng)該拋出 StopIteration 異常镐确。
class Counter(object):
def __init__(self, low, high):
self.current = low
self.high = high
def __iter__(self):
return self
def __next__(self):
#返回下一個(gè)值直到當(dāng)前值大于 high
if self.current > self.high:
raise StopIteration
else:
self.current += 1
return self.current - 1
>>> c = Counter(5,10)
>>> for i in c:
... print(i, end=' ')
迭代器只能被使用一次。這意味著迭代器一旦拋出 StopIteration肛根,它會(huì)持續(xù)拋出相同的異常辫塌。
>>> c = Counter(5,6)
>>> next(c)
5
>>> next(c)
6
>>> next(c)
>>> iterator = iter(c)
>>> while True:
... try:
... x = iterator.__next__()
... print(x, end=' ')
... except StopIteration as e:
... break
生成器
生成器是更簡(jiǎn)單的創(chuàng)建迭代器的方法,這通過(guò)在函數(shù)中使用 yield 關(guān)鍵字完成:
>>> def my_generator():
... print("Inside my generator")
... yield 'a'
... yield 'b'
... yield 'c'
...
>>> my_generator()
我們能在 for 循環(huán)中使用它派哲,就像我們使用任何其它迭代器一樣臼氨。
>>> for char in my_generator():
... print(char)
使用一個(gè)生成器函數(shù)完成與 Counter 類(lèi)相同的功能,并且把它用在 for 循環(huán)中芭届。
>>> def counter_generator(low, high):
... while low <= high:
... yield low
... low += 1
...
>>> for i in counter_generator(5,10):
... print(i, end=' ')
在 While 循環(huán)中储矩,每當(dāng)執(zhí)行到 yield 語(yǔ)句時(shí),返回變量 low 的值并且生成器狀態(tài)轉(zhuǎn)為掛起褂乍。在下一次調(diào)用生成器時(shí)持隧,生成器從之前凍結(jié)的地方恢復(fù)執(zhí)行然后變量 low 的值增一。生成器繼續(xù) while 循環(huán)并且再次來(lái)到 yield 語(yǔ)句...
當(dāng)你調(diào)用生成器函數(shù)時(shí)它返回一個(gè)生成器對(duì)象逃片。如果你把這個(gè)對(duì)象傳入 dir() 函數(shù)屡拨,你會(huì)在返回的結(jié)果中找到 _iter_ 和 _next_ 兩個(gè)方法名。
通常使用生成器進(jìn)行惰性求值褥实。這樣使用生成器是處理大數(shù)據(jù)的好方法呀狼。如果你不想在內(nèi)存中加載所有數(shù)據(jù),你可以使用生成器损离,一次只傳遞給你一部分?jǐn)?shù)據(jù)哥艇。
os.path.walk() 函數(shù)是最典型的這樣的例子,它使用一個(gè)回調(diào)函數(shù)和當(dāng)前的 os.walk 生成器僻澎。使用生成器實(shí)現(xiàn)節(jié)約內(nèi)存貌踏。
可以使用生成器產(chǎn)生無(wú)限多的值十饥。
>>> def infinite_generator(start=0):
... while True:
... yield start
... start += 1
...
>>> for num in infinite_generator(4):
... print(num, end=' ')
... if num > 20:
... break
如果我們回到 my_generator() 這個(gè)例子,我們會(huì)發(fā)現(xiàn)生成器的一個(gè)特點(diǎn):它們是不可重復(fù)使用的祖乳。
>>> g = my_generator()
>>> for c in g:
... print(c)
生成器表達(dá)式
生成器表達(dá)式是列表推導(dǎo)式和生成器的一個(gè)高性能逗堵,內(nèi)存使用效率高的推廣。
嘗試對(duì) 1 到 9 的所有數(shù)字進(jìn)行平方求和凡资。
>>> sum([x*x for x in range(1,10)])
這個(gè)例子實(shí)際上首先在內(nèi)存中創(chuàng)建了一個(gè)平方數(shù)值的列表砸捏,然后遍歷這個(gè)列表谬运,最終求和后釋放內(nèi)存隙赁。
>>> sum(x*x for x in range(1,10))
生成器表達(dá)式的語(yǔ)法要求其總是直接在在一對(duì)括號(hào)內(nèi),并且不能在兩邊有逗號(hào)梆暖。
>>> sum(x*x for x in range(1,10))
>>> g = (x*x for x in range(1,10))
>>> g
>>> jobtext = 'anacron'
>>> all = (line for line in open('/etc/crontab', 'r') )
>>> job = ( line for line in all if line.find(jobtext) != -1)
>>> text = next(job)
>>> text
'25 6\t* * *\troot\ttest -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )\n'
>>> text = next(job)
>>> text
'47 6\t* * 7\troot\ttest -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )\n'
>>> text = next(job)
>>> text
'52 6\t1 * *\troot\ttest -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )\n'
閉包
由另外一個(gè)函數(shù)返回的函數(shù)伞访。我們使用閉包去除重復(fù)代碼。在下面的例子中我們創(chuàng)建了一個(gè)簡(jiǎn)單的閉包來(lái)對(duì)數(shù)字求和轰驳。
>>> def add_number(num):
... def adder(number):
... #adder 是一個(gè)閉包
... return num + number
... return adder
>>> a_10 = add_number(10)
>>> a_10(21)
>>> a_10(34)
>>> a_5 = add_number(5)
>>> a_5(3)
裝飾器
用來(lái)給一些對(duì)象動(dòng)態(tài)的添加一些新的行為厚掷,我們使用過(guò)的閉包也是這樣的。
>>> def my_decorator(func):
... def wrapper(*args, **kwargs):
... print("Before call")
... result = func(*args, **kwargs)
... print("After call")
... return result
... return wrapper
...
>>> @my_decorator
... def add(a, b):
... #我們的求和函數(shù)
... return a + b
...
>>> add(1, 3)
Virtualenv
$ sudo apt-get update
$ sudo apt-get install python3-pip
$ sudo pip3 install virtualenv
$ cd /home/shiyanlou
$ mkdir virtual
$ cd virtual
$ virtualenv virt1
$ source virt1/bin/activate
(virt1)shiyanlou:~/$
關(guān)閉虛擬環(huán)境
(virt1)$ deactivate
測(cè)試
測(cè)試范圍
如果可能的話级解,代碼庫(kù)中的所有代碼都要測(cè)試冒黑。有一個(gè)堅(jiān)實(shí)可靠的測(cè)試套件,你可以做出大的改動(dòng)勤哗,并確信外部可見(jiàn)行為保持不變抡爹。
單元測(cè)試
又稱為模塊測(cè)試, 是針對(duì)程序模塊(軟件設(shè)計(jì)的最小單位)來(lái)進(jìn)行正確性檢驗(yàn)的測(cè)試工作。程序單元是應(yīng)用的最小可測(cè)試部件芒划。在過(guò)程化編程中冬竟,一個(gè)單元就是單個(gè)程序、函數(shù)民逼、過(guò)程等泵殴;對(duì)于面向?qū)ο缶幊蹋钚卧褪欠椒ㄆ床裕ɑ?lèi)(超類(lèi))笑诅、抽象類(lèi)、或者派生類(lèi)(子類(lèi))中的方法疮鲫。
階乘計(jì)算程序
import sys
def fact(n):
"""
階乘函數(shù)
:arg n: 數(shù)字
:returns: n 的階乘
"""
if n == 0:
return 1
return n * fact(n -1)
def div(n):
"""
只是做除法
"""
res = 10 / n
return res
def main(n):
res = fact(n)
print(res)
if __name__ == '__main__':
if len(sys.argv) > 1:
main(int(sys.argv[1]))
fact(n) 這個(gè)函數(shù)執(zhí)行所有的計(jì)算吆你,所以我們至少應(yīng)該測(cè)試這個(gè)函數(shù)。
import unittest
from factorial import fact
class TestFactorial(unittest.TestCase):
"""
我們的基本測(cè)試類(lèi)
"""
def test_fact(self):
"""
實(shí)際測(cè)試
任何以 `test_` 開(kāi)頭的方法都被視作測(cè)試用例
"""
res = fact(5)
self.assertEqual(res, 120)
if __name__ == '__main__':
unittest.main()
各類(lèi) assert 語(yǔ)句
異常測(cè)試
如果我們?cè)?factorial.py 中調(diào)用 div(0)棚点,我們能看到異常被拋出早处。
import unittest
from factorial import fact, div
class TestFactorial(unittest.TestCase):
"""
我們的基本測(cè)試類(lèi)
"""
def test_fact(self):
"""
實(shí)際測(cè)試
任何以 `test_` 開(kāi)頭的方法都被視作測(cè)試用例
"""
res = fact(5)
self.assertEqual(res, 120)
def test_error(self):
"""
測(cè)試由運(yùn)行時(shí)錯(cuò)誤引發(fā)的異常
"""
self.assertRaises(ZeroDivisionError, div, 0)
if __name__ == '__main__':
unittest.main()
mounttab.py
mounttab.py 中只有一個(gè) mount_details() 函數(shù),函數(shù)分析并打印掛載詳細(xì)信息瘫析。
import os
def mount_details():
"""
打印掛載詳細(xì)信息
"""
if os.path.exists('/proc/mounts'):
fd = open('/proc/mounts')
for line in fd:
line = line.strip()
words = line.split()
print('{} on {} type {}'.format(words[0],words[1],words[2]), end=' ')
if len(words) > 5:
print('({})'.format(' '.join(words[3:-2])))
else:
print()
fd.close()
if __name__ == '__main__':
mount_details()
現(xiàn)在我們?cè)?mounttab2.py 中重構(gòu)了上面的代碼并且有一個(gè)我們能容易的測(cè)試的新函數(shù) parse_mounts()砌梆。
import os
def parse_mounts():
"""
分析 /proc/mounts 并 返回元祖的列表
"""
result = []
if os.path.exists('/proc/mounts'):
fd = open('/proc/mounts')
for line in fd:
line = line.strip()
words = line.split()
if len(words) > 5:
res = (words[0],words[1],words[2],'({})'.format(' '.join(words[3:-2])))
else:
res = (words[0],words[1],words[2])
result.append(res)
fd.close()
return result
def mount_details():
"""
打印掛載詳細(xì)信息
"""
result = parse_mounts()
for line in result:
if len(line) == 4:
print('{} on {} type {} {}'.format(*line))
else:
print('{} on {} type {}'.format(*line))
if __name__ == '__main__':
mount_details()
測(cè)試代碼默责,編寫(xiě) mounttest.py 文件:
#!/usr/bin/env python
import unittest
from mounttab2 import parse_mounts
class TestMount(unittest.TestCase):
"""
我們的基本測(cè)試類(lèi)
"""
def test_parsemount(self):
"""
實(shí)際測(cè)試
任何以 `test_` 開(kāi)頭的方法都被視作測(cè)試用例
"""
result = parse_mounts()
self.assertIsInstance(result, list)
self.assertIsInstance(result[0], tuple)
def test_rootext4(self):
"""
測(cè)試找出根文件系統(tǒng)
"""
result = parse_mounts()
for line in result:
if line[1] == '/' and line[2] != 'rootfs':
self.assertEqual(line[2], 'ext4')
if __name__ == '__main__':
unittest.main()
測(cè)試覆蓋率
測(cè)試覆蓋率是找到代碼庫(kù)未經(jīng)測(cè)試的部分的簡(jiǎn)單方法。它并不會(huì)告訴你的測(cè)試好不好咸包。
$ sudo pip3 install coverage
$ coverage3 run mounttest.py
我們還可以使用下面的命令以 HTML 文件的形式輸出覆蓋率結(jié)果桃序,然后在瀏覽器中查看它。
$ coverage3 html
項(xiàng)目結(jié)構(gòu)
創(chuàng)建 Python 項(xiàng)目
實(shí)驗(yàn)項(xiàng)目名為 factorial烂瘫,放到 /home/shiyanlou/factorial 目錄:
$ cd /home/shiyanlou
$ mkdir factorial
$ cd factorial/
將要?jiǎng)?chuàng)建的 Python 模塊取名為 myfact媒熊,因此我們下一步創(chuàng)建 myfact 目錄。
$ mkdir myfact
$ cd myfact/
主代碼將在 fact.py 文件里面坟比。
"myfact module"
def factorial(num):
"""
返回給定數(shù)字的階乘值
:arg num: 我們將計(jì)算其階乘的整數(shù)值
:return: 階乘值芦鳍,若傳遞的參數(shù)為負(fù)數(shù),則為 -1
"""
if num >= 0:
if num == 0:
return 1
return num * factorial(num -1)
else:
return -1
還有模塊的 _init_.py 文件葛账,內(nèi)容如下:
from fact import factorial
__all__ = [factorial, ]
在 factorial 目錄下添加了一個(gè) README.rst 文件柠衅。
MANIFEST.in
寫(xiě)一個(gè) /home/shiyanlou/factorial/MANIFEST.in 文件,它用來(lái)在使用 sdist 命令的時(shí)候找出將成為項(xiàng)目源代碼壓縮包一部分的所有文件籍琳。
include *.py
include README.rst
如果你想要排除某些文件菲宴,你可以在這個(gè)文件中使用 exclude 語(yǔ)句。
安裝 python-setuptools 包
$ sudo pip3 install setuptools
setup.py
寫(xiě)一個(gè) /home/shiyanlou/factorial/setup.py趋急,用來(lái)創(chuàng)建源代碼壓縮包或安裝軟件喝峦。
#!/usr/bin/env python3
"""Factorial project"""
from setuptools import find_packages, setup
setup(name = 'factorial', # 注意這里的name不要使用factorial相關(guān)的名字,因?yàn)闀?huì)重復(fù)呜达,需要另外取一個(gè)不會(huì)與其他人重復(fù)的名字
version = '0.1',
description = "Factorial module.",
long_description = "A test module for our book.",
platforms = ["Linux"],
author="ShiYanLou",
author_email="support@shiyanlou.com",
url="/courses/596",
license = "MIT",
packages=find_packages()
)
name 是項(xiàng)目名稱谣蠢,version 是發(fā)布版本,description 和 long_description_ 分別是項(xiàng)目介紹闻丑,項(xiàng)目長(zhǎng)描述漩怎。platforms 是此模塊的支持平臺(tái)列表。_find_packages() 是一個(gè)能在你源目錄下找到所有模塊的特殊函數(shù)
創(chuàng)建一個(gè)源文件發(fā)布版本嗦嗡,執(zhí)行以下命令勋锤。
python3 setup.py sdist
能在 dist 目錄下看到一個(gè) tar 壓縮包。
ls dist/
執(zhí)行下面的命令從源代碼安裝侥祭。
$ sudo python3 setup.py install
Python Package Index (PyPI)
PyPI 的測(cè)試服務(wù)器 https://testpypi.python.org/pypi叁执。
在這個(gè)鏈接注冊(cè)賬號(hào)。你會(huì)收到帶有鏈接的郵件矮冬,點(diǎn)擊這個(gè)鏈接確認(rèn)你的注冊(cè)谈宛。
創(chuàng)建 ~/.pypirc 文件,存放你的賬號(hào)詳細(xì)信息胎署,其內(nèi)容格式如下:
[distutils]
index-servers = pypi
testpypi
[pypi]
repository: https://upload.pypi.org/legacy/
username: <username>
password: <password>
[testpypi]
repository:https://test.pypi.org/legacy/
username: <username>
password: <password>
替換 <username> 和 <password> 為您新創(chuàng)建的帳戶的詳細(xì)信息吆录。在這里,由于我們是到 testpypi的網(wǎng)頁(yè)上去注冊(cè)賬號(hào)琼牧,即將相應(yīng)的服務(wù)上傳到 testpypi恢筝,所以在這里哀卫,你只需修改[testpypi]的用戶名和密碼
記得在 setup.py 中更改項(xiàng)目的名稱為其它的名字來(lái)測(cè)試下面的指令,在接下來(lái)的命令中我將項(xiàng)目名稱修改為 factorial2撬槽,為了不重復(fù)此改,大家需要自行修改至其它名稱(不要使用 factorial 和 factorial2,因?yàn)橐呀?jīng)被使用了)侄柔。
將我們的項(xiàng)目到 TestPyPI 服務(wù)共啃。這通過(guò) twine 命令完成。
使用 -r 把它指向測(cè)試服務(wù)器暂题。
$ sudo pip3 install twine
$ twine upload dist/* -r testpypi
也可以使用下面的命令上傳到 PyPI 服務(wù)上移剪,但這里需要注意,在 ~/.pypirc 里面敢靡,你需要到 https://pypi.python.org頁(yè)面挂滓,按照上面的步驟去注冊(cè)一個(gè)賬號(hào)苦银,然后到~/.pypirc 的 [pypi] 下填寫(xiě)相應(yīng)的用戶名和密碼啸胧。testpypi 和 pypi 的賬號(hào)密碼并不通用。
$ twine upload dist/* -r pypi
Flask 介紹
Flask 是一個(gè) web 框架幔虏。也就是說(shuō) Flask 為你提供工具纺念,庫(kù)和技術(shù)來(lái)允許你構(gòu)建一個(gè) web 應(yīng)用程序。這個(gè) web 應(yīng)用程序可以是一些 web 頁(yè)面想括、博客陷谱、wiki、基于 web 的日歷應(yīng)用或商業(yè)網(wǎng)站瑟蜈。
Flask 屬于微框架(micro-framework)這一類(lèi)別烟逊,微架構(gòu)通常是很小的不依賴于外部庫(kù)的框架。這既有優(yōu)點(diǎn)也有缺點(diǎn)铺根,優(yōu)點(diǎn)是框架很輕量宪躯,更新時(shí)依賴少,并且專(zhuān)注安全方面的 bug位迂,缺點(diǎn)是访雪,你不得不自己做更多的工作,或通過(guò)添加插件增加自己的依賴列表掂林。
Web 服務(wù)器網(wǎng)關(guān)接口(Python Web Server Gateway Interface臣缀,縮寫(xiě)為 WSGI)是為Python語(yǔ)言定義的Web 服務(wù)器和Web 應(yīng)用程序或框架之間的一種簡(jiǎn)單而通用的接口。自從 WSGI 被開(kāi)發(fā)出來(lái)以后泻帮,許多其它語(yǔ)言中也出現(xiàn)了類(lèi)似接口精置。
模板引擎:使用模板你可以設(shè)置你的頁(yè)面的基本布局,并提及哪個(gè)元素將發(fā)生變化锣杂。這種方式可以定義您的網(wǎng)頁(yè)頭部并在您的網(wǎng)站的所有頁(yè)面使它保持一致脂倦,如果你需要改變網(wǎng)頁(yè)頭部饲常,你只需要更新一個(gè)地方。
"Hello World" 應(yīng)用
$ sudo pip3 install flask
$ cd /home/shiyanlou
$ mkdir -p hello_flask/{templates,static}
templates 文件夾是存放模板的地方狼讨,static 文件夾存放 web 應(yīng)用所需的靜態(tài)文件(images, css, javascript)贝淤。
$ cd hello_flask
$ vim hello_flask.py
hello_flask.py 文件里編寫(xiě)如下代碼:
#!/usr/bin/env python3
import flask
# Create the application.
APP = flask.Flask(__name__)
@APP.route('/')
def index():
""" 顯示可在 '/' 訪問(wèn)的 index 頁(yè)面
"""
return flask.render_template('index.html')
if __name__ == '__main__':
APP.debug=True
APP.run()
創(chuàng)建模板文件 index.html
$ vim templates/index.html
index.html 文件內(nèi)容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Hello world!</title>
<link
type="text/css"
rel="stylesheet"
href="{{ url_for('static',
filename='hello.css')}}"
/>
</head>
<body>
It works!
</body>
</html>
運(yùn)行 flask 應(yīng)用程序
$ python3 hello_flask.py
Flask 中使用參數(shù)
更新 hello_flask.py 文件。
在 hello_flask.py 文件中添加以下條目
@APP.route('/hello/<name>/')
def hello(name):
""" Displays the page greats who ever comes to visit it.
"""
return flask.render_template('hello.html', name=name)
創(chuàng)建下面這個(gè)模板 hello.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Hello</title>
<link
type="text/css"
rel="stylesheet"
href="{{ url_for('static',
filename='hello.css')}}"
/>
</head>
<body>
Hello {{name}}
</body>
</html>
運(yùn)行 flask 應(yīng)用
$ python3 hello_flask.py
額外工作
對(duì)于每一個(gè)頁(yè)面我們都創(chuàng)建了一個(gè)模板政供,其實(shí)這是不好的做法播聪,我們應(yīng)該做的是創(chuàng)建一個(gè)主模板并且在每個(gè)頁(yè)面使用它。
創(chuàng)建模板文件 master.html布隔。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>{% block title %}{% endblock %} - Hello Flask!</title>
<link
type="text/css"
rel="stylesheet"
href="{{ url_for('static',
filename='hello.css')}}"
/>
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>
調(diào)整模板 index.html离陶。
在模板 index.html 中,我們聲明這個(gè)模板擴(kuò)展自 master.html 模板衅檀,然后我們定義了內(nèi)容來(lái)放在這兩個(gè)部分中(blocks)招刨。在第一個(gè) block title 中,我們放置了 Home 單詞哀军,在第二個(gè) block body 中我們定義了我們想要在頁(yè)面的 body 中有的東西沉眶。