第八章(二)
3欧引、返回值
函數(shù)返回的值被稱(chēng)為返回值听系。在函數(shù)中,可使用return語(yǔ)句將值返回到調(diào)用函數(shù)的代碼行航棱。返回值可以將程序中大部分繁重的工作移到函數(shù)中去完成睡雇,從而簡(jiǎn)化程序。
(1)返回簡(jiǎn)單值
def get_formatted_name(first_name, last_name):
full_name = first_name + ' ' + last_name
return full_name.title()
musician = get_formatted_name('jimi', 'hendrix')
print(musician)
# 輸出:
Jimi Hendrix
這個(gè)函數(shù)將接收到的姓名整潔地重新輸出饮醇。
(2)讓實(shí)參變成可選的
讓實(shí)參變成可選的它抱,可以讓使用函數(shù)的人只有在必要時(shí)才提供額外的信息∑蛹瑁可使用默認(rèn)值來(lái)讓實(shí)參變成可選的观蓄。
def get_formatted_name(first_name, last_name, middle_name=''):
if middle_name:
full_name = first_name + ' ' + middle_name + ' ' + last_name
else:
full_name = first_name + ' ' + last_name
return full_name.title()
musician = get_formatted_name('jimi', 'hendrix')
print(musician)
musician = get_formatted_name('john', 'hooker', 'lee')
print(musician)
# 輸出:
Jimi Hendrix
John Lee Hooker
在上面的函數(shù)中添加了一個(gè)中間名,若沒(méi)有給定默認(rèn)值祠墅,調(diào)用時(shí)只提供名和姓侮穿,Python會(huì)報(bào)錯(cuò)。而給它一個(gè)空字符串作為默認(rèn)值就不會(huì)報(bào)錯(cuò)毁嗦。給了默認(rèn)值的參數(shù)必須移到?jīng)]有默認(rèn)值的參數(shù)后面亲茅。在調(diào)用函數(shù)的時(shí)候,有默認(rèn)值的形參是否傳遞實(shí)參,完全在于調(diào)用的人是否需要克锣∫鹚啵可選值讓函數(shù)能夠處理各種不同的情形的同時(shí),確保函數(shù)調(diào)用盡可能簡(jiǎn)單娶耍。
(3)返回字典
函數(shù)可返回任何類(lèi)型的值,包括列表和字典等較為復(fù)雜的的數(shù)據(jù)結(jié)構(gòu)饼酿。
def build_person(first_name, last_name):
person = {'first': first_name, 'last': last_name}
return person
musician = build_person('jimi', 'hendrix')
print(musician)
# 輸出:
{'first': 'jimi', 'last': 'hendrix'}
在這個(gè)函數(shù)中榕酒,你可以輕松的擴(kuò)展這個(gè)函數(shù),使其接收可選值故俐。
def build_person(first_name, last_name, age=''):
person = {'first': first_name, 'last': last_name}
if age:
person['age'] = age
return person
musician = build_person('jimi', 'hendrix', age=27)
print(musician)
# 輸出:
{'first': 'jimi', 'last': 'hendrix', 'age': 27}
在這里新增了一個(gè)可選的形參age想鹰。同理也可以進(jìn)行其他信息的擴(kuò)展。
(4)結(jié)合使用函數(shù)和while循環(huán)
def get_formatted_name(first_name, last_name):
full_name = first_name + ' ' + last_name
return full_name.title()
while True:
print("\nPlease tell me your name:")
print("(enter 'q' at any time to quit)")
f_name = input("First name: ")
if f_name == 'q':
break
l_name = input("Last name: ")
if l_name == 'q':
break
formatted_name = get_formatted_name(f_name, l_name)
print("\nHello, " + formatted_name + "!")
# 輸出:
Please tell me your name:
(enter 'q' at any time to quit)
First name: eric
Last name: matthes
Hello, Eric Matthes!
Please tell me your name:
(enter 'q' at any time to quit)
First name: q
4药版、傳遞列表
將列表傳遞給函數(shù)后辑舷,函數(shù)就能直接訪問(wèn)其內(nèi)容。用函數(shù)訪問(wèn)列表中的每個(gè)人:
def greet_users(names):
for name in names:
msg = "Hello, " + name.title() + "!"
print(msg)
usernames = ['hannah', 'ty', 'margot']
greet_users(usernames)
# 輸出:
Hello, Hannah!
Hello, Ty!
Hello, Margot!
(1)在函數(shù)中修改列表
將列表傳遞給函數(shù)后槽片,函數(shù)就可對(duì)其進(jìn)行修改何缓。在函數(shù)中對(duì)這個(gè)列表所做的任何修改都是永久的。
def print_models(unprinted_designs, completed_models):
while unprinted_designs:
current_design = unprinted_designs.pop()
print("Printing model: " + current_design)
completed_models.append(current_design)
def show_completed_models(completed_models):
print("\nThe following models have been printed:")
for completed_model in completed_models:
print(completed_model)
unprinted_designs = ['iphone case', 'robot pendant', 'dodecahedron']
completed_models = []
print_models(unprinted_designs, completed_models)
show_completed_models(completed_models)
# 輸出:
Printing model: dodecahedron
Printing model: robot pendant
Printing model: iphone case
The following models have been printed:
dodecahedron
robot pendant
iphone case
這個(gè)例子演示了一種理念还栓,即每個(gè)函數(shù)都應(yīng)只負(fù)責(zé)一項(xiàng)具體的工作碌廓。編寫(xiě)函數(shù)時(shí),如果你發(fā)現(xiàn)它執(zhí)行的任務(wù)太多剩盒,可以嘗試將它分到兩個(gè)函數(shù)中谷婆,而且總是可以在一個(gè)函數(shù)中調(diào)用另一個(gè)函數(shù),這有助于將復(fù)雜的任務(wù)劃分成一系列的步驟辽聊。
(2)禁止函數(shù)修改列表
當(dāng)你執(zhí)行修改列表后纪挎,還需要使用未修改之前的列表時(shí),可以將傳遞給函數(shù)的列表改為列表的副本而不是原件跟匆,這樣函數(shù)所做的任何修改都只影響副本异袄,而絲毫不影響原件。
用切片表示法[:]創(chuàng)建列表的副本玛臂。如:
print_models(unprinted_designs[:], completed_models)
雖然向函數(shù)傳遞列表的副本可保留原始列表的內(nèi)容隙轻,但除非有充分的理由需要傳遞副本,否則還是應(yīng)該將原始列表傳遞給函數(shù)垢揩,因?yàn)樽尯瘮?shù)使用現(xiàn)成列表可避免花時(shí)間和內(nèi)存創(chuàng)建副本玖绿,從而提高效率,在處理大型列表時(shí)尤其如此叁巨。
5斑匪、傳遞任意數(shù)量的實(shí)參
Python允許函數(shù)從調(diào)用語(yǔ)句中收集任意數(shù)量的實(shí)參。
def make_pizza(*toppings):
print(toppings)
make_pizza('pepperoni')
make_pizza('mushrooms', 'green peppers', 'extra cheese')
# 輸出:
('pepperoni',)
('mushrooms', 'green peppers', 'extra cheese')
形參名*toppings中的星號(hào)讓Python創(chuàng)建一個(gè)名為toppings的空元組,并將收到的所有值都封裝在這個(gè)元組中蚀瘸,即使只收到一個(gè)值也是封裝在元組中狡蝶。上述例子的第一條輸出就是如此,只有一個(gè)元素的元組用小括號(hào)括起來(lái)贮勃,并在元素的后面添加一個(gè)逗號(hào)贪惹。
(1)結(jié)合使用位置實(shí)參和任意數(shù)量實(shí)參
如果要讓函數(shù)接收不同類(lèi)型的實(shí)參,必須在函數(shù)定義中將接納任意數(shù)量實(shí)參的形參放在最后寂嘉。Python先匹配位置實(shí)參和關(guān)鍵字實(shí)參奏瞬,再將余下的實(shí)參都收集到一個(gè)形參中。
def make_pizza(size, *toppings):
print("\nMaking a " + str(size) +
"-inch pizza with the following toppings:")
for topping in toppings:
print("- " + topping)
make_pizza(16, 'pepperoni')
make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
# 輸出:
Making a 16-inch pizza with the following toppings:
- pepperoni
Making a 12-inch pizza with the following toppings:
- mushrooms
- green peppers
- extra cheese
(2)使用任意數(shù)量的關(guān)鍵字實(shí)參
需要接收任意數(shù)量的實(shí)參泉孩,但預(yù)先不知道傳遞給函數(shù)的會(huì)是什么樣的信息硼端。這時(shí)候可將函數(shù)編寫(xiě)成能夠接收任意數(shù)量的鍵-值對(duì)——調(diào)用語(yǔ)句提供了多少就接收多少。
def build_profile(first, last, **user_info):
profile = {}
profile['first_name'] = first
profile['last_name'] = last
for key, value in user_info.items():
profile[key] = value
return profile
user_profile = build_profile('albert', 'einstein',
location='princeton',
field='physics')
print(user_profile)
# 輸出:
{'first_name': 'albert', 'last_name': 'einstein',
'location': 'princeton', 'field': 'physics'}
形參**user_info中的兩個(gè)星號(hào)讓Python創(chuàng)建一個(gè)名為user_info的空字典寓搬,并將收到的所有名稱(chēng)-值對(duì)都封裝到這個(gè)字典中珍昨。
編寫(xiě)函數(shù)時(shí),可以以各種方式混合使用位置實(shí)參句喷、關(guān)鍵字實(shí)參和任意數(shù)量的實(shí)參镣典。
6、將函數(shù)存儲(chǔ)在模塊中
函數(shù)的優(yōu)點(diǎn)之一是唾琼,使用它們可將代碼塊與主程序分離骆撇。通過(guò)給函數(shù)指定描述性名稱(chēng),可讓主程序容易理解得多父叙。還可以將函數(shù)存儲(chǔ)在被稱(chēng)為模塊的獨(dú)立文件中神郊,再將模塊導(dǎo)入到主程序中。import語(yǔ)句允許在當(dāng)前運(yùn)行的程序文件中使用模塊中的代碼趾唱。
通過(guò)將函數(shù)存儲(chǔ)在獨(dú)立的文件中涌乳,可隱藏程序代碼的細(xì)節(jié),將重點(diǎn)放在程序的高層邏輯上甜癞。這可以在眾多不同的程序中重用函數(shù)夕晓。將函數(shù)存儲(chǔ)在獨(dú)立文件中后,可與其他程序員共享這些文件而不是整個(gè)程序悠咱。
(1)導(dǎo)入整個(gè)模塊
要讓函數(shù)是可導(dǎo)入的蒸辆,得先創(chuàng)建模塊。模塊是擴(kuò)展名為.py的文件析既,包含要導(dǎo)入到程序中的代碼躬贡。
將前面make_pizza函數(shù)放在一個(gè)名為pizza.py的文件中,然后再創(chuàng)建一個(gè)名為making_pizzas.py的文件眼坏,在文件的開(kāi)頭添加import pizza拂玻,然后在下面寫(xiě)入調(diào)用函數(shù)的語(yǔ)句運(yùn)行即可。程序運(yùn)行時(shí),import會(huì)將pizza文件中的所有函數(shù)復(fù)制到程序中檐蚜。
要調(diào)用被導(dǎo)入的模塊中的函數(shù)魄懂,可指定導(dǎo)入的模塊的名稱(chēng)pizza和函數(shù)名make_pizza(),并用句點(diǎn)分隔它們闯第。如:
pizza.make_pizza(16, 'pepperoni')
只需編寫(xiě)一條import語(yǔ)句并在其中指定模塊名市栗,就可以在程序中使用該模塊中的所有函數(shù)。
module_name.function_name()
(2)導(dǎo)入特定的函數(shù)
導(dǎo)入模塊中的特定函數(shù):
from module_name import function_name
通過(guò)用逗號(hào)分隔函數(shù)名咳短,可根據(jù)需要從模塊中導(dǎo)入任意數(shù)量的函數(shù):
from module_name import function_0, function_1, function_2
使用這種方法導(dǎo)入函數(shù)后填帽,調(diào)用函數(shù)時(shí)就不需要使用句點(diǎn)。因?yàn)橐呀?jīng)在import語(yǔ)句中顯示地導(dǎo)入了函數(shù)诲泌,所以調(diào)用時(shí)指定其名稱(chēng)即可盲赊。
(3)使用as給函數(shù)指定別名
如果要導(dǎo)入的函數(shù)的名稱(chēng)可能與程序中現(xiàn)有的名稱(chēng)沖突铣鹏,或者函數(shù)的名稱(chēng)太長(zhǎng)敷扫,可指定簡(jiǎn)短而獨(dú)一無(wú)二的別名——類(lèi)似于給函數(shù)起一個(gè)外號(hào)。若要這么做诚卸,就要在導(dǎo)入它時(shí)就要做葵第。
在import語(yǔ)句中使用關(guān)鍵字as將函數(shù)重命名為你想要的別名:
from pizza import make_pizza as mp
因?yàn)橛辛艘粋€(gè)別名,所以調(diào)用函數(shù)時(shí)可以直接用別名來(lái)調(diào)用合溺。
(4)使用as給模塊指定別名
給模塊指定別名卒密,能使代碼更簡(jiǎn)潔,而且不再關(guān)注模塊名棠赛,而專(zhuān)注于描述性的函數(shù)名哮奇,對(duì)理解代碼更好。
import module_name as mn
(5)代入模塊中的所有函數(shù)
使用星號(hào)(*)運(yùn)算符可讓Python導(dǎo)入模塊中的所有函數(shù)睛约。由于導(dǎo)入了每個(gè)函數(shù)鼎俘,可通過(guò)名稱(chēng)來(lái)調(diào)用每個(gè)函數(shù),而無(wú)需使用句點(diǎn)表示法辩涝。然而贸伐,使用并非自己編寫(xiě)的大型模塊時(shí),最好不要采用這種導(dǎo)入方法:如果模塊中有函數(shù)的名稱(chēng)與你的項(xiàng)目中使用的名稱(chēng)相同怔揩,可能導(dǎo)致意想不到的結(jié)果:Python可能遇到多個(gè)名稱(chēng)相同的函數(shù)或變量捉邢,進(jìn)而覆蓋函數(shù),而不是分別導(dǎo)入所有函數(shù)商膊。
最佳的做法是伏伐,要么只導(dǎo)入你需要使用的函數(shù),要么導(dǎo)入整個(gè)模塊并使用句點(diǎn)表示法晕拆。
from module_name import *
7秘案、函數(shù)編寫(xiě)指南
應(yīng)給函數(shù)指定描述性名稱(chēng),且只在其中使用小寫(xiě)字母和下劃線。給模塊命名時(shí)也應(yīng)遵循上述約定阱高。
每個(gè)函數(shù)都應(yīng)包含簡(jiǎn)要地闡述其功能的注釋?zhuān)撟⑨尵o跟在函數(shù)定義后面赚导,并采用文檔字符串格式。
給形參指定默認(rèn)值時(shí)赤惊,等號(hào)兩邊不要有空格吼旧。對(duì)于函數(shù)調(diào)用中的關(guān)鍵字實(shí)參,也應(yīng)遵循這種約定未舟。
如果函數(shù)的形參很多圈暗,導(dǎo)致函數(shù)定義的長(zhǎng)度超過(guò)了79字符,可在函數(shù)定義中輸入左括號(hào)后按回車(chē)鍵裕膀,并在下一行按兩次Tab鍵员串,從而將形參列表和只縮進(jìn)一層的函數(shù)體區(qū)分開(kāi)來(lái)。
如果程序或模塊包含多個(gè)函數(shù)昼扛,可使用兩個(gè)空行將相鄰的函數(shù)分開(kāi)寸齐,這樣將更容易知道前一個(gè)函數(shù)在什么地方結(jié)束,下一個(gè)函數(shù)在什么地方開(kāi)始抄谐。
所有的import語(yǔ)句都應(yīng)放在文件開(kāi)頭渺鹦,唯一例外的情形是,在文件開(kāi)頭使用了注釋來(lái)描述整個(gè)程序蛹含。