2018-01-16 Python學(xué)習(xí)第四天

2.相等運(yùn)算符

3.is:同一性運(yùn)算符

#避免將is運(yùn)算符用于比較類似數(shù)值和字符串這類不可變值归薛,由于Python內(nèi)部操作這些對(duì)象的方式的原因吱晒,使用is運(yùn)算符的結(jié)果是不可預(yù)測(cè)的履磨。

4.in: 成員資格運(yùn)算符

【代碼】

name = input('what

is your name?')

if 's' in name:


print('Your name contains the letter "s".')

else:


print ('Your name does not contain the letter

"s".')

【結(jié)果】

what is your name?nihao

Your name does not contain the letter "s".

5.字符串和序列比較

【代碼】

print("alpha"< "beta")

print(

'FnOrD'.lower())

print(

'FnOrD'.upper())

print([

1,2] < [2,1]) #參與比較的不是字符而是元素的其他類型print([2,[1,4]] <[2,[1,5]]) #如果一個(gè)序列中包含其他序列元素仙辟,比較規(guī)則同樣適用于序列元素

【結(jié)果】

True

fnord

FNORD

True

True

6.布爾運(yùn)算符

【代碼】

#有時(shí)想要檢查一個(gè)以上的條件,可以這樣做:number = int(input('Enter

a number between 1 and 10:'))

if number <= 10:


if number

>=1:


print('Great!')


else:


print('Wrong!')

else:


print('Wrong')

#下面使用布爾思想進(jìn)行優(yōu)化if number <= 10 and number >= 1:


print('Great')

else:


print('Wrong')

#and運(yùn)算符就是所謂的布爾運(yùn)算符允懂。它連接兩個(gè)布爾值厕怜,并且在兩者都為真時(shí)返回真,否則返回假。與它同類的還有兩個(gè)運(yùn)算符粥航,or和not琅捏。

#

布爾運(yùn)算符有個(gè)有趣的特性:只有在需要求值時(shí)才進(jìn)行求值。例如递雀,表達(dá)式x and y需要兩個(gè)變量都為真時(shí)才為真柄延,如果x為假,表達(dá)之會(huì)立刻返回false映之,不管y的值拦焚。這類短路邏輯可以用來實(shí)現(xiàn)C和Java中所謂的三元運(yùn)算符。

【結(jié)果】

Enter a number between 1 and 10:111

Wrong

Wrong

5.4.7 斷言

【代碼】

#if語句有個(gè)非常有用的“近親”杠输,它的工作方式像下面:

#if not condition

#?? crash program

#

就是因?yàn)槠渌绦蛟谕硇r(shí)候崩潰赎败,比如在錯(cuò)誤條件出現(xiàn)時(shí)直接讓它崩潰。語句中使用的關(guān)鍵字是assertage = 10

assert 0 <

age < 100

age = -1

assert 0 <

age < 100

【結(jié)果】

Traceback (most recent call last):

? File"D:/python_file/20180113/test.py", line 8, in

??? assert 0 < age < 100

AssertionError

【代碼】

#如果需要確保程序中的某個(gè)條件一定為真才讓程序正常工作的話蠢甲,assert語句就有用了僵刮,它可以在程序中置入檢查點(diǎn),條件后添加字符串鹦牛,用于解釋斷言age = -1

assert 0 <

age < 100 ,'The

age must be realistic'

【結(jié)果】

Traceback (most recent call last):

? File"D:/python_file/20180113/test.py", line 3, in

??? assert 0 < age < 100,'The age must be realistic'

AssertionError: The age must be realistic

5.5 循環(huán)

但是怎樣才能重復(fù)執(zhí)行多次呢搞糕?比如,寫一個(gè)每月提醒付房租的程序曼追,但是不使用循環(huán)窍仰,需要這樣寫:

發(fā)郵件

等一個(gè)月

發(fā)郵件

等一個(gè)月

(繼續(xù)下去……)

但是如果想讓程序繼續(xù)執(zhí)行,直到認(rèn)為停止它呢礼殊?

5.5.1 while循環(huán)

【代碼】

x = 1

while x <= 100:


print(x)

??? x+=

1

【結(jié)果】

不寫了吧

【代碼】

name = ''

while not name.strip(): #這回驹吮,連空格也逃脫不掉了

??? name = input('Please

enter your name:')

print('Hello,%s!'% name)

【結(jié)果】

不寫了吧

5.5.2 for循環(huán)

【代碼】

#while語句非常靈活,它可以用來在任何條件為真的情況下重復(fù)執(zhí)行一個(gè)代碼塊晶伦。但是碟狞,有時(shí)還得量體裁衣。比如要為一個(gè)集合(序列或其他可迭代對(duì)象)的每個(gè)元素都執(zhí)行一個(gè)代碼塊words = ['this','is','an','ex','parrot']

for word in words:


print(word)

#range函數(shù)的工作方式類似于分片婚陪,它包含下限族沃,但不包含上限。

#range()

函數(shù)返回的是一個(gè)可迭代對(duì)象(類型是對(duì)象)泌参,而不是列表類型脆淹, 所以打印的時(shí)候不會(huì)打印列表。

# #list()

函數(shù)是對(duì)象迭代器沽一,把對(duì)象轉(zhuǎn)為一個(gè)列表盖溺。返回的變量類型為列表。a = range(0,10) #下限為0锯玛,上限為9a = list(a)

print(a)

#xrange函數(shù)的循環(huán)行為類似于range函數(shù),區(qū)別在于range函數(shù)一次創(chuàng)建整個(gè)序列而xrange一次只創(chuàng)建一個(gè)數(shù)。當(dāng)需要迭代一個(gè)巨大的序列時(shí)攘残,xrange會(huì)更高效拙友,一般情況下不需要關(guān)注它。

【結(jié)果】

this

is

an

ex

parrot

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

5.5.3 循環(huán)遍歷字典元素

【代碼】

#一個(gè)簡單的for語句就能循環(huán)字典的所有鍵歼郭,就像處理序列一樣d = {'x':1,'y':2,'z':3}

for key in d:


print(key,'correspends to',d[key])

#for循環(huán)的一大好處就是可以使用序列解包

#

字典嚴(yán)肅的順序通常是沒有意義的遗契。迭代的時(shí)候,字典中的鍵和值都能保證被處理病曾,但是處理順序不確定牍蜂。如果處理順序很重要的話,可以把鍵保存在列表中泰涂。

【結(jié)果】

y correspends to 2

z correspends to 3

x correspends to 1

5.5.4 一些迭代工具

在Python中迭代序列時(shí)鲫竞,一些函數(shù)非常有用。有些函數(shù)位于itertools模塊中逼蒙,還有一些內(nèi)建函數(shù)也十分有用从绘。

[if !supportLists]1.? [endif]并行迭代

【代碼】

#程序可以同時(shí)迭代兩個(gè)序列。比如:names = ['anne','beth','george','damon']

ages = [

12,45,32,102]

#如果想要打印名字和對(duì)應(yīng)的年齡是牢,可以像下面這樣做:for i in range(len(names)):


print(names[i],'is',ages[i],'years

old')

print('---------------------------------------------')

z =

zip(names,ages) #python3中僵井,使用zip后,得到的是一個(gè)可迭代對(duì)象print(z)

for i in z:


print(i) #可以看出批什,打印出來的是一個(gè)元組print('---------------------------------------------')

#注:要重新獲得迭代對(duì)象,不能再使用上面一個(gè)z了社搅,以為上面的z已經(jīng)迭代到末尾了z = zip(names,ages) #python3中驻债,使用zip后,得到的是一個(gè)可迭代對(duì)象for i in z: #這里不嫩解包了罚渐?

??? print(i[0],'is',i[1],'years old')

【結(jié)果】

anne is 12 years old

beth is 45 years old

george is 32 years old

damon is 102 years old

---------------------------------------------

('anne', 12)

('beth', 45)

('george', 32)

('damon', 102)

---------------------------------------------

anne is 12 years old

beth is 45 years old

george is 32 years old

damon is 102 years old

【代碼】

#zip函數(shù)也可以用于任意多的序列却汉。關(guān)于它很重要的一點(diǎn)就是zip可以應(yīng)付不等長序列:當(dāng)最短的序列用完時(shí)停止z = zip(range(5),range(100000))

for i in z:


print(i)


#print(i[0],i[1])

【結(jié)果】

(0, 0)

(1, 1)

(2, 2)

(3, 3)

(4, 4)

[if !supportLists]2.? [endif]編號(hào)迭代

【代碼】

#有時(shí)候想要迭代序列中的對(duì)象,還想要獲取當(dāng)前對(duì)象的索引荷并。例如合砂,在一個(gè)字符串列表中替換所有包含'xxx'的子字符串。strings = ['hello,world!,xxx,yyy,zzz','dkdskldsklkl']

#strings 村莊

#string?

人家

#xxx????

要找的人for string in strings:#大框

??? if 'xxx' instring: #小框

??????? index = strings.index(string) #index相當(dāng)于門牌號(hào)

??????? strings[index] = '[censored]'

print(strings)

【結(jié)果】

['[censored]', 'dkdskldsklkl']

【同上源织,代碼】

#沒問題翩伪,但是在替換之前搜索給定的字符串似乎沒必要。如果不替換的話谈息,搜索還會(huì)返回錯(cuò)誤的索引缘屹,較好的版本如下index = 0

for string in strings:


if 'xxx' in string:

??????? strings[index] =

'[censored]'

??? index += 1

print(strings)

【結(jié)果】

['[censored]', 'dkdskldsklkl']

【同上,代碼】

#方法有點(diǎn)笨侠仇,不過可以接受轻姿。另一種方法是使用內(nèi)建的enumerate函數(shù):for index,string in enumerate(strings): #這樣的話犁珠,一戶人家和一戶人家的門牌號(hào)都有了

??? if 'xxx' instring:

??????? strings[index] =

'[censored]'

print(strings)

【結(jié)果】

['[censored]', 'dkdskldsklkl']

[if !supportLists]3.? [endif]翻轉(zhuǎn)和排序迭代

【代碼】

s = sorted([4,3,6,8,3])

print(s)

s2 =

sorted('Hello,

world!')

print(s2)

s3 =

list(reversed('Hello,

world!'))

print(s3)

#reversed函數(shù)和sorted函數(shù)作用相反,但是reversed函數(shù)還需要使用list函數(shù)把得到的對(duì)象解包互亮,sorted函數(shù)自帶解包功能犁享。

【結(jié)果】

[3, 3, 4, 6, 8]

[' ', '!', ',', 'H', 'd', 'e', 'l', 'l', 'l', 'o', 'o', 'r', 'w']

['!', 'd', 'l', 'r', 'o', 'w', ' ', ',', 'o', 'l', 'l', 'e', 'H']

5.5.5 跳出循環(huán)

一般來說,循環(huán)會(huì)一直執(zhí)行直到條件為假豹休,或者到序列元素用完時(shí)炊昆。但是有些時(shí)候可能會(huì)提前中斷一個(gè)循環(huán),進(jìn)行新的迭代威根。

[if !supportLists]1.? [endif]break

【代碼】

#結(jié)束(跳出)循環(huán)可以使用break語句凤巨。假設(shè)需要尋找100以內(nèi)的最大平方數(shù),那么程序可以從100往下迭代到0洛搀,當(dāng)找到一個(gè)平方數(shù)時(shí)就不需要繼續(xù)循環(huán)了敢茁。from math import sqrt

for n in range(99,0,-1): #range增加了第三個(gè)參數(shù):步長

??? root = sqrt(n)


if root

== int(root):


print(n)


break

【結(jié)果】

81

[if !supportLists]2.? [endif]continue

for x in seq:

??? if condition1:continue

??? if condition2:continue

??? if condition3:continue


??? do_something()

??? do_something_else()

??? do_another_thing()

??? etc()

很多時(shí)候,只要使用if語句就可以了姥卢;

for x in seq:

??? if not (condition1 orcondition2 or condition3):

?????? do_something()

?????? do_something_else()

?????? do_another_thing()

?????? etc()

盡管continue語句非常有用卷要,它卻不是最本質(zhì)的。應(yīng)該習(xí)慣使用break語句独榴,因?yàn)樵趙hile True語句中會(huì)經(jīng)常用到它僧叉。

[if !supportLists]3.? [endif]while True/break習(xí)語

【代碼1】

#Python中while和for循環(huán)非常靈活,但一旦使用while語句就會(huì)遇到一個(gè)需要更多功能的問題棺榔。word = 'dummy' #代碼有些丑瓶堕,在進(jìn)入循環(huán)體之前需要給word賦一個(gè)啞值。使用啞值就是工作沒有盡善盡美的標(biāo)志while word:

??? word =

input('please enter a word:')


#處理word

??? print('The word was',word)

【代碼2】

#解決啞值問題while True:

??? word =

input('please enter a word:')


if not word: break

??? #處理word

??? print('The word was',word)

#while True部分實(shí)現(xiàn)了一個(gè)永遠(yuǎn)不會(huì)自己停止的循環(huán)症歇。但在循環(huán)內(nèi)部的if語句中加入條件是可以的郎笆,在條件滿足時(shí)調(diào)用break語句,這樣就可以在循環(huán)體內(nèi)部的任何地方結(jié)束循環(huán)忘晤,而不僅僅在凱循環(huán)的開頭部分宛蚓。if/break語句自然地將循環(huán)分為兩部分:第1部分負(fù)責(zé)初始化,第2部分則在循環(huán)條件為真的情況下使用第1部分內(nèi)部初始化好的數(shù)據(jù)设塔。

5.5.6 循環(huán)中的else子句

broke_out = False

for x in seq:

??? do_something(x)

??? if condition(x):

?????? broke_out = True

?????? break

??? do_something_else(x)

if not broke_out:

??? print(“I didn’t break out!”)

更簡單的方式是在循環(huán)中增加一個(gè)else子句—它僅在沒有調(diào)用break時(shí)執(zhí)行凄吏。

【代碼】

from math import sqrt

for n in range(99,81,-1):

??? root = sqrt(n)


if root

== int(root):


print(n)


break

else: #for循環(huán)中的所有語句都執(zhí)行過的時(shí)候(沒有跳出循環(huán)),從這個(gè)地方開始執(zhí)行

??? print("Didn't find it!")

#跳出for循環(huán)的話闰蛔,從這個(gè)地方開始執(zhí)行

#

注:for和while循環(huán)中都可以使用continue痕钢、break語句和else子句

【結(jié)果】

Didn't find it!

5.6 列表推導(dǎo)式----輕量級(jí)循環(huán)

【代碼】

#列表推導(dǎo)式是利用其他列表創(chuàng)建新列表(類似于數(shù)學(xué)術(shù)語中的集合推導(dǎo)式)的一種方法。它的工作方式類似于for循環(huán)x = [x*x for x in range(10)]

x2 = [x*x

for x in range(10) if x % 3 == 0]

xy = [(x,y)

for x in range(3) for y in range(3)] #兩個(gè)for之間不需要加and

#

作為對(duì)比序六,下面的代碼使用兩個(gè)for語句創(chuàng)建了相同的列表:result = []

for x in range(3):


for y in range(3):

??????? result.append((x,y))

print(x)

print(x2)

print(xy)

print(result)

#也可以和if子句聯(lián)合使用任连,像以前一樣:girls = ['alice','bernice','clarice']

boys = [

'chris','arnold','bob']

print([b + '+' + g for g in girls for b in boys if b[0] == g[0]])

#注:使用普通的圓括號(hào)而不是方括號(hào)不會(huì)得到“元組推導(dǎo)式”。例诀,在最近的版本中随抠,則會(huì)得到一個(gè)生成器裁着。

【結(jié)果】

2

[0, 9, 36, 81]

[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]

[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]

['arnold+alice', 'bob+bernice', 'chris+clarice']

使用字典進(jìn)行效率更高的優(yōu)化,只使用一層for循環(huán):

【代碼】

girls = ['alice','bernice','clarice']

boys = [

'chris','arnold','bob']

letteGirls = {}

for girl in girls:

??? letteGirls.setdefault(girl[

0],[]).append(girl)

a = [b +

'+' + g for b in boys for g in letteGirls[b[0]]] #列表推導(dǎo)式不能使用元組"()"拱她,而應(yīng)使用列表"[]"print(a)

【結(jié)果】

['chris+clarice', 'arnold+alice', 'bob+bernice']

5.7 三人行

5.7.1 什么都沒發(fā)生

有時(shí)跨算,程序什么事情都不做,這種情況椭懊,應(yīng)讓pass出馬

【代碼】

#Python中空代碼是非法的,解決的方法就是在語句塊中加上一個(gè)pass語句:name = 'Bill Gates'

if name == 'Ralph Auldus Melish':


print('Welcome')

elif name == 'Enid':


#還沒完步势。氧猬。。

??? pass

elifname == 'Bill Gates':


print('Access Denied')

#注釋pass語句聯(lián)合的替代方案時(shí)插入字符串

【結(jié)果】

Access Denied

5.7.2 使用del刪除

【代碼】

#一般來說坏瘩,Python會(huì)刪除那些不再使用的對(duì)象scoundrel = {'age':42,'first

name':'Robin','last

name':'of Locksley'}

robin = scoundrel

print(scoundrel)

print(robin)

scoundrel =

None

print(robin)

#首先盅抚,robin和scoundrel都被綁定到同一個(gè)字典上。所以當(dāng)設(shè)置scoundrel為None的時(shí)候倔矾,字典通過robin還是可用的妄均。但是當(dāng)把robin也設(shè)置為None的時(shí)候,字典就“漂”在內(nèi)存里面了哪自,沒有任何名字綁定到它上面丰包。所以python解釋器直接刪除了那個(gè)字典(這種行為被稱為垃圾收集)。也可以使用None之外的其他值壤巷,字典同樣會(huì)“消失不見”

【結(jié)果】

{'age': 42, 'last name': 'of Locksley', 'first name': 'Robin'}

{'age': 42, 'last name': 'of Locksley', 'first name': 'Robin'}

{'age': 42, 'last name': 'of Locksley', 'first name': 'Robin'}

【代碼】

#使用del語句邑彪,不僅會(huì)移動(dòng)一個(gè)對(duì)象的引用,也會(huì)移除那個(gè)名字本身

# x = 1

# del x

# print(x)

x = ['Hello','world']

y = x

y[

1] = 'Pythoin'

print(x)

del x

print(y)

#原因是刪除的只是名稱胧华,而不是列表本身寄症。事實(shí)上,在Python中是沒有辦法刪除值的(也不需要過多考慮刪除值的問題矩动,因?yàn)樵谀硞€(gè)值不再使用的時(shí)候有巧,Python解釋器會(huì)負(fù)責(zé)內(nèi)存的回收)

【結(jié)果】

['Hello', 'Pythoin']

['Hello', 'Pythoin']

5.7.3 使用exec和eval執(zhí)行和求值字符串

有時(shí)可能會(huì)需要?jiǎng)討B(tài)創(chuàng)造Python代碼,然后將其作為語句執(zhí)行或作為表達(dá)式計(jì)算悲没,---在此之前篮迎,一定要謹(jǐn)慎

[if !supportLists]1.? [endif]exec

【代碼】

#在Python3中,exec是一個(gè)函數(shù)而不是語句exec('print("hello,world")') #exec函數(shù)的形參是一個(gè)字符串檀训,所以兩邊加引號(hào)from math import sqrt

exec("sqrt

= 1")

print(sqrt(4))

#為什么一開始要這樣做柑潦?exec函數(shù)最有用的地方在于可以動(dòng)態(tài)創(chuàng)建代碼字符串。為了安全起見峻凫,可以增加一個(gè)字典渗鬼,起到命名空間的作用。命名空間又稱為作用域荧琼,是個(gè)非常重要的只知識(shí)譬胎。

【結(jié)果】

hello,world

Traceback (most recent call last):

? File"D:/python_file/20180113/test.py", line 6, in

??? print(sqrt(4))

TypeError: 'int' object is not callable

【示例】

#可以通過增加in 來實(shí)現(xiàn)差牛,其中的就是起到放置代碼字符串命名空間作用的字典。from math import sqrt

scope = {}

exec('sqrt =

1',scope) #python3中使用這種形式限定作用域print(sqrt)

print(len(scope))

print(scope['sqrt']) #可以看出堰乔,sqrt=1 中偏化,sqrt是鍵,1是值print(scope.keys()) #因?yàn)閮?nèi)建的__builtins__字典自動(dòng)包含所有的內(nèi)建函數(shù)和值

【結(jié)果】

2

1

dict_keys(['sqrt', '__builtins__'])

[if !supportLists]2.? [endif]eval

【示例】

#eval(用于“求值”)是類似于exec的內(nèi)建函數(shù)镐侯。exec語句會(huì)執(zhí)行一些列Python語句侦讨,而eval會(huì)計(jì)算Python表達(dá)式(以字符串形式書寫),并且返回結(jié)果值苟翻,(exec語句并不返回任何對(duì)象韵卤,因?yàn)樗旧砭褪钦Z句)。e = eval(input("Enter

an arithmetic expression:"))

print(e)

#注:Python2中崇猫,表達(dá)式eval(raw_input(...))事實(shí)上等同于input(...).在Python3.0中沈条,raw_input被重命名為input

#

可以給eval語句提供兩個(gè)命名空間,一個(gè)全局的一個(gè)局部的诅炉。全局的必須是字典蜡歹,局部的可以是任何形式的映射。

#

目前Python內(nèi)沒有任何執(zhí)行不可信任代碼的安全方式涕烧,一個(gè)可選的方案是使用Pythono的實(shí)現(xiàn)月而,比如Jython,以及使用一些本地機(jī)制议纯,比如Java的sandbox

【結(jié)果】

Enter an arithmetic expression:6 + 18 * 2

42

【示例】

#初探作用域

#

給exec或者eval語句提供命名空間時(shí)景鼠,還可以在真正使用命名空間前放置一些值進(jìn)去scope = {}

scope[

'x'] = 2

scope['y'] = 3

print(eval('x*y',scope))

#同理,exec或者eval調(diào)用的作用域也能在另外一個(gè)上面使用:scope = {}

exec('x = 2',scope)

print(eval('x*x',scope))

【結(jié)果】

6

4

第六章 抽 象

這里痹扇,將會(huì)學(xué)習(xí)語句組織成函數(shù)铛漓,這樣,可以告訴計(jì)算機(jī)如何做事鲫构。有了函數(shù)之后浓恶,不必反反復(fù)復(fù)項(xiàng)計(jì)算機(jī)傳遞同樣的具體指令了。本章還會(huì)詳細(xì)介紹參數(shù)和作用域的概念结笨。以及遞歸概念及其在程序中的用途包晰。

6.1 懶惰即美德

【代碼】

fibs = [0,1]

for i in range(8):

??? fibs.append(fibs[-

2] +fibs[-1])

print(fibs)

#如果想要一次計(jì)算前10個(gè)數(shù)的話,沒有問題炕吸。甚至可以將用戶輸入的數(shù)字作為動(dòng)態(tài)范圍的長度使用伐憾,從而改變for語句循環(huán)的次數(shù)fibs = [0,1]

num =

int(input('How

many Fibonacci number do you want?')) #使用for i in range(num-2):


print('i=',i,)

??? fibs.append(fibs[-

2] +fibs[-1]) #主要在于循環(huán)幾次(總共需要5個(gè),原始序列中有兩個(gè))print(fibs)

【結(jié)果】

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

How many Fibonacci number do you want?5

i= 0

i= 1

i= 2

[0, 1, 1, 2, 3]

#真正的程序員會(huì)讓自己的程序抽象一些赫模,上面的程序可以改寫為較抽象的版本:

#num = int(input('How many numbers do you want?'))

#print(fibs(num))

如果函數(shù)要用很多次的話树肃,這么做會(huì)節(jié)省很多精力

6.2 抽象和結(jié)構(gòu)

抽象可以節(jié)省很多工作,實(shí)際上它的作用還要更大瀑罗,它是計(jì)算機(jī)程序可以讓人讀懂的關(guān)鍵(這也是最基本的要求)胸嘴。計(jì)算機(jī)非常樂于處理精確和具體的指令雏掠,但是人可就不同了。

計(jì)算機(jī)會(huì):向前走10米劣像,左轉(zhuǎn)90度乡话,再走5步,右轉(zhuǎn)45度耳奕,走123步

人只需要知道:一直沿著街道走绑青,過橋,電影院就在左手邊屋群,這樣就明白了吧时迫!關(guān)鍵大家都知道怎樣走路和過橋,不需要指令來知道這些事谓晌。

組織計(jì)算機(jī)程序也是類似的。程序應(yīng)該是非常抽象的癞揉。事實(shí)上纸肉,我們把這段描述翻譯為Python程序。

page = download_page()

freqs = compute_frequencies(page)

for word,freq in freqs:

??? print word,freq

6.3 創(chuàng)建函數(shù)

函數(shù)可以調(diào)用(可能包含參數(shù))喊熟,它執(zhí)行某種行為并且返回一個(gè)值柏肪。一般來說,內(nèi)建的callable函數(shù)可以用來判斷函數(shù)是否可調(diào)用:

【示例】

import math

x =

1

y = math.sqrt

print(callable(x))

print(callable(y))

【結(jié)果】

False

True

【示例】

#那么芥牌,怎樣定義函數(shù)呢def hello(name):


return 'Hello,'+name+'!'

print(hello('world'))

print(hello('Gumby'))

【結(jié)果】

Hello,world!

Hello,Gumby!

【示例】

def fibs(num):

??? result = [

0,1]


for i in range(num-2):

??????? result.append(result[-

2]+result[-1])


return result

print(fibs(10))

print(fibs(15))

#注:result語句是用來從函數(shù)中返回值的

【結(jié)果】

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]

6.3.1 記錄函數(shù)

如果想要給函數(shù)寫文檔烦味,讓后面使用該函數(shù)人能理解的haul,可以加入注釋(以#開頭)壁拉。另外一個(gè)方式就是直接寫上字符串谬俄。這類字符串在其他地方可能會(huì)非常有用。如果在函數(shù)的開頭寫下字符串弃理,它就會(huì)作為函數(shù)的一部分進(jìn)行存儲(chǔ)溃论,這稱為文檔字符串。

【示例】

def square(x):


'Calculates the square of the number x.'

??? return x*x

print(square(2))

【結(jié)果】

4

【示例】

def square(x):


'Calculates the square of the number x.'

??? return x*x

print(square(2))

print(square.__doc__) #這樣對(duì)文檔字符串進(jìn)行訪問痘昌,__doc__是函數(shù)屬性钥勋。第7章會(huì)介紹更多關(guān)于屬性的知識(shí),雙下劃線表示它是個(gè)特殊屬性辆苔。這類特殊和"魔法"屬性在第9章中介紹

#

內(nèi)建的help函數(shù)是非常有用的算灸。在交互式解釋器中使用它,可以得到關(guān)于函數(shù)驻啤,包括它的文檔字符串的信息:print(help(square)) #第10章對(duì)help函數(shù)進(jìn)行討論

【結(jié)果】

4

Calculates the square of the number x.

Help on function square in module __main__:


square(x)

??? Calculates the square of thenumber x.


None

6.3.3 并非真正函數(shù)的函數(shù)

數(shù)學(xué)意義上的函數(shù)菲驴,總在計(jì)算其參數(shù)后返回點(diǎn)什么。Python的有些函數(shù)并不返回任何東西骑冗。但是Python的函數(shù)就是函數(shù)谢翎,即便它從學(xué)術(shù)上講并不是函數(shù)捍靠。沒有return語句,或者return后沒有跟任何值的函數(shù)不返回值

【示例】

def test():


print('This is printed')


return

??? print('This is not')

x =test()

#可以看到森逮,第2個(gè)return語句被跳過了(類似于循環(huán)中的break語句)

#

但是如果test不返回任何值榨婆,那么x又引用什么呢?print(x)

#好熟悉的None褒侧,所以所有的函數(shù)的確都返回了東西:當(dāng)不需要它們返回值的時(shí)候良风,它們就返回None∶乒看來烟央,“有些函數(shù)并不是真正的函數(shù)”的說法有些不公平了。

#

不要被默認(rèn)的行為所迷惑歪脏,當(dāng)調(diào)用者期待一個(gè)序列的時(shí)候疑俭,就不會(huì)意外地返回None。

【結(jié)果】

This is printed

None

6.4 參數(shù)魔法

函數(shù)用起來很簡單婿失,創(chuàng)建起來也不復(fù)雜钞艇。但函數(shù)參數(shù)的用法就有時(shí)有些不可思議了。

6.4.1 值從哪里來

寫在def語句中函數(shù)名后面的變量通常叫做函數(shù)的形式參數(shù)豪硅,而調(diào)用函數(shù)的時(shí)候提供的值是實(shí)際參數(shù)(值)哩照。

6.4.2 能改變參數(shù)么

【示例】

#函數(shù)通過它的參數(shù)獲得一系列值。那參數(shù)只是變量而已懒浮,所以它們的行為和預(yù)想的一樣飘弧。在函數(shù)內(nèi)為參數(shù)賦予新值不會(huì)改變外部任何變量的值:def try_to_change(n):


n = 'Mr. Gumby'

name = 'Mrs. Entity'

try_to_change(name)

print(name) #可以看出,該函數(shù)沒有改變變量name的值

#

在try_to_change函數(shù)的內(nèi)部砚著,參數(shù)n獲得了新值次伶,但是它沒有影響到name變量。n實(shí)際上是個(gè)完全不同的變量稽穆,具體的工作方式類似于下面:name = "Mrs. Entity"

n = name #這等于傳遞參數(shù)n = 'Mr. Gumby'

print(name)

#結(jié)果是顯而易見的学少,當(dāng)變量n改變的時(shí)候,變量name不變秧骑。同樣版确,當(dāng)在函數(shù)內(nèi)部把參數(shù)重綁定(賦值)的時(shí)候,函數(shù)外部的變量不會(huì)受到影響乎折。

#

注:參數(shù)存儲(chǔ)在局部作用域內(nèi)

【結(jié)果】

Mrs. Entity

Mrs. Entity

【示例】

#字符串(以及數(shù)字和元組)是不可變的绒疗,即無法修改(也就是說只能用新的值覆蓋)。但是:如果將可變的數(shù)據(jù)結(jié)構(gòu)如列表用作參數(shù)的時(shí)候會(huì)發(fā)生什么:def change(n): #關(guān)鍵看實(shí)參是什么骂澄,實(shí)參是字符串吓蘑,則不能改變,實(shí)參是列表,則能改變

??? n[0] = 'Mr. Gumby'

names = ['Mrs. Entity','Mrs.

Thing']

change(names)

print(names)

#本例中磨镶,參數(shù)被改變了溃蔫。這就是本例和前面例子中至關(guān)重要的區(qū)別。前面的例子中琳猫,局部變量被賦予了新值伟叛,但是這個(gè)例子中變量names所綁定的列表的確改變了。有些奇怪了吧脐嫂?

#

下面進(jìn)行模仿names = ['Mrs. Entity','Mrs.

Thing']

n = names

#再來一次统刮,模擬傳參行為n[0] = 'Mr. Gumby' #改變列表names

【結(jié)果】

['Mr. Gumby', 'Mrs. Thing']

【示例】

#這種情況在前面已經(jīng)出現(xiàn)很多次了。當(dāng)兩個(gè)變量同時(shí)引用一個(gè)列表的時(shí)候账千,它們的確是同時(shí)引用一個(gè)列表侥蒙。如果想避免出現(xiàn)這種情況,可以復(fù)制一個(gè)列表的副本匀奏。在序列中做切片的時(shí)候鞭衩,返回的切片總是一個(gè)副本。names =['Mrs. Entity','Mrs.

Thing']

n = names[:]

#使用切片進(jìn)行復(fù)制(這個(gè)相當(dāng)于字典中的深復(fù)制)

#

如果現(xiàn)在改變n娃善,則不會(huì)影響到namesn[0] = 'Mr. Gumby'

print(n)

print(names)

【結(jié)果】

['Mr. Gumby', 'Mrs. Thing']

['Mrs. Entity', 'Mrs. Thing']

【示例】

#這種情況在前面已經(jīng)出現(xiàn)很多次了论衍。當(dāng)兩個(gè)變量同時(shí)引用一個(gè)列表的時(shí)候,它們的確是同時(shí)引用一個(gè)列表会放。如果想避免出現(xiàn)這種情況,可以復(fù)制一個(gè)列表的副本钉凌。在序列中做切片的時(shí)候,返回的切片總是一個(gè)副本。names =['Mrs. Entity','Mrs.

Thing']

n = names[:]

#使用切片進(jìn)行復(fù)制(這個(gè)相當(dāng)于字典中的深復(fù)制)

#

如果現(xiàn)在改變n蓝谨,則不會(huì)影響到namesn[0] = 'Mr. Gumby'

print(n) #n變了print(names) #names沒變

#

再用change試一下def change(n): #關(guān)鍵看實(shí)參是什么削樊,實(shí)參是字符串,則不能改變酸纲,實(shí)參是列表捣鲸,則能改變

??? n[0] = 'Mr. Gumby'

change(names[:]) #使用這種方式,傳遞進(jìn)去的是一個(gè)串闽坡,如果形參是names,則傳遞進(jìn)去的是一個(gè)列表print(names)

【結(jié)果】

['Mr. Gumby', 'Mrs. Thing']

['Mrs. Entity', 'Mrs. Thing']

['Mrs. Entity', 'Mrs. Thing']

[if !supportLists]1.? [endif]為什么我們要修改參數(shù)

使用函數(shù)改變數(shù)據(jù)結(jié)構(gòu)(比如列表或字典)是將程序抽象化的好方法栽惶。假設(shè)需要編寫一個(gè)存儲(chǔ)名字并且能用名字、中間名或姓查找聯(lián)系人的程序疾嗅,可以使用下面的數(shù)據(jù)結(jié)構(gòu):

【示例】

storage= {}

storage[

'first'] = {}

storage[

'middle'] = {}

storage[

'last'] = {}

#storage這個(gè)數(shù)據(jù)結(jié)構(gòu)的存儲(chǔ)方式是帶有3個(gè)鍵“first”外厂、“middle”和“l(fā)ast”的字典。每個(gè)鍵的下面都又存儲(chǔ)一個(gè)字典代承。子字典中汁蝶,可以使用名字(名字、中間名或姓)作為鍵,插入聯(lián)系人列表作為值掖棉。me = 'Magnus Lie Hetland'

storage['first']['Magnus'] = [me] #Magnus是key墓律,me是value(說明value是一個(gè)列表,可以使用append方法進(jìn)行追加元素)storage['middle']['Lie'] =[me]

storage[

'last']['Hetland'] = [me]

#每個(gè)鍵下面都存儲(chǔ)了一個(gè)以人名組成的列表幔亥。本例表中耻讽,人名只有“我”。如果想得到所有注冊(cè)的中間名為Lie的人紫谷,可以像下面這樣做:print(storage['middle']['Lie'])

#將人名加入到列表中的步驟有些枯燥乏味齐饮,尤其是要加入很多姓名相同的人時(shí),因?yàn)橐獢U(kuò)展已經(jīng)存儲(chǔ)了哪些名字的列表笤昨。例如祖驱,下面加入我姐姐的名字,而且假設(shè)不知道數(shù)據(jù)庫中已經(jīng)存儲(chǔ)了什么:my_sister = 'Anne Lie Hetland'

storage['first'].setdefault('Anne',[]).append(my_sister)#Anne是key瞒窒,my_sister是valuestorage['middle'].setdefault('Lie',[]).append(my_sister)

storage[

'last'].setdefault('Hetland',[]).append(my_sister)

print(storage['middle']['Lie'])

【結(jié)果】

['Magnus Lie Hetland']

['Magnus Lie Hetland', 'Anne Lie Hetland']

【代碼】

#如果要寫個(gè)大程序來這樣更新列表捺僻,那么很顯然程序很快就會(huì)變得臃腫且笨拙不堪了。抽象的要點(diǎn)就是隱藏更新時(shí)的繁瑣的細(xì)節(jié)崇裁,這個(gè)過程可以使用函數(shù)來實(shí)現(xiàn)匕坯。def init(data): #data本身是個(gè)字典

??? data['first'] = {}

??? data[

'middle'] = {}

??? data[

'last'] = {}

#使用的方法如下:storage = {}

init(storage)

#print(storage)

#可以看到,函數(shù)包辦了初始化工作拔稳,讓代碼更易讀

#

在編寫存儲(chǔ)名字的函數(shù)前葛峻,先寫個(gè)獲得名字的函數(shù)def lookup(data,label,name):


return data[label].get(name)

#標(biāo)簽(比如“middle")以及名字(比如“Lie”)可以作為參數(shù)提供給lookup函數(shù)使用,這樣會(huì)獲得包含全名的列表

#

注:返回的列表和存儲(chǔ)在數(shù)據(jù)結(jié)構(gòu)中的列表是相同的巴比,所以如果列表修改了术奖,那么也會(huì)影響數(shù)據(jù)結(jié)構(gòu)def store(data,full_name):

??? names = full_name.split()

#得到的是一個(gè)列表['','','',...]

??? if len(names)

== 2:

??????? names.insert(

1,'') #在names列表的下標(biāo)為1的位置處插入

??? labels = 'first','middle','last'#是一個(gè)元組

??? for label,name inzip(labels,names):

??????? people = lookup(data,label,name)


if people:

??????????? people.append(full_name)


else:

??????????? data[label][name] =[full_name]

#如果原先沒有值,則賦值

#

(1)通過參數(shù)data和full_name進(jìn)入函數(shù)轻绞,這兩個(gè)參數(shù)被設(shè)置為函數(shù)在外部獲得的一些值采记。

#

(2)通過拆分full_name,得到一個(gè)叫做names的列表

#

(3)如果names的長度為2(只有首名和末名)政勃,那么插入一個(gè)空字符串作為中間名

#

(4)將字符串“first”唧龄、“middle”和“l(fā)ast”作為元組存儲(chǔ)在labels中(也可以使用列表,這里只是為了方便而去掉括號(hào))

#

(5)使用zip函數(shù)聯(lián)合標(biāo)簽和名字奸远,對(duì)于每一個(gè)(label既棺,name)對(duì),進(jìn)行以下處理:

??? #

①獲得屬于給定標(biāo)簽和名字的列表

??? #

②將full_name添加到列表中懒叛,或者插入一個(gè)需要更新的新列表MyNames = {}

init(MyNames)

store(MyNames,

'Magnus Lie

Hetland')

print(lookup(MyNames,'middle','Lie'))

#好像可以工作援制,再試試store(MyNames,'Robin Hood')

store(MyNames,

'Robin Locksley')

print(lookup(MyNames,'first','Robin'))

store(MyNames,

'Mr. Gumby')

print(lookup(MyNames,'middle',''))

#可看到,如果某些人的名字芍瑞、中間名或姓相同晨仑,那么結(jié)果中會(huì)包含所有這些人的信息。

#

這類程序很適合進(jìn)行面向?qū)ο蟪绦蛟O(shè)計(jì)

【結(jié)果】

['Magnus Lie Hetland']

['Robin Hood', 'Robin Locksley']

['Robin Hood', 'Robin Locksley', 'Mr. Gumby']

[if !supportLists]2.? [endif]如果我的參數(shù)不可變呢

在某些語言(如C++,Pascal和Ada)中洪己,重綁定參數(shù)并且使這些改變到函數(shù)外的變量是很平常的事情妥凳。但在Python中,這是不可能的:函數(shù)只能修改參數(shù)對(duì)象本身答捕。但是如果你的參數(shù)不可變—比如是數(shù)字—又該怎么辦呢逝钥?

不好意思,沒有辦法拱镐。這個(gè)時(shí)候應(yīng)該從函數(shù)中返回所有需要的值(如果值多余一個(gè)的話就以元組的形式返回)艘款。

??1???N??

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市沃琅,隨后出現(xiàn)的幾起案子哗咆,更是在濱河造成了極大的恐慌,老刑警劉巖益眉,帶你破解...
    沈念sama閱讀 206,013評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件晌柬,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡郭脂,警方通過查閱死者的電腦和手機(jī)年碘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來展鸡,“玉大人屿衅,你說我怎么就攤上這事∮ū祝” “怎么了涤久?”我有些...
    開封第一講書人閱讀 152,370評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長箱硕。 經(jīng)常有香客問我拴竹,道長悟衩,這世上最難降的妖魔是什么剧罩? 我笑而不...
    開封第一講書人閱讀 55,168評(píng)論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮座泳,結(jié)果婚禮上惠昔,老公的妹妹穿的比我還像新娘。我一直安慰自己挑势,他們只是感情好镇防,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著潮饱,像睡著了一般来氧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,954評(píng)論 1 283
  • 那天啦扬,我揣著相機(jī)與錄音中狂,去河邊找鬼。 笑死扑毡,一個(gè)胖子當(dāng)著我的面吹牛胃榕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播瞄摊,決...
    沈念sama閱讀 38,271評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼勋又,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了换帜?” 一聲冷哼從身側(cè)響起楔壤,我...
    開封第一講書人閱讀 36,916評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎膜赃,沒想到半個(gè)月后挺邀,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,382評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡跳座,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評(píng)論 2 323
  • 正文 我和宋清朗相戀三年端铛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片疲眷。...
    茶點(diǎn)故事閱讀 37,989評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡禾蚕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出狂丝,到底是詐尸還是另有隱情换淆,我是刑警寧澤,帶...
    沈念sama閱讀 33,624評(píng)論 4 322
  • 正文 年R本政府宣布几颜,位于F島的核電站倍试,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏蛋哭。R本人自食惡果不足惜县习,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望谆趾。 院中可真熱鬧躁愿,春花似錦、人聲如沸沪蓬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽跷叉。三九已至逸雹,卻和暖如春营搅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背梆砸。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評(píng)論 1 260
  • 我被黑心中介騙來泰國打工剧防, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人辫樱。 一個(gè)月前我還...
    沈念sama閱讀 45,401評(píng)論 2 352
  • 正文 我出身青樓峭拘,卻偏偏與公主長得像,于是被迫代替她去往敵國和親狮暑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子鸡挠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評(píng)論 2 345