python程式設計:從入門到實踐 (第一版) 第八章學習筆記
第8章:函式
8.1 定義函式
def greet_user():
"""顯示簡單的問候語"""
print("Hello!")
greet_user()
8.1.1 向函式傳遞資訊
def greet_user(username):
"""顯示簡單的問候語"""
print("Hello, " + username.title() + ".")
greet_user('bruce')
8.1.2 形參和實參
在函式greet_user() 的定義中,變數username 是一個形參 ——函式完成其工作所需的一項資訊。在程式碼greet_user(‘bruce’) 中,值’bruce’ 是一個實參 。實參是呼叫函式時傳遞給函式的資訊。我們呼叫函式時,將要讓函式使用的資訊放在括號內。在greet_user(‘bruce’) 中,將實參’bruce’ 傳遞給了函式greet_user() ,這個值被儲存在形參username 中。
8.2 傳遞實參
鑑於函式定義中可能包含多個形參,因此函式呼叫中也可能包含多個實參。向函式傳遞實參的方式很多,可使用位置實參 ,這要求實參的順序與形參的順序相同;也可使用關鍵字實參 ,其中每個實參都由變數名和值組成;還可使用列表和字典。下面來依次介紹這些方式。
8.2.1 位置實參
示例
def discribe_pet(animal_type, pet_name):
"""顯示寵物資訊"""
print("I have a " + animal_type +".")
print("My " + animal_type + "'s name is " + pet_name.title() + ".")
discribe_pet('cat', 'tom')
輸出:
I have a cat.
My cat's name is Tom.
呼叫函式多次
def discribe_pet(animal_type, pet_name):
"""顯示寵物資訊"""
print("I have a " + animal_type +".")
print("My " + animal_type + "'s name is " + pet_name.title() + ".")
discribe_pet('cat', 'tom')
discribe_pet('mouse', 'jerry')
位置實參的順序很重要
使用位置實參來呼叫函式時,如果實參的順序不正確,結果可能出乎意料:
def discribe_pet(animal_type, pet_name):
"""顯示寵物資訊"""
print("I have a " + animal_type +".")
print("My " + animal_type + "'s name is " + pet_name.title() + ".")
discribe_pet('tom', 'cat')
輸出:
I have a tom.
My tom's name is Cat.
8.2.2 關鍵字實參
關鍵字實參是傳遞給函式的名稱—值對。你直接在實參中將名稱和值關聯起來了,因此向函式傳遞實參時不會混淆
def discribe_pet(animal_type, pet_name):
"""顯示寵物資訊"""
print("I have a " + animal_type +".")
print("My " + animal_type + "'s name is " + pet_name.title() + ".")
discribe_pet(animal_type = 'cat', pet_name = 'tom')
print("=====================")
discribe_pet(pet_name = 'tom', animal_type = 'cat')
輸出:
I have a cat.
My cat's name is Tom.
=====================
I have a cat.
My cat's name is Tom.
關鍵字實參的順序無關緊要,因為Python知道各個值該儲存到哪個形參中。由上面的結果可以看到,下面兩個函式呼叫是等價的:
discribe_pet(animal_type = 'cat', pet_name = 'tom')
discribe_pet(pet_name = 'tom', animal_type = 'cat')
8.2.3 預設值
編寫函式時,可給每個形參指定預設值 。在呼叫函式中給形參提供了實參時,Python將使用指定的實參值。
def describe_pet(pet_name, animal_type='dog'):
"""顯示寵物的資訊"""
print("\nI have a " + animal_type + ".")
print("My " + animal_type + "'s name is " + pet_name.title() + ".")
describe_pet(pet_name='willie')
輸出:
I have a dog.
My dog's name is Willie.
如果要描述的動物不是小狗,可使用類似於下面的函式呼叫:
describe_pet(pet_name='jerry', animal_type='mouse')
由於顯式地給animal_type 提供了實參,因此Python將忽略這個形參的預設值。
注意: 使用預設值時,在形參列表中必須先列出沒有預設值的形參,再列出有預設值的實參。這讓Python依然能夠正確地解讀位置實參。
8.2.4 等效的函式呼叫
鑑於可混合使用位置實參、關鍵字實參和預設值,通常有多種等效的函式呼叫方式。請看下面的函式describe_pets() 的定義,其中給一個形參提供了預設值:
def describe_pet(pet_name, animal_type='dog'):
幾種呼叫的示例:
# 一條名為Willie的小狗
describe_pet('willie')
describe_pet(pet_name='willie')
# 一隻名為Harry的倉鼠
describe_pet('harry', 'hamster')
describe_pet(pet_name='harry', animal_type='hamster')
describe_pet(animal_type='hamster', pet_name='harry')
8.2.5 避免實參錯誤
你提供的實參多於或少於函式完成其工作所需的資訊時,將出現實參不匹配錯誤。這時python會報錯,可以根據traceback 來分析
8.3 返回值
函式並非總是直接顯示輸出,相反,它可以處理一些資料,並返回一個或一組值。函式返回的值被稱為返回值 。在函式中,可使用return 語句將值返回到呼叫函式的程式碼行。返回值讓你能夠將程式的大部分繁重工作移到函式中去完成,從而簡化主程式。
8.3.1 返回簡單值
def get_formatted_name(first_name, last_name):
"""返回整潔的姓名"""
full_name = first_name + " " + last_name
return full_name.title()
musician = get_formatted_name('bruce', 'zhang')
print(musician)
8.3.2 讓實參變成可選的
有時候,需要讓實參變成可選的,這樣使用函式的人就只需在必要時才提供額外的資訊。可使用預設值來讓實參變成可選的。
例如,假設我們要擴充套件函式get_formatted_name() ,使其還處理中間名。為此,可將其修改成類似於下面這樣:
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)
呼叫這個函式時,如果只想指定名和姓,呼叫起來將非常簡單。如果還要指定中間名,就必須確保它是最後一個實參,這樣Python才能正確地將位置實參關聯到形參。
8.3.3 返回字典
函式可返回任何型別的值,包括列表和字典等較複雜的資料結構。
def build_person(first_name, last_name):
person = {'first': first_name, 'last': last_name}
return person
musician = build_person('bruce', 'zhang')
print(musician)
你可以輕鬆地擴充套件這個函式,使其接受可選值,如中間名、年齡、職業或你要儲存的其他任何資訊。例如,下面的修改讓你還能儲存年齡:
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('bruce', 'zhang', 22)
print(musician)
8.3.4 結合使用函式和while 迴圈
def get_formatted_name(first_name, last_name):
"""返回整潔的姓名"""
full_name = first_name.title() + " " + last_name.title()
return full_name
while True:
print("Please tell me your name: ")
print("Enter 'q' anytime 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(formatted_name)
8.4 傳遞列表
假設有一個使用者列表,我們要問候其中的每位使用者
def greet_users(names):
"""向列表中的每位使用者都發出簡單的問候"""
for name in names:
print("Hello, " + name.title() + ",welcome to you.")
names = ['tom', 'jack', 'bruce']
greet_users(names)
8.4.1 在函式中修改列表
來看一家為使用者提交的設計製作3D列印模型的公司。需要列印的設計儲存在一個列表中,列印後移到另一個列表中。
# 首先建立一個列表,其中包含一些要列印的設計
unprinted_designs = ['iphone case', 'robot pendant', 'dodecahedron']
completed_models = []
# 模擬列印每個設計,直到沒有未列印的設計為止
# 列印每個設計後,都將其移到列表completed_models中
while unprinted_designs:
current_design = unprinted_designs.pop()
#模擬根據設計製作3D列印模型的過程
print("Printing model: " + current_design)
completed_models.append(current_design)
# 顯示列印好的所有模型
print("\nThe following models have been printed:")
for completed_model in completed_models:
print(completed_model)
為重新組織這些程式碼,我們可編寫兩個函式,每個都做一件具體的工作。第一個函式將負責處理列印設計的工作,而第二個將概述列印了哪些設計:
def print_models(unprinted_designs, completed_models):
"""# 列印每個設計後,都將其移到列表completed_models中"""
while unprinted_designs:
current_design = unprinted_designs.pop()
#模擬根據設計製作3D列印模型的過程
print("Printing model: " + current_design)
completed_models.append(current_design)
def show_completed_models(completed_models):
"""顯示列印好的所有模型"""
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)
8.4.2 禁止函式修改列表
你可能會做出這樣的決定:即便列印所有設計後,也要保留原來的未列印的設計列表,以供備案。
要將列表的副本傳遞給函式,可以像下面這樣做:
function_name(list_name[:])
在8.4.1中,如果不想清空未列印的設計列表,可像下面這樣呼叫print_models() :
print_models(unprinted_designs[:], completed_models)
8.5 傳遞任意數量的實參
有時候,你預先不知道函式需要接受多少個實參,好在Python允許函式從呼叫語句中收集任意數量的實參。
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 的空元組,並將收到的所有值都封裝到這個元組中。
def make_pizza(*toppings):
"""列印顧客點的所有配料"""
print("\nMaking a pizza with the following toppings:")
for topping in toppings:
print("-" + topping)
make_pizza('pepperoni')
make_pizza('mushrooms', 'green peppers', 'extra cheese')
8.5.1 結合使用位置實參和任意數量實參
如果要讓函式接受不同型別的實參,必須在函式定義中將接納任意數量實參的形參放在最後。Python先匹配位置實參和關鍵字實參,再將餘下的實參都收集到最後一個形參中。
如果前面的函式還需要一個表示比薩尺寸的實參,必須將該形參放在形參*toppings 的前面:
def make_pizza(size, *toppings):
"""列印顧客點的所有配料"""
print("\nMaking a " + str(size) +"-inch pizza with the following toppings:")
for topping in toppings:
print("-" + topping)
make_pizza(9, 'pepperoni')
make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
8.5.2 使用任意數量的關鍵字實參
有時候,需要接受任意數量的實參,但預先不知道傳遞給函式的會是什麼樣的資訊。在這種情況下,可將函式編寫成能夠接受任意數量的鍵—值對——呼叫語句提供了多少就接受多少。
def build_profile(first, last, **user_profile):
"""建立一個字典,其中包含我們知道的有關使用者的一切"""
profile = {}
profile['first'] = first
profile['last'] = last
for key, value in user_profile.items():
profile[key] = value
return profile
user_profile = build_profile('albert', 'einstein', location='princeton', field='physics')
print(user_profile)
形參**user_info 中的兩個星號讓Python建立一個名為user_info 的
空字典,並將收到的所有名稱—值對都封裝到這個字典中。
8.6 將函式儲存在模組中
函式的優點之一是,使用它們可將程式碼塊與主程式分離。通過給函式指定描述性名稱,可讓主程式容易理解得多。你還可以更進一步,將函式儲存在被稱為模組 的獨立檔案中,再將模組匯入 到主程式中。import 語句允許在當前執行的程式檔案中使用模組中的程式碼。
通過將函式儲存在獨立的檔案中,可隱藏程式程式碼的細節,將重點放在程式的高層邏輯上。這還能讓你在眾多不同的程式中重用函式。將函式儲存在獨立檔案中後,可與其他程式設計師共享這些檔案而不是整個程式。知道如何匯入函式還能讓你使用其他程式設計師編寫的函式庫。
8.6.1 匯入整個模組
要讓函式是可匯入的,得先建立模組。模組 是副檔名為.py的檔案,包含要匯入到程式中的程式碼。
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() 兩次:
making_pizzas.py
import pizza
pizza.make_pizza(12, 'pepperoni')
pizza.make_pizza(16, 'mushrooms', 'green peppers', 'extra cheese')
這就是一種匯入方法:只需編寫一條import 語句並在其中指定模組名,就可在程式中使用該模組中的所有函式。如果你使用這種import 語句匯入了名為module_name.py 的整個模組,就可使用下面的語法來使用其中任何一個函式:
module_name.function_name()
8.6.2 匯入特定的函式
你還可以匯入模組中的特定函式,這種匯入方法的語法如下:
from module_name import function_name
通過用逗號分隔函式名,可根據需要從模組中匯入任意數量的函式:
from module_name import function_1,function_2,function_3...
對於前面的making_pizzas.py示例,如果只想匯入要使用的函式,程式碼將類似於下面這樣:
from pizza import make_pizza
make_pizza(12, 'pepperoni')
make_pizza(16, 'mushrooms', 'green peppers', 'extra cheese')
若使用這種語法,呼叫函式時就無需使用句點。由於我們在import 語句中顯式地匯入了函式make_pizza() ,因此呼叫它時只需指定其名稱。
8.6.3 使用as 給函式指定別名
如果要匯入的函式的名稱可能與程式中現有的名稱衝突,或者函式的名稱太長,可指定簡短而獨一無二的別名 ——函式的另一個名稱,類似於外號。要給函式指定這種特殊外號,需要在匯入它時這樣做。
下面給函式make_pizza() 指定了別名mp() 。這是在import 語句中使用make_pizza as mp 實現的,關鍵字as 將函式重新命名為你提供的別名:
from pizza import make_pizza as mp
mp(12, 'pepperoni')
mp(16, 'mushrooms', 'green peppers', 'extra cheese')
指定別名的通用語法如下:
from module_name import function_name as fn
8.6.4 使用as 給模組指定別名
你還可以給模組指定別名。通過給模組指定簡短的別名(如給模組pizza 指定別名p ),讓你能夠更輕鬆地呼叫模組中的函式。
import pizza as p
p.make_pizza(12, 'pepperoni')
p.make_pizza(16, 'mushrooms', 'green peppers', 'extra cheese')
給模組指定別名的通用語法如下:
import module_name as mn
8.6.5 匯入模組中的所有函式
使用星號(* )運算子可讓Python匯入模組中的所有函式:
from pizza import *
make_pizza(12, 'pepperoni')
make_pizza(16, 'mushrooms', 'green peppers', 'extra cheese')
使用並非自己編寫的大型模組時,最好不要採用這種匯入方法:如果模組中有函式的名稱與你的專案中使用的名稱相同,可能導致意想不到的結果:Python可能遇到多個名稱相同的函式或變數,進而覆蓋函式,而不是分別匯入所有的函式。
最佳的做法是,要麼只匯入你需要使用的函式,要麼匯入整個模組並使用句點表示法。
匯入模組中的所有函式的通用語法如下:
from module_name import *
8.7 函式編寫指南
編寫函式時,需要牢記幾個細節。應給函式指定描述性名稱,且只在其中使用小寫字母和下劃線。描述性名稱可幫助你和別人明白程式碼想要做什麼。給模組命名時也應遵循上述約定。
給形參指定預設值時,等號兩邊不要有空格:
def function_name(parameter_0, parameter_1='default value')
對於函式呼叫中的關鍵字實參,也應遵循這種約定:
function_name(value_0, parameter_1='value')
習題
8-1
def display_message():
print("害,本章學了好多東西。")
display_message()
8-2
def favorite_book(title):
print("One of my favorite book is " + title + ".")
favorite_book("Harry Potter")
8-3
def make_shirt(size, typeface):
print("This is a " + size + " shirt.\nIts typeface is " + typeface + ".")
#位置實參
make_shirt('L','GOOGLE')
print("=====================")
#關鍵字實參
make_shirt(size='L', typeface='GOOGLE')
8-4
def make_shirt(size, typeface='I love Python'):
print("This is a " + size + " shirt.\nIts typeface is " + typeface + ".")
make_shirt('L')
print("=================")
make_shirt('M')
print("=================")
make_shirt('S', 'I know nothing')
8-5
def discribe_city(city, country='China'):
print(city.title() + " is in " + country + ".")
discribe_city('wuhan')
discribe_city('beijing')
discribe_city('tokyo', 'Japan')
8-6
def city_country(city, country):
full_city_country = city + ", " + country
return full_city_country
print(city_country('Beijing', 'China'))
print(city_country('Tokyo', 'japan'))
print(city_country('Paris', 'France'))
8-7
def make_album(singer, album_name):
"""製作一張專輯"""
album = {'singer': singer, 'album_name': album_name}
return album
print(make_album('林俊杰', '不為誰而作的歌'))
print(make_album('back number', 'Sister'))
print(make_album('周杰倫', '八度空間'))
# 可選形參
def make_album(singer, album_name, number=''):
"""製作一張專輯"""
album = {'singer': singer, 'album_name': album_name}
if number:
album['number'] = number
return album
print(make_album('林俊杰', '不為誰而作的歌', 8))
print(make_album('back number', 'Sister'))
print(make_album('周杰倫', '八度空間'))
8-8
def make_album(singer, album_name, number=''):
album = {'singer': singer, 'album_name': album_name}
if number:
album['number'] = number
return album
while True:
print("您好,可以問一下您最喜歡的專輯嗎?(輸入'q'可以退出程式)")
singer = input("singer: ")
if singer == 'q':
break
album_name = input("album_name: ")
if album_name == 'q':
break
your_album = make_album(singer, album_name)
print(your_album)
8-9
def show_magicians(names):
for name in names:
print(name.title())
magicians = ['tom', 'jack', 'bruce']
show_magicians(magicians)
8-10
# 先貼上我的錯誤做法,無法改變原列表magicians,不符合題目要求
def show_magicians(names):
for name in names:
print(name.title())
def make_great(magicians):
for magician in magicians:
magician = "the Great " + magician
magicians = ['tom', 'jack', 'bruce']
make_great(magicians)
show_magicians(magicians)
發現知乎上有關於這題的討論,參考連結
要點: 要修改列表元素的值,必須使用索引,即:
magicians[i] = "The great " + magicians[i]
下面是符合題目要求的做法:
def show_magicians(names):
for name in names:
print(name.title())
def make_great(magicians):
for i in range(len(magicians)):
magicians[i] = "the Great " + magicians[i]
magicians = ['tom', 'jerry', 'jack']
make_great(magicians)
show_magicians(magicians)
8-11
#傳遞magicians的副本就可以
def show_magicians(names):
for name in names:
print(name.title())
def make_great(magicians, great_magicians):
for i in range(len(magicians)):
magicians[i] = "the Great " + magicians[i]
great_magicians.append(magicians[i])
magicians = ['tom', 'jack', 'bruce']
great_magicians = []
make_great(magicians[:], great_magicians)
show_magicians(great_magicians)
show_magicians(magicians)
8-12
def make_sandwich(*toppings):
print("\nWe will add these things for your sandwich:")
for topping in toppings:
print("-" + topping)
make_sandwich('mushrooms', 'green peppers')
make_sandwich('mushrooms', 'pepperoni', 'extra cheese')
8-13
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('bruce', 'zhang',
country='China',
province='hubei',
age=18)
print(user_profile)
8-14
def make_car(manufacturer, car_type, **others):
"""建立一個字典,其中包含我們知道的關於車的一切"""
profile = {}
profile['manufacturer'] = manufacturer
profile['car_type'] = car_type
for key, value in others.items():
profile[key] = value
return profile
car_profile = make_car('subaru', 'outback', color='blue', tow_package=True)
print(car_profile)
相關文章
- python程式設計:從入門到實踐學習筆記-字典Python程式設計筆記
- python程式設計:從入門到實踐學習筆記-函式Python程式設計筆記函式
- 《python 程式設計從入門到實踐》序:學習目標Python程式設計
- python程式設計:從入門到實踐學習筆記-使用者輸入和while迴圈Python程式設計筆記While
- 《Python程式設計:從入門到實踐》Python程式設計
- 《Python程式設計:從入門到實踐》 筆記(一)基礎知識Python程式設計筆記
- Python 程式設計從入門到實踐5Python程式設計
- 《Python程式設計:從入門到實踐》第2章習題Python程式設計
- 7月讀書筆記-Python程式設計:從入門到實踐(未完進展中)筆記Python程式設計
- Python專案實戰(一)《Python程式設計 從入門到實踐》Python程式設計
- 資源 | 小白必收!《Python程式設計 從入門到實踐》Python程式設計
- Python程式設計:從入門到實踐(第2版)第1章習題答案Python程式設計
- 三週刷完《Python程式設計從入門到實踐》的感受Python程式設計
- 【docker】Docker入門到實踐 筆記Docker筆記
- 好程式設計師分享Python從入門到精通最佳學習路線程式設計師Python
- 【Python程式設計從入門到實踐】 1 Linux搭建Python編譯環境Python程式設計Linux編譯
- Python Type Hints 從入門到實踐Python
- GraphQL 從入門到實踐
- Redis從入門到實踐Redis
- nginx從入門到實踐Nginx
- python學習筆記(一)——入門Python筆記
- Spark MLlib 入門學習筆記 - 程式設計環境配置Spark筆記程式設計
- JavaScript入門學習之旅(二)——JavaScript DOM程式設計藝術學習筆記(上)JavaScript程式設計筆記
- 微信小程式入門學習筆記微信小程式筆記
- python學習筆記——jieba庫入門Python筆記Jieba
- Python多執行緒程式設計深度探索:從入門到實戰Python執行緒程式設計
- Minecraft 從入門到入坑(邊玩遊戲邊學程式設計)Raft遊戲程式設計
- 學習筆記專案實踐(python)筆記Python
- 求大神解答,《Python程式設計從入門到實踐》第94-95頁,外星人入侵Python程式設計
- python程式設計學習筆記⑦-1函式Python程式設計筆記函式
- Docker從入門到動手實踐Docker
- GDB除錯-從入門到實踐除錯
- go實戰web入門學習筆記GoWeb筆記
- Java學習從入門到精通Java
- Python入門到實踐-計算機算數Python計算機
- Nacos入門學習&實踐
- python核心程式設計:入門Python程式設計的8個實踐性建議Python程式設計
- TS入門學習筆記筆記