函數(shù)可以將程序拆分成獨立的幾部分,使程序趨于簡單化重父。
1.1花椭、定義和調(diào)用函數(shù)
使用關(guān)鍵字def 來告訴python定義一個函數(shù),向python指出了函數(shù)名房午,也還可以在括號內(nèi)指出函數(shù)為完成任務(wù)需要什么樣的信息矿辽。
而調(diào)用一個函數(shù),只需讓python指定函數(shù)名以及括號內(nèi)的必要信息即可郭厌。
def display_message(): # 函數(shù)定義
"""display a message about what I am learning.""" # 文檔字符串的注釋袋倔,描述函數(shù)是做什么的,由三引號組成折柠,python用來生成有關(guān)程序中函數(shù)的文檔
msg = "I'm learning to store code in functions."
print(msg)
display_message() # 函數(shù)調(diào)用
----------
I'm learning to store code in functions.
1.1.1宾娜、向函數(shù)參數(shù)傳遞信息
函數(shù)在定義時,可在括號內(nèi)指定任意參數(shù)扇售,在調(diào)用時再給其指定一個值前塔,調(diào)用函數(shù)時,可將值傳遞給參數(shù):
def great_user(username): # 指定參數(shù)(形參)
print('Hello ' + username.title() + '!')
great_user('edward') # 指定值并傳遞給參數(shù)(實參)
-------
Hello Edward!
1.1.2承冰、形參和實參
在1.1.1中华弓,變量username是一個形參,它是函數(shù)定義時括號內(nèi)的參數(shù)困乒,是函數(shù)完成其工作所需的一項信息寂屏。
值'edward' 是一個實參,它是函數(shù)調(diào)用時括號內(nèi)的參數(shù)顶燕,是調(diào)用函數(shù)時傳遞給函數(shù)的信息凑保。
在great_user('edward')中,將參數(shù)edward傳遞給函數(shù)great_user()涌攻,并存儲在形參user_name中欧引。
1.2、傳遞實參
函數(shù)定義可能包含多個形參恳谎,調(diào)用時也可以有多個實參芝此,傳遞實參的方式很多,有位置參數(shù)法因痛,(要求形參實參的順序一致)意義婚苹,關(guān)鍵字參數(shù)。
1.2.1鸵膏、位置實參
位置實參要求實參與形參的順序一一對應(yīng),切記不能對應(yīng)錯誤膊升,另一方面,一個函數(shù)可以多次調(diào)用谭企,只需再次指定實參即可廓译。
def describe_pet(animal_type, pet_name):
"""顯示寵物信息"""
print('\nI have a ' + animal_type + '.')
print("My " + animal_type + "'s name is " + pet_name.title() + '.')
describe_pet('hamster', 'harry') # 實參與形參順序?qū)?yīng)评肆,寵物種類對應(yīng)animal_type、名字對應(yīng)pet_name
describe_pet('dog', 'baby') # 二次調(diào)用
1.2.2非区、關(guān)鍵字實參
位置參數(shù)固然有其優(yōu)點瓜挽,但只適合形參比較少的程序,若形參有很多征绸,傳遞實參時就容易顯得雜亂無章久橙,關(guān)鍵字實參將名稱與值關(guān)聯(lián)起來,向形參傳遞實參時就不會混淆管怠。
def describe_pet(animal_type, pet_name): # 形參
"""顯示寵物信息"""
print('\nI have a ' + animal_type + '.')
print("My " + animal_type + "'s name is " + pet_name.title() + '.')
describe_pet(animal_type= 'hamster', pet_name= 'harry') # 將實參直接存儲到形參變量中淆衷,不管順序如何變化都不影響結(jié)果
describe_pet(pet_name= 'baby', animal_type= 'dog')
1.2.3、默認(rèn)值
在函數(shù)定義時可以給形參直接指定個默認(rèn)值排惨,如果與其關(guān)聯(lián)的實參給有默認(rèn)值的形參提供了值吭敢,則用提供的值,否則用默認(rèn)值暮芭。
需要注意的是鹿驼,在調(diào)用函數(shù)時,只有一個實參辕宏,且是位置實參畜晰,那么沒有指定默認(rèn)值的形參要在有默認(rèn)值的形參前面,否則實參將會以位置參數(shù)的形式傳遞給第一個形參:
def describe_pet(pet_name, animal_type='dogs'): # 有默認(rèn)值在沒有默認(rèn)值的形參后面
"""顯示寵物信息"""
print('\nI have a ' + animal_type + '.')
print("My " + animal_type + "'s name is " + pet_name.title() + '.')
describe_pet('willie') # 這個實參將傳遞給第一個形參瑞筐,第二個形參使用默認(rèn)值
describe_pet(animal_type='dog', pet_name='baby') # 有默認(rèn)值的形參使用實參
-------------------
I have a dogs.
My dogs's name is Willie.
I have a dog.
My dog's name is Baby.
1.2.4凄鼻、等效的函數(shù)調(diào)用
鑒于可混合位置實參、關(guān)鍵字實參以及默認(rèn)值聚假,通常有多種調(diào)用方式块蚌,以下便是等效的函數(shù)調(diào)用方式,其結(jié)果一致:
# 一只名為Willie的小狗
describe_pet('willie') # 結(jié)果一致
describe_pet(pet_name='willie')
# 一只名為Harry的倉鼠 # 結(jié)果一致
describe_pet('harry', 'hamster')
describe_pet(pet_name='harry', animal_type='hamster')
describe_pet(animal_type='hamster', pet_name='harry')
1.2.5膘格、避免實參錯誤
在使用函數(shù)時峭范,若遇到實參不匹配時,python會提示我們需要為哪些提供實參瘪贱,如果這個函數(shù)存儲在一個獨立的文件中纱控,那么需要打開這個文件查看函數(shù)的代碼:
def describe_pet(pet_name, animal_type):
print('My ' + animal_type + "'s name is " + pet_name.title() + '.')
describe_pet() # 這個函數(shù)缺少實參,python會提示我們需要為哪個形參提供實參
Traceback (most recent call last):
File "C:/Users/hj/PycharmProjects/untitled1/function_1.py", line 55, in <module>
describe_pet()
TypeError: describe_pet() missing 2 required positional arguments: 'pet_name' and 'animal_type'
1.3菜秦、返回值
函數(shù)并非總是直接顯示輸出甜害,相反,它也處理一些數(shù)據(jù)球昨,并返回一個或一組值尔店,返回的 值稱為返回值,它可以返回列表、元組和字典闹获,可使用return 語句將值返回到調(diào)用函數(shù)的代碼行期犬,返回值可以讓你能夠?qū)⒊绦虻拇蟛糠址敝毓ぷ饕频胶瘮?shù)中去完成河哑,從而簡化程序避诽。
1.3.1、返回簡單值
def get_formatted_name(first_name, last_name):
"""返回完整姓名"""
full_name = first_name + ' ' + last_name # 將完整姓名存儲到變量full_name中
return full_name.title() # 將full_name的值返回到函數(shù)調(diào)用行
musician = get_formatted_name('jimi', 'hendrix') # 在調(diào)用返回值的函數(shù)時璃谨,需要提供一個變量沙庐,用于存儲返回值
print(musician) # 打印變量
------
Jimi Hendrix
1.3.2、讓實參變得可選
有時需要讓實參變得可選佳吞,這樣就能存儲額外的信息拱雏,可使用默認(rèn)值來使實參可選:
# 拓展get_formatted_name(),使其還處理中間名
def get_formatted_name(first_name, last_name, middle_name=''): # 指定middle_name的默認(rèn)值為空
"""返回完整姓名"""
if middle_name: # 判斷調(diào)用函數(shù)時是否給middle_name指定了實參,python將非空字符串認(rèn)為True
full_name = first_name + ' ' + middle_name + ' ' + last_name
else:
full_name = first_name + ' ' + last_name
return full_name.title()
musician = get_formatted_name('jimi', 'hooker', 'lee')
print(musician)
musician = get_formatted_name('jimi', 'hooker') # 調(diào)用函數(shù)時底扳,如果沒有middle_name的實參就會導(dǎo)致程序錯誤铸抑,因此可以指定形參middle_name的默認(rèn)值為空,當(dāng)有實參時則用實參的值衷模,沒有的時候就是空字符串鹊汛,這樣不會奔潰程序
print(musician)
-----
Jimi Lee Hooker
Jimi Hooker
1.3.3、返回字典
函數(shù)可以返回任何類型的值阱冶,包括列表刁憋、元組以及字典等較復(fù)雜的數(shù)據(jù)結(jié)構(gòu):
def build_person(first_name, last_name):
"""返回一個字典,其中包含有關(guān)一個人的信息"""
person = {'first': first_name, 'last': last_name} # 也可以時列表木蹬、元組
return person
musician = build_person('jimi', 'hendrix')
print(musician) # 音樂家
-------
{'first': 'jimi', 'hendrix': 'hendrix'}
返回字典至耻,可以輕易拓展這個函數(shù),使其接受可選值镊叁,如年齡尘颓、中間名、職業(yè)等你想存儲的其他信息:
def buile_person(first_name, last_name, age=''): # 新增了age可選項
"""返回一個字典晦譬,其中包含人名疤苹、年齡"""
person = {'first': first_name, 'last': last_name}
if age:
person['age'] = age # 將鍵-值對添加到字典person中
return person
musician = build_person('jimi', 'hendrix', age=27)
print(musician)
-------
{'first': 'jimi', 'last': 'hendrix', 'age': 27}
1.3.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("\nTell me what's your name: ")
print("(enter 'q' to quit)") # 設(shè)置循環(huán)退出條件
f_n = input('First_name: ') # 接收用戶輸入信息
if f_n == 'q':
break
l_n = input('Last_name: ')
if l_n == 'q':
break
formatted = get_formatted_name(f_n, l_n)
print('\nHello: ' + formatted + '!')
--------------------
Please tell me your name:
(Enter 'q' to quit.)
First_name: Li
Last_name: La
Hello Li La!
1.4蛔添、傳遞列表
向函數(shù)傳遞列表痰催,這種列表包含的可能是名字、數(shù)字或更復(fù)雜的對象(字典)迎瞧,將列表傳遞給函數(shù)后夸溶,函數(shù)就能直接訪問其內(nèi)容,可以提高處理列表的效率凶硅。
1.4.1缝裁、在函數(shù)中修改列表
將列表傳遞給函數(shù)后,可以對其進行修改,修改后是永久性的捷绑,可以高效第處理大量數(shù)據(jù)韩脑。
一家為用戶提交設(shè)計制作的3D打印模型公司,需要打印的設(shè)計存儲在一個列表中粹污,打印后移到另一個列表中:
def printed_models(unprinted_designs, completed_models): # 定義一個函數(shù)段多,2個形參,一個為未打印的設(shè)計壮吩,一個為完成的模型
"""
模擬打印每個設(shè)計进苍,直到?jīng)]有未打印的為止
打印每個設(shè)計后,將其移動completed_models中
"""
while unprinted_designs: # 循環(huán)(只要unprinted_designs不為空循環(huán)繼續(xù))
current_design = unprited_designs.pop() # 將列表中所有元素彈出
# 模擬根據(jù)設(shè)計制作3D打印模型的過程
print('Printing model: ' + current_design)
completed_models.append(current_design) # 將彈出的元素添加到空列表completed_models中
def show_completed_models(completed_models): # 定義一個函數(shù)鸭叙,用以處理所有打印好的模型
"""顯示打印好的模型"""
print('\nThe folloing models have been printed:')
for completed_model in completed_models: # 遍歷打印好的模型列表completed_models
print(completed_model)
unprinted_designs = ['iphone case', 'robot pendant', 'dodecahedron'] # 定義未打印的設(shè)計的列表
completed_models = [] # 定義已經(jīng)打印好的模型為空列表
printed_models(unprinted_designs, completed_models) # 調(diào)用函數(shù)觉啊,將列表傳遞給主函數(shù)
show_printed_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
1.4.2、禁止函數(shù)修改列表
有時需要禁止修改列表沈贝,因為修改是永久的杠人,如上個列子,修改未打印的設(shè)計中元素宋下,將其中的元素全部移到已經(jīng)打印的模型列表中嗡善,原來的列表就變?yōu)榭眨瑸榻鉀Q這個問題杨凑,可以在調(diào)用函數(shù)時滤奈,只傳遞列表的副本(切片)而不是原列表:
# 在上個列子中,可以在調(diào)用函數(shù)撩满,傳遞列表時蜒程,只傳遞列表的切片
# 格式為:function_name(list_name[:])
printed_models(unprinted_design[:], completed_models)
但是除非有充分理由需要保留原列表,否則盡量避免使用伺帘,因為可以使函數(shù)避免花時間去和內(nèi)存去創(chuàng)建副本昭躺,從而提高效率,在處理大型列表尤其如此伪嫁。
1.5领炫、傳遞任意數(shù)量的實參
有時不知需要接受多少個實參,好在python可以允許函數(shù)調(diào)用語句中收集任意數(shù)量的實參:
def make_pizza(*topping): # 形參名*topping的星號讓python創(chuàng)建一個名為tooping的空元組张咳,并將傳遞來的實參全部封裝在這個元組中
"""打印顧客點的所有配料"""
print(topping)
make_pizza('pepperoni')
make_pizza('mushrooms', 'green peppers', 'extra cheese')
----
('pepperoni') # 封裝成一個元組
('mushrooms', 'green peppers', 'extra cheese')
1.5.1帝洪、結(jié)合使用位置實參和任意數(shù)量實參
如果要讓函數(shù)接受不同類型的實參,必須將接受任意數(shù)量的實參放置在位置參數(shù)后面脚猾,python先匹配位置和關(guān)鍵字實參葱峡,再匹配任意數(shù)量的實參:
def make_pizza(size, *toppings): # 定義一個尺寸的位置形參,放在任意數(shù)量形參前
"""打印顧客點的所有配料"""
print('\nMaking a ' + str(size) + '-inch pizza with the following toppings: ')
for topping in toppings:
print('- ' + topping)
make_pizza(16, 'pepperoni')
make_pizza(20, 'mushrooms', 'green peppers', 'extra cheese')
------------
Making a 16-inch pizza with the following toppings:
- pepperoni
Making a 20-inch pizza with the following toppings:
- mushrooms
- green peppers
- extra cheese
1.5.2龙助、使用任意數(shù)量的關(guān)鍵字實參
有時砰奕,要接受任意數(shù)量的實參,但不知道傳遞給函數(shù)的會是什么信息,這種情況下军援,可以將函數(shù)寫成能夠接受任意數(shù)量的鍵-值對仅淑,調(diào)用語句提供了多少就接受多少:
下面列子,你將接受用戶信息胸哥,但不確定什么信息涯竟,函數(shù)build_profile()接受名和姓,同時還接受任意數(shù)量的關(guān)鍵字實參:
def build_profile(first, last, **user_info): # **user_info兩個星號讓python創(chuàng)建一個名為user_info的空字典烘嘱,并將接受到所有名稱-值對都封裝在其中
"""創(chuàng)建一個字典昆禽,其中包含我們知道的有關(guān)用戶的一切"""
profile = {} # 首先創(chuàng)建一個空字典,用以存儲用戶的名和姓
profile['first_name'] = first # 將名和姓添加到字典profile中
profile['last_name'] = last
for key, value in user_info.items(): # 遍歷user_info這個字典
profile[key] = value # 將每個鍵-值對添加到字典profile中
return profile # 返回字典profile到函數(shù)調(diào)用行蝇庭,并把它存儲到變量user_profile中
user_profile = build_profile('albert', 'einstein',
location='princeton',
field='physics') # 傳入實參(調(diào)用函數(shù))
print(user_profile)
在上面列子中,返回的字典包含了用戶的名和姓捡硅,已經(jīng)求學(xué)的地方和所學(xué)專業(yè)哮内,調(diào)用這個函數(shù)時,不管額外提供了多少鍵-值對壮韭,它都能正確處理北发。
練習(xí)
編寫一個函數(shù),將一輛汽車的信息存儲在一個字典中喷屋,這個函數(shù)始終接受制造商和型號琳拨,還接受關(guān)鍵字實參,調(diào)用這個函數(shù)屯曹,提供必不可少的信息以及兩個名稱-值對狱庇,如顏色、選擇配件等:
def make_car(manufacturer, model, **options): # **options接受任意數(shù)量的關(guān)鍵字實參恶耽,創(chuàng)建一個字典并將信息存儲在其中
"""做一個字典代表一輛車"""
car_dict = { # 創(chuàng)建一個字典能代表一輛車密任,其中有必不可少的 制造商型號等信息
'manufacturer': manufacturer.title(),
'model': model.title(),
}
for option, value in options.items(): # 遍歷字典options
car_dict[option] = value # 將其他信息諸如顏色等添加到字典car_dict中
return car_dict # 返回car_dict字典
car = make_car('subaru', 'outback', color='blue', tow_package=True)
print(car)
my_car = make_car('honda', 'accord', year=1991, color='white', headlights='popup')
print(my_car)
1.6、將函數(shù)存儲在模塊中
函數(shù)可以將代碼塊與主程序分離偷俭,這樣使程序更容易理解浪讳,還可以進一步將函數(shù)存儲到獨立的文件中(模塊),再將模塊帶入主程序中涌萤,這樣就可以將重點放在程序的高層邏輯上淹遵,可以與其他程序員共享這個文件而不是程序。
1.6.1负溪、導(dǎo)入整個模塊
模塊的拓展名為.py的文件透揣,包含要導(dǎo)入到程序中的代碼,下面來演示再另一個程序中調(diào)用第一個模塊里的函數(shù)笙以。
創(chuàng)建一個名為pizza.py的模塊淌实,里面包含make_pizza() 的函數(shù),再在模塊pizza.py所在目錄創(chuàng)建一個名為making_pizza.py的文件,在這個文件中導(dǎo)入剛創(chuàng)建的模塊拆祈,再調(diào)用make_pizza() 函數(shù)恨闪,調(diào)用模塊中函數(shù)格式:(模塊名.函數(shù)名,如pizza.make_pizza() ):
# pizza.py 模塊
def make_piza(size, *topping): # make_pizza() 函數(shù)
"""概述要制作的披薩"""
print('\nMaking a ' + str(size) + '-inch pizza with the following topping:')
for topping in toppings:
print('- ' + topping)
# making_pizza.py 文件
import pizza # 導(dǎo)入pizza模塊
pizza.make_pizza(16, 'fish') # 調(diào)用pizza.py模塊中的make_pizza()函數(shù)
pizza.make_pizza(20, 'egg', 'meat', 'fish')
----------------
Making a 12-inch pizza with the following topping:
- meat
- fish
- egg
1.6.2放坏、導(dǎo)入特定的函數(shù):
import 只是一種導(dǎo)入方式咙咽,還可以導(dǎo)入模塊中的特定函數(shù),其格式為:
from modul_name import function_name # from 模塊名 import 函數(shù)名
from modul_name import function_0, function_1, function_2 # 導(dǎo)入任意數(shù)量的函數(shù)
對于1.6.1的列子也可以使用這種導(dǎo)入方式:
from pizza import make_pizza
make_pizza(16, 'fish') # 因為import語句顯示地導(dǎo)入了函數(shù)名淤年,所以調(diào)用時不需要指定其名稱
1.6.3钧敞、使用 as 給函數(shù)指定別名
如果要導(dǎo)入的函數(shù)與現(xiàn)有函數(shù)名有沖突,或者函數(shù)名過長麸粮,可指定別名(用以代替函數(shù)名溉苛,類似于外號),只需在導(dǎo)入模塊時弄诲,(from modul_name import funtion_name as fn):
from pizza import make_pizza as mp # 給函數(shù)指定別名
mp(16, 'fish') # 調(diào)用時可以使用別名
1.6.4愚战、給模塊指定別名
也可以給模塊指定別名,其格式為:( import module_name as mn )
import pizza as p
p.make_pizza(16, 'fish')
1.6.5齐遵、導(dǎo)入模塊中所有函數(shù)
使用星號(*)可以讓python導(dǎo)入模塊中的所有函數(shù)寂玲,其格式為:
from modul_name import *
在大型模塊中,最好不要采用這種導(dǎo)入方式梗摇,如果模塊中有函數(shù)的名稱與你的項目有相同的拓哟,可能導(dǎo)致意想不到的結(jié)果,python處置名稱相同的函數(shù)或者變量時伶授,會進行覆蓋断序,最佳做法是,只導(dǎo)入需要的函數(shù)谎砾,要么整個模塊并使用句點表示法(即modul_name.function_name() )逢倍。
1.7、函數(shù)編寫指南
- 函數(shù)名景图,應(yīng)取具有描述性的名稱(即與實現(xiàn)函數(shù)功能相關(guān)的名稱)较雕,使用小寫字母與下劃線,模塊名亦如此挚币,這樣便于理解亮蒋。
- 每個函數(shù)應(yīng)有注釋,緊跟函數(shù)定義后面妆毕,采用文檔字符串格式慎玖。
- 給形參指定默認(rèn)值時,等號兩邊不用有空格笛粘,實參亦如此趁怔。
- PEP 8 建議代碼行長度不超過79個字符湿硝,如果形參很多,超過79個字符润努,可以在函數(shù)定義時輸入左括號后按回車鍵关斜,并在下一行按兩次Tab鍵,實質(zhì)上多數(shù)編輯器都能自動實現(xiàn)參數(shù)對齊铺浇,如下:
def function_name(
parameter_0, parameter_1, parameter_2,
parameter_3, parameter_4, parameter_5
):
- 如果程序或模塊包含多個函數(shù)痢畜,可使用兩個空行將相鄰的函數(shù)分開,這樣將更容易知道前一個函數(shù)在哪結(jié)束鳍侣,下一個函數(shù)在哪開始丁稀。
- 所有的import 語句都應(yīng)在開頭,唯一的列外的情形時倚聚,在文件開頭使用了注釋來描述整個程序线衫。