1. 函式定義
Python使用關鍵字def來定義函式,語法為:
def function_name(param1,param2):
"""檔案字串"""
函式體
栗子:
def greet_user():
"""顯示簡單的問候語"""
print("Hello!")
檔案字串用于描述函式做了什么,
1.1 向函式傳遞引數
現對函式做簡單的修改,讓函式不只會顯示hello,
def greet_user(username):
"""顯示簡單的問候語"""
print("Hello!" + username + ".")
呼叫函式:
greet_user("Jack")
輸出:
Hello!Jack
1.2 實參和形參
在函式greet_user()的定義中,變數username是一個形參–函式完成其作業所需要的一項資訊,
在代碼greet_user(‘Jack’)中,'Jack’是一個實參,實參是呼叫函式時傳遞給函式的資訊,當呼叫函式時,將要讓函式使用的資訊放在括號內,
在greet_user(‘Jack’)中,將實參’Jack’傳遞給函式greet_user(),這個值被存盤在形參username中,
2. 傳遞實參
函式定義中可能包含多個形參,因此也可能包含多個實參,向函式傳遞實參的方式很多:
可以使用位置實參,這要求實參的順序與形參的順序相同,
可以是使用關鍵字實參,其中每個實參都由變數名和值組成,
還可以使用串列和字典,
2.1 位置實參
呼叫函式時,Python必須將函式呼叫的每個實參都關聯到函式定義中的一個形參,這就要求實參的順序與形參的順序要一致,
下面來看一個顯示寵物資訊的函式,
def describe_pet(animal_type,pets_name):
"""顯示寵物資訊"""
print("I have a " + animal_type + "!")
print("its name was " + pets_name + ".")
呼叫函式:
describe_pet("dog","哈哈")
輸出:
I have a dog!
its name was 哈哈.
位置實參的順序很重要,如果實參放錯了順序將會導致違背我們預期的結果:
def describe_pet(animal_type,pets_name):
"""顯示寵物資訊"""
print("I have a " + animal_type + "!")
print("its name was " + pets_name + ".")
呼叫函式:
describe_pet("哈哈","dog")
輸出:
I have a 哈哈!
its name was dog.
2.2 關鍵字實參
關鍵之實參是傳遞給函式的名稱-值對,直接在實參中將名稱和值關聯起來,無需考慮傳遞的實參的順序,
就上面的例子使用關鍵字實參:
def describe_pet(animal_type,pets_name):
"""顯示寵物資訊"""
print("I have a " + animal_type + "!")
print("its name was " + pets_name + ".")
呼叫函式:
describe_pet(animal_type = "dog",pets_name = "哈哈")
輸出:
I have a dog!
its name was 哈哈.
2.3 默認值
撰寫函式時,可以給每個形參都設定默認值,在呼叫函式時,如果給函式中的形參指定了實參,Python就會使用指定的實參,如果不指定的話就會使用默認的形參,
還是對寵物的例子,我們修改一下形參的順序,將animal_type放在第二個形參的位置:
def describe_pet(pets_name,animal_type=“dog”):
"""顯示寵物資訊"""
print("I have a " + animal_type + "!")
print("its name was " + pets_name + ".")
呼叫函式:
describe_pet(“哈哈”)
輸出:
I have a dog!
its name was 哈哈.
上面代碼中已經給animal_type指定了默認值’dog’,所以在函式呼叫的時候,如果animal_type是’dog’的話,就不要指定實參了,在呼叫函式的時候,只指定了一個實參’哈哈’,但是這個實參還是位置實參,也就是關聯到pets_name,這也就是為什么將默認值animal_type放在后面的原因,
2.4 避免實參錯誤
在使用函式后,如果提供的實參多出或者少于形參都會導致錯誤:
# 避免實參錯誤
def describe_pet(animal_type, pet_name):
"""describe_pet imformation"""
print("I have a " + animal_type + ".")
print("My " + animal_type + "'s name is " + pet_name.title() + ".")
呼叫函式:
describe_pet()
由于沒有給函式傳遞實際引數,所以程式報錯:
Traceback (most recent call last):
File "C:/Users/ASUS/PycharmProjects/Test_Program/Note.py", line 8, in <module>
describe_pet()
TypeError: describe_pet() missing 2 required positional arguments: 'animal_type' and 'pet_name'
報錯解讀:
TypeError: describe_pet() missing 2 required positional arguments: 'animal_type' and 'pet_name'
程式提示呼叫函式時缺少2個位置引數,分別是“animal_type”和“pet_name”,
3.回傳值
函式并不是總是直接顯示輸出,相反,它可以處理一些資料,回傳一個或者一組值,函式回傳的值被稱為回傳值,在函式中,可以使用return陳述句將值回傳到呼叫函式的代碼行,
3.1 回傳簡單值
下面是一個回傳完整姓名的函式,注意:英語的first_name是中文姓名里面的名,last_name是姓,
def get_formatted_name(first_name, last_name):
"""return_formatted_name"""
full_name = first_name + " " + last_name
return full_name.title()
呼叫函式:
musician = get_formatted_name("ma", "jack")
print(musician)
輸出:
Ma Jack
呼叫回傳值的函式時,需要提供一個變數,用于存盤回傳的值,在這里,回傳的值存盤在了變數musician中,
3.2 讓實參變成可選的
擴展上面的函式,讓這個函式還可以處理帶有中間名的姓名:
def get_formatted_name(first_name, middle_name, last_name):
"""return_formatted_name"""
full_name = first_name + " " + middle_name + " " + last_name
return full_name.title()
呼叫函式:
musician = get_formatted_name("ma", "jack", "yun")
print(musician)
輸出:
Ma Yun Jack
上面這個函式有一個問題,所有人都有名(first_name)和姓(last_name),但是不是所有人都有中間名(middle_name),所以,要讓中間名(middle_name)變成可選的,因為傳遞實參的時候,如果不是是要關鍵字實參傳遞的話,需要將默認值放在形參的最后面,
def get_formatted_name(first_name, last_name, middle_name = ""):
"""return_formatted_name"""
if middle_name:
full_name = first_name + " " + middle_name + " " + last_name
else:
full_name = first_name + " " + last_name
return full_name.title()
呼叫函式:
musician1 = get_formatted_name("ma", "jack", "yun")
musician2 = get_formatted_name("ma", "jack")
print("musician1:" + musician1 + "\nmusician2:" + musician2)
輸出:
musician1:Ma Yun Jack
musician2:Ma Jack
在上面的函式體中,我們檢查了是否提供中間名,Python將非空字串解讀為True,所以如果函式呼叫中提供了中間名,if middle_name將為True,如果沒有提供中間名,middle_name將為空字串,導致if測驗未通過,進而執行else代碼塊,
3.3 回傳字典
函式可以回傳任何型別的值,包括串列和字典等復雜的資料型別,
def build_person(first_name, last_name):
"""回傳一個字典,包含個人資訊"""
person = {"first":first_name, "last":last_name}
return person
呼叫函式:
musician = build_person("ma", "jack")
print(musician)
輸出:
{'first': 'ma', 'last': 'jack'}
對上面函式做擴展,使其可以接收年齡:
def build_person(first_name, last_name, age=""):
"""回傳一個字典,包含個人資訊"""
if age:
person = {"first":first_name, "last":last_name, "age":age}
else:
person = {"first": first_name, "last": last_name}
return person
呼叫函式:
musician = build_person("ma", "jack", 18)
print(musician)
輸出:
{'first': 'ma', 'last': 'jack', 'age': 18}
3.4 結合使用函式和while回圈
下面結合使用函式get_formatted_name和while回圈,
def get_formatted(first_name, last_name):
"""回傳一個完整的姓名"""
full_name = first_name + " " + last_name
return full_name.title()
while True:
print("Please tell me your name:")
f_name = input("first_name: ")
l_name = input("last_name: ")
formatted_name = get_formatted(f_name,l_name)
print("\nHello, " + formatted_name + "!")
輸出:
Please tell me your name:
first_name: ma
last_name: jack
Hello, Ma Jack!
Please tell me your name:
first_name:
上面程式存在兩個問題:第一,遇到有中間名的姓名就不可以了;第二,沒有定義退出條件,我們應該在每次用戶輸入時,都應該提供一個簡單的退出途徑,
def get_formatted(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()
while True:
print("Please tell me your name.")
print("If you want to quit,enter 'q'!")
f_name = input("first_name: ")
if f_name == 'q':
break
print("If you don't have a middle_name,enter 'Enter' key to pass!")
m_name = input("middle_name: ")
if m_name == 'q':
break
l_name = input("last_name: ")
if l_name == 'q':
break
formatted_name = get_formatted(f_name, l_name, m_name)
print("\nHello, " + formatted_name + "!")
輸出:
If you want to quit,enter 'q'!
first_name: ma
If you don't have a middle_name,enter 'Enter' key to pass!
middle_name: yun
last_name: jack
Hello, Ma Yun Jack!
Please tell me your name.
If you want to quit,enter 'q'!
first_name:
4.傳遞串列
將串列傳遞給函式以后,函式就可以直接訪問其內容,假設有一個用戶串列,我們要問候其中的每個人,
def greet_user(names):
"""向串列中的每位用戶發出問候"""
for name in names:
print("Hello," + name + "!")
usernames = ["Jack", "Nacy", "Mary"]
greet_user(usernames)
輸出:
Hello,Jack!
Hello,Nacy!
Hello,Mary!
4.1 在函式中修改串列
串列傳遞給函式后,函式可以對其進行修改,這些修改都是永久性的,這樣可以極大的提高作業效率,
下面這個例子來看一家為用戶提交的設計制作的3D列印模型的公司,需要列印的設計存盤在一個串列中,列印后轉移到另一個串列中,
未使用函式撰寫的代碼:
unprinted_designs = ['iphone case', 'robot pendant', 'dodecahedron']
completed_modles = []
# 模擬列印每個設計,直到沒有未列印的為止
# 列印每個設計后,都將其移動到一個串列中
while unprinted_designs:
current_design = unprinted_designs.pop()
# 模擬根據設計制作3D列印的程序
print("Printing modles:" + current_design)
completed_modles.append(current_design)
print("\nThe following modles have been printed:")
for completed_modle in completed_modles:
print(completed_modle)
輸出:
Printing modles:dodecahedron
Printing modles:robot pendant
Printing modles:iphone case
The following modles have been printed:
dodecahedron
robot pendant
iphone case
下面創建兩個函式,一個用于列印設計,一個用于展示設計:
def print_modles(unprinted_designs, completed_modles):
"""
模擬列印每個設計,直到沒有未列印為止
列印每個設計后,都將其移動到串列completed_modles中
"""
while unprinted_designs:
current_design = unprinted_designs.pop()
# 模擬根據設計制作3D列印的程序
print("Printing modles:" + current_design)
completed_modles.append(current_design)
def show_modles(completed_modles):
"""顯示列印好的所有模型"""
print("\nThe following modles have been printed:")
for completed_modle in completed_modles:
print(completed_modle)
unprinted_designs = ['iphone case', 'robot pendant', 'dodecahedron']
completed_modles = []
print_modles(unprinted_designs, completed_modles)
show_modles(completed_modles)
輸出:
Printing modles:dodecahedron
Printing modles:robot pendant
Printing modles:iphone case
The following modles have been printed:
dodecahedron
robot pendant
iphone case
4.2 禁止函式修改串列
對于上面的程式,可能處于這樣的需要,即便列印所有設計后,也要保留原來未列印的設計串列,已供備案,為解決這個問題,可以向函式傳遞串列的副本而不是原件,這樣函式所做的任何修改都是只影響副本,
使用切片創建串列的副本,可以像下面這樣呼叫print_models():
print_modles(unprinted_designs[:], completed_modles)
5.傳遞任意數量的實參
來看一個制作比薩的函式,它需要接受很多的配料,但是無法預先知道顧客需要幾種配料,下面的函式只有一個形參*toppings,不管呼叫陳述句傳入多少個實參,這個形參都統統納入囊中:
def make_pizza(*toppings):
"""列印顧客點的所有配料"""
print(toppings)
呼叫函式:
make_pizza('pepperoni')
make_pizza('mushrooms', 'green peppers', 'extra cheese')
輸出:
('pepperoni',)
('mushrooms', 'green peppers', 'extra cheese')
形參名*toppings中的星號讓Python創建一個名為toppings的空元組,并將所有收到的值都封裝進這個元組中,
現在,我們可以將這條print陳述句修改為一個回圈,對配料串列進行遍歷,并對顧客點的比薩進行描述:
def make_pizza(*toppings):
"""列印顧客點的所有配料"""
print("\nMaking a pizza with the following toppings:")
for topping in toppings:
print(toppings)
呼叫函式:
make_pizza('pepperoni')
make_pizza('mushrooms', 'green peppers', 'extra cheese')
輸出:
Making a pizza with the following toppings:
-pepperoni
Making a pizza with the following toppings:
-mushrooms
-green peppers
-extra cheese
5.1 結合使用位置實參和任意數量實參
如果要讓函式接受不同型別的實參,必須在函式定義中將接納任意數量實參的形參放在最后,Python先匹配位置實參和關鍵字實參,再將余下的實參都收集到最后一個形參中,
修改上面的函式,還需要一個表示比薩餅尺寸的實參,必須將該形參放在形參*topping的前面,
def make_pizza(size, *toppings):
"""列印顧客點的所有配料"""
print("\nMaking a " + str(size) + "-inch pizza with the following toppings:")
for topping in toppings:
print("-" + topping)
呼叫函式:
make_pizza(10, 'pepperoni')
make_pizza(3, 'mushrooms', 'green peppers', 'extra cheese')
輸出:
Making a 10-inch pizza with the following toppings:
-pepperoni
Making a 3-inch pizza with the following toppings:
-mushrooms
-green peppers
-extra cheese
5.2 使用任意數量的關鍵字實參
有時候,需要接受任意數量的實參,但是預先不知道傳遞給函式的會是什么樣的資訊,這個時候,可將函式撰寫成能夠接受任意數量的鍵值對,呼叫陳述句提供多少就接受多少,
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('ma', 'jack', location = 'HanZhou', age=18)
print(user_profile)
輸出:
{'first_name': 'ma', 'last_name': 'jack', 'location': 'HanZhou', 'age': 18}
6. 將函式存盤在模塊中
函式的優點之一是,使用它們可將代碼塊與主程式分離,通過給函式指定描述性名稱,可讓主程式容易理解的多,將函式存盤在稱為模塊的獨立檔案中,再將模塊匯入到主程式,import陳述句允許在當前運行的程式檔案中使用模塊中的代碼,
通過將函式存盤在獨立檔案中,可以隱藏代碼的細節,將重點放在程式的高層邏輯上,還可以在不同的程式中重用函式,也可與其他程式員共享這個檔案而不是整個程式,
6.1 匯入整個模塊
要讓函式是可以匯入的,得先創建模塊,模塊是擴展名為.py的檔案,包含要匯入到程式中代碼,下面來創建一個包含函式make_pizza()的模塊,并將其存盤為pizza.py
def make_pizza(size, *toppings):
"""列印顧客點的所有配料"""
print("\nMaking a " + str(size) + "-inch pizza with the following toppings:")
for topping in toppings:
print("-" + topping)
在pizza.py所在的目錄創建一個名為making_pizzas.py的檔案,在這個檔案里面匯入剛剛創建的模塊,再呼叫make_pizza()兩次,
import pizza
pizza.make_pizza(16, 'pepperoni')
pizza.make_pizza(21, 'mushrooms', 'green peppers', 'extra cheese')
匯入模塊和使用模塊中的函式的語法:
import module
module_name.function_name()
6.2 匯入特定函式
如果一個模塊中函式太多,還可以只匯入模塊中的特定函式:
from module_name import function_name
通過使用逗號分隔函式名,可根據需要從模塊中匯入任意數量的函式:
from module_name import function_0,fuction_1,function_2
對于前面的making_pizza.py示例,如果只想匯入想要的函式,可像下面這樣操作:
from pizza import make_pizza
pizza.make_pizza(16, 'pepperoni')
pizza.make_pizza(21, 'mushrooms', 'green peppers', 'extra cheese')
6.3 使用as給函式指定別名
當函式名過長時,給函式指定別名,在呼叫函式時更輕松,
from pizza import make_pizza as mp
mp(16, 'pepperoni')
mp(21, 'mushrooms', 'green peppers', 'extra cheese')
指定別名的通用語法如下:
from module_name import function_name as fn
6.4 使用as給模塊指定別名
除了可以給函式指定別名,還可以給模塊指定別名:
import pizza as p
p.make_pizza(16, 'pepperoni')
p.make_pizza(21, 'mushrooms', 'green peppers', 'extra cheese')
給模塊指定別名的通用語法:
import module_name as mn
6.5 匯入模塊中的所有函式
使用星號(*)可以讓Python匯入模塊中的所有函式:
from pizza import *
make_pizza(16, 'pepperoni')
make_pizza(21, 'mushrooms', 'green peppers', 'extra cheese')
匯入所有模塊的通用語法:
from module_name import *
使用并非自己撰寫的大型模塊時,最好不要采用這種匯入方法:如果模塊中有函式的名稱與你專案中使用的名稱相同,可能導致意想不到的結果,
7.函式撰寫指南
①應給函式指定描述性的名稱,且只在其中使用小寫字母和下劃線,給模塊命名是也一樣,
②每個函式都應該包含簡要的闡述其功能的注釋,且注釋要跟在函式定義的后面,并采用檔案字串格式,
③給形參指定默認值時,等號兩邊不要有空格:
def function_name(parameter_0,parameter_1='default_value')
對于函式呼叫中的關鍵字實參,也應該遵循這種約定:
function_name(value_0,parameter_1='value')
④建議代碼行的長度不要超過79個字符,如果形參很多,導致函式定義超過了79個字符,可在函式定義中輸入左括號后按回車鍵,并在下一行按兩次Tab鍵,從而將形參和只縮進一層的函式體區分開來,
def function_name(
parameter_0, parameter_1, parameter_2,
parameter_3, parameter_4, parameter_5):
function body..
⑤如果程式或者模塊中包含多個函式,可以使用兩個空行將相鄰的函式分開,
⑥所有的import陳述句都應該放在開頭,
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/180880.html
標籤:其他
