前言:函数是带名字的代码块,用于完成具体的工作。调用函数执行重复性的任务,程序的编写、阅读、测试和修复都将更容易。可将函数存储在模块中,让主程序文件更有序。
8.1 定义函数:关键字def
def greet_user():
"""显示简单的问候语""" #文档字符串docstring,是一种注释,描述了函数是做什么的。由三引号括起,用来生成有关程序中函数的文档
print('hello!')
greet_user()#函数调用
8.1.1 向函数传递信息
def greet_user(username):
"""显示简单的问候语""" #文档字符串docstring,是一种注释,描述了函数是做什么的。由三引号括起,用来生成有关程序中函数的文档
print('hello,'+ username.title() + '!')
greet_user('claudia')#函数调用
8.1.2 实参和形参
8.1.1的例子中,username是一个形参,claudia是一个实参。
实参是调用函数时传递给函数的信息。
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")
describe_pet("cat","gary")
输出:
I have a hamster.
My hamster's name is Harry.
I have a cat.
My cat's name is Gary.
8.2.2 关键字实参
传递给函数的名称-值对。
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")
describe_pet(pet_name ="gary",animal_type ="cat")
输出于8.2.1相同结果
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 = "gary")
输出:
I have a dog.
My dog's name is Gary.
8.2.4 等效的函数调用
可混合使用位置实参、关键字实参和默认值,使用最容易理解的调用方式即可。
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("jimi","hendrix")
print(musician)
8.3.2 让实参编程可选的
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("sarah","lee","Cooper")
print(musician)
8.3.3 返回字典
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)
8.3.4 结合使用函数和while循环
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 + '!')
输出:
8.4 传递列表
将列表传递给函数后,函数可以直接访问列表内容,提高处理效率。
def greet_users(names):
"""向列表中的每位用户发出简单问候"""
for name in names:
msg = "hello, " + name.title() + '!'
print(msg)
usernames = ['sarah','claudia','jack']
greet_users(usernames)
8.4.1 在函数中修改列表
在函数中对列表所做的任何修改都是永久性的。
#创建一个列表,包含一些要打印的设计
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_models,completed_models):
"""
模拟打印每个设计,直到全部打印
打印后,移到completed_model中
"""
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)
8.4.2 禁止函数修改列表
向函数传递列表的副本而不是原件。function_name(list_name[:])
除非特殊需求,否则还是传递原始列表,避免花时间和创建副本。
print_models(unprinted_designs[:],completed_models)
8.5 传递任意数量的实参
使用*形参创建空元组(值不可变的列表),将所有值都装到这个元组中
def make_pizza(*toppings):
"""概述要制作的pizza"""
print("\nmaking a pizza with the follwoing toppings:")
for topping in toppings:
print("-" + topping)
make_pizza('pepperoni')
make_pizza('mushrooms','green peppers','extra cheese')
8.5.1 结合使用位置实参和任意数量实参
要让函数接受不同类型的实参,必须在函数定义中将接纳任意数量实参的形参都放在最后,python先匹配位置实参和关键字实参,再将余下的实参都收集到一个形参中
def make_pizza(size,*toppings):
"""概述要制作的pizza"""
print("\nmaking a " + str(size) + "-inch pizza with the follwoing toppings:")
for topping in toppings:
print("-" + topping)
make_pizza(16,'pepperoni')
make_pizza(12,'mushrooms','green peppers','extra cheese')
8.5.2 使用任意数量的关键字实参
def build_profile(first,last,**user_info): #形参的两个星号让python创建一个名为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)
8.6 将函数存储在模块中
函数可以将代码块与主程序分离。将函数存储在模块(独立文件,扩展名为.py)中,再将模块使用import语句导入主程序。
8.6.1 导入整个模块
module_nam.function_name()
import pizza
8.6.2. 导入特定的函数
导入特定函数无需再使用句点
- 特定函数 from module_name import function_name
- 任意数量函数 from module_name import function_0,function_1,function_2
8.6.3 使用as给函数指定别名
如函数名称与程序现有名称冲突,或者名称太长,可指定独一无二的别名
from module_name import function_name as fn
from pizza import make_pizza as mp
mp(16,"pepperoni")
8.6.4 使用as给模块指定别名
import module_name as mn
import pizza as p
8.6.5 导入模块中的所有函数
使用星号*可导入模块中的所有函数
from module_name import *
from pizza import *
Tips:最佳做法是要么只导入需要使用的函数,要么导入整个模块并用句点表示法,使代码更清晰,更易阅读和理解
8.7 函数编写指南
- 应给函数指定描述性名称
- 只在函数中使用小写字母和下划线
- 应包含简要阐述其功能的注释,且需紧跟函数定义后面,并采用文档字符串格式
- 给形参指定默认值时,等号两边不要有空格
- 函数调用关键字实参时,等号两边不要有空格
- 形参较多时,可在函数定义中输入左括号后按回车键,并在下一行按两次tab键,将形参列表和函数体区分开
- 如果程序或模块包含多个函数,可用两个空行将相邻函数隔开
- 所有import语句都应该放在文件开头(除非文件开头使用了注释来描述整个程序)