[TOC]
*****
# 8.1 定義函數
```
#定義函數
def greet_user(username):
"""Display a simple greeting."""
print("Hello, " + username.title() + "!")
#函數調用 給函數傳遞參數
greet_user('jesse')
```
#8.1.2 實參和形參
在函數greet_user()的定義中,變量username是一個形參 —— 函數完成其工作所需的一項信息。在代碼greet_user('jesse')中,值'jesse'是一個實參。
# 8.2 傳遞實參
## 8.2.1 位置實參
將函數調用中的每個實參都關聯到函數定義中的一個形參。 為此,最簡單的關聯方式是基于實參的順序。這種關聯方式被稱為位置實參
```
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')
```
2. 位置實參的順序很重要
```
#這樣子編程動物類型是harry, 寵物名字是松鼠,和目標不一致錯誤
describe_pet('harry', 'hamster')
```
## 8.2.2 關鍵字實參
關鍵字實參是傳遞給函數的名稱—值對。你直接在實參中將名稱和值關聯起來了,因此向函數傳遞實參時不會混淆(不會得到名為Hamster的harry這樣的結果)。關鍵字實參讓你無需考慮函數調用中的實參順序,還清楚地指出了函數調用中各個值的用途。
```
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')
```
## 8.2.3 默認值
編寫函數時,可給每個形參指定默認值。在調用函數中給默認的形參提供了實參時,使用指定的實參值;否則,將使用形參的默認值。給形參指定默認值后,可在函數調用中省略相應的實參。
```
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')
```
形參是默認值,傳參數時實參和形參綁定依然會按照位置綁定
** 注意**
使用默認值時,在形參列表中必須先列出沒有默認值的形參,再列出有默認值的形參。
## 8.2.4 等效的函數調用
對于以下函數定義
```
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 避免實參錯誤

# 8.3 返回值
## 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('jimi', 'hendrix')
print(musician)
```
## 8.3.2 讓實參變成可選的
給函數的形參指定默認值為空。不用該參數時不傳值。使用參數時,給實參賦值覆蓋原來的默認值
```
def get_formatted_name(first_name, last_name, middle_name=''):
musician = get_formatted_name('john', 'hooker', 'lee')
```
## 8.3.3 返回字典
```
def build_person(first_name, last_name, age=''):
"""Return a dictionary of information about a person."""
person = {'first': first_name, 'last': last_name}
return person
```
# 8.4 傳遞列表
```
def greet_users(names):
"""Print a simple greeting to each user in the list."""
for name in names:
msg = "Hello, " + name.title() + "!"
print(msg)
usernames = ['hannah', 'ty', 'margot']
greet_users(usernames)
```
## 8.4.1 在函數中修改列表
將列表傳遞給函數后,函數就可對其進行修改。在函數中對這個列表所做的任何修改都是永
久性的,這讓你能夠高效地處理大量的數據。
## 8.4.2 禁止函數修改列表
可向函數傳遞列表的副本而不是原件;這樣函數所做的任何修改都只影響副本,而絲毫不影響原件。
```
function_name(list_name[:])
```
# 8.5 傳遞任意數量的實參
Python允許函數從調用語句中收集任意數量的實參。
```
def make_pizza(*toppings):
"""打印顧客點的所有配料"""
print(toppings)
make_pizza('pepperoni')
make_pizza('mushrooms', 'green peppers', 'extra cheese')
```
形參名*toppings中的星號讓Python創建一個名為toppings的空元組,并將收到的所有值都封裝到這個元組中
## 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(16, 'pepperoni')
make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
```
Python將收到的第一個值存儲在形參size中,并將其他的所有值都存儲在元組toppings中。
## 8.5.2 使用任意數量的關鍵字實參
需要接受任意數量的實參,但預先不知道傳遞給函數的會是什么樣的信息。在這種
情況下,可將函數編寫成能夠接受任意數量的鍵—值對——調用語句提供了多少就接受多少。一
個這樣的示例是創建用戶簡介:你知道你將收到有關用戶的信息,但不確定會是什么樣的信息。
在下面的示例中,函數build_profile()接受名和姓,同時還接受任意數量的關鍵字實參
```
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)
```
函數build_profile()的定義要求提供名和姓,同時允許用戶根據需要提供任意數量的名稱—
值對。形參**user_info中的兩個星號讓Python創建一個名為user_info的空字典,并將收到的所
有名稱—值對都封裝到這個字典中。在這個函數中,可以像訪問其他字典那樣訪問user_info中的
名稱—值對。
# 8.6 將函數存儲在模塊中
將函數存儲在被稱為模塊的獨立文件中,再將模塊導入到主程序中。 import語句允許在當前運行的程序文件中使用模塊中的代碼。
通過將函數存儲在獨立的文件中,可隱藏程序代碼的細節,將重點放在程序的高層邏輯上。 這還能讓你在眾多不同的程序中重用函數。將函數存儲在獨立文件中后,可與其他程序員共享這些文件而不是整個程序。知道如何導入函數還能讓你使用其他程序員編寫的函數庫。
## 8.6.1 導入整個模塊
要讓函數是可導入的,得先創建模塊。 模塊是擴展名為.py的文件,包含要導入到程序中的代碼。
**pizza.py**
```
def make_pizza(size, *toppings):
"""Summarize the pizza we are about to make."""
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_pizzas.py**
```
import pizza as p
p.make_pizza(16, 'pepperoni')
p.make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
```
代碼行import pizza讓Python打開文件pizza.py,并將其中的所有函數都復制到這個程序中。你看不到復制的代碼,因為這個程序運行時, Python在幕后復制這些代碼。
## 8.6.2 導入特定的函數
**語法** : from module_name import function_name
```
from pizza import make_pizza
make_pizza(16, 'pepperoni')
make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
```
## 8.6.3 使用 as 給函數指定別名
如果要導入的函數的名稱可能與程序中現有的名稱沖突,或者函數的名稱太長,可指定簡短而獨一無二的別名——函數的另一個名稱
給函數make_pizza()指定了別名mp()
```
from pizza import make_pizza as mp
mp(16, 'pepperoni')
mp(12, 'mushrooms', 'green peppers', 'extra cheese')
```
## 8.6.4 使用 as 給模塊指定別名
還可以給模塊指定別名。通過給模塊指定簡短的別名(如給模塊pizza指定別名p),讓你能夠更輕松地調用模塊中的函數
```
import pizza as p
p.make_pizza(16, 'pepperoni')
p.make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
```
## 8.6.5 導入模塊中的所有函數
使用星號(*)運算符可讓Python導入模塊中的所有函數:
```
from pizza import *
make_pizza(16, 'pepperoni')
make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
```
不推薦這種做法,要么只導入你需要使用的函數,要么導入整個模塊并使用句點表示法
# 8.7 函數編寫指南

用兩個空行將相鄰的函數分開