目录
1. 函数的定义
在Python中,函数可按下面这种方式定义:
def greet_user(username):
""" 显示简单的问候语 """
print("Hello, " + username.title() + "!")
greet_user('jesse')
上面这段代码演示了最简单的函数结构,第一行代码使用关键字def来定义一个函数,def后面的greet_user(username)为函数名,username叫做函数的形参,而'jesse'叫做实参。紧跟在def greet_user(username):后面的所有缩进行构成了函数体。""" 显示简单的问候语 """叫做文档字符串,描述的函数是做什么的,文档字符串用三引号括起,Python使用它们来生成有关程序中函数的文档。要使用这个函数,可调用它,依次指定函数名以及要传入括号中的参数。上面这段代码的输出为:
Hello, Jesse!
2. 传递实参
鉴于函数定义中可能包含多个形参,因此函数调用中也可能包含多个实参。向函数传递参数的方式很多,可使用位置实参,这要求实参的顺序与形参的顺序相同;也可使用关键字实参,其中每个实参由变量名和值组成;还可使用列表和字典。下面将一一介绍
2.1 位置实参
在调用函数时,Python必须将函数调用中的每个实参都关联到函数定义中的一个形参,为此,最简单的关联方式是基于实参的顺序,这种关联方式被称为位置实参:
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')
如上面的代码所示,在函数调用中,实参'hamster'存储在形参animal_type中,而实参'harry'存储在形参pet_name中,即实参按位置依次存储在两个形参中,最后的输出结果为:
I have a hamster.
My hamster's name is Harry.
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')
在上面的代码中,在调用函数时使用了关键字实参,其输出结果与2.1中的结果一样,值得注意的是,关键字实参的顺序无关紧要,如下面两个函数的调用是等效的:
describe_pet(animal_type='hamster', pet_name='harry')
describe_pet(pet_name='harry', animal_type='hamster')
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')
describe_pet('willie')
在上面的代码中,调用函数时,没有给形参animal_type传入实参的值,因此形参animal_type将使用默认值'dog'作为要传入的实参值,其输出结果为:
I have a dog.
My dog's name is Willie.
I have a dog.
My dog's name is Willie.
值得注意的是,在给形参指定默认值后,要是想用位置实参,则需要在函数定义时将指定了默认值的形参放在末尾,防止参数传递错误。
当然,你也可以在调用函数时传入实参以覆盖掉默认值,像下面这样:
describe_pet(pet_name='harry', animal_type='hamster')
describe_pet('harry', 'hamster')
此时,函数的输出结果为:
I have a hamster.
My hamster's name is Harry.
I have a hamster.
My hamster's name is Harry.
3. 返回值
3.1 返回简单值
在Python的函数中,可以使用return来返回一个值,如下所示:
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)
在上面的代码中,调用函数get_formatted_name()时,会将整理好的姓名返回,并存储在变量musician中,其输出结果为:
Jimi Hendrix
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('john', 'hooker', 'lee')
print(musician)
在上面的代码中,将形参middle_name指定为空字符串,这样在调用函数时就可不向其传入参数。
3.3 返回字典或列表
函数可返回任何类型的值,包括字典和列表等较复杂的数据结构,如下所示:
def build_person(first_name, last_name):
""" 返回一个字典,其中包含有关一个人的信息 """
person = {'first': first_name, 'last': last_name}
return person
musician = build_person('jimi', 'hendrix')
print(musician)
其输出结果为:
{'first': 'jimi', 'last': 'hendrix'}
4. 传递列表
4.1 向函数传递列表
有时候,向函数传递列表很有用,这种列表包含的可能是名字、数字或更复杂的对象(如字典)。将列表传递给函数后,函数就能直接访问其内容,如下所示:
def greet_users(names):
"""向列表中的每位用户都发出简单的问候"""
for name in names:
msg = "Hello, " + name.title() + "!"
print(msg)
usernames = ['hannah', 'ty', 'margot']
greet_users(usernames)
在上面的代码中,将一个列表传入了函数,并在函数中对其进行遍历打印,其输出结果为:
Hello, Hannah!
Hello, Ty!
Hello, Margot!
4.2 在函数中修改列表
将列表传递给函数后,函数就可对其进行修改,在函数中对这个列表所做的任何修改都是永久性的,如下所示:
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):
""" 显示打印好的所有模型 """
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)
在上面这段代码中,向函数print_models()传入一个具有三个元素的列表unprinted_designs和一个空列表completed_models,在函数中将列表unprinted_designs中的元素依次弹出,再依次存储在空列表completed_models中,调用print_models()函数后,原本具有三个元素的列表unprinted_designs变为空列表,而原本为空列表的completed_models则倒序存储有unprinted_designs中的元素,其输出结果如下所示:
Printing model: dodecahedron
Printing model: robot pendant
Printing model: iphone case
The following models have been printed:
dodecahedron
robot pendant
iphone case
4.3 禁止函数修改列表(使用列表切片副本)
将原列表当作实参传入函数时,如果在函数对其进行修改,则该修改是不可逆的,如果想要将列表传入函数,又要原列表不发生变化,则可选择将列表的切片副本传入函数,这样既能得到传递原列表相同的结果,又能保证原列表不发生变化,其形式如下所示:
function_name(list_name[:])
5. 传递任意数量的实参
如果你预先不知道函数需要接受多少个实参,则可以采用下面的方法使函数能够传递任意数量的实参:
def make_pizza(*toppings):
""" 打印顾客点的所有配料 """
print(toppings)
make_pizza('pepperoni')
make_pizza('mushrooms', 'green peppers', 'extra cheese')
形参名*toppings中的星号让Python创建一个名为toppings的空元组,并将收到的所有值都封装到这个元组中,其输出结果为:
('pepperoni',)
('mushrooms', 'green peppers', 'extra cheese')
5.1 结合使用位置实参和任意数量实参
如果要让函数接收不同类型的实参,必须在函数定义中将接纳任意数量实参的形参放在最后。Python先匹配位置实参和关键字实参,再将余下的实参都收集到最后一个形参中,如下所示:
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中,其使出结果为:
Making a 16-inch pizza with the following toppings:
- pepperoni
Making a 12-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('albert', 'einstein', location='princeton', field='physics')
print(user_profile)
函数build_profile()的定义要求提供名和姓,同时允许用户根据需要提供任意数量的名称—值对。形参**user_info中的两个星号让Python创建一个名为user_info的空字典,并将收到的所有名称—值对都封装到这个字典中。在这个函数中,可以像访问其他字典那样访问user_info中的名称—值对。
6. 将函数存储在模块中
函数的优点之一是使用它们可将代码与主程序分离。通过给函数指定描述性名称,可让主程序容易理解得多。进一步的,函数还可以存储在被称为模块的独立文件中,再将模块导入到主程序中。import语句允许再当前运行的程序文件中使用模块中的函数。导入模块的方法有很多种,下面将做一一介绍。
6.1 导入整个模块
要让函数是可导入的,得先创建模块。模块是扩展名为.py的文件,包含要导入到程序中的代码。下面来创建一个包含函数make_pizza()的模块,并将其保存在pizza.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(16, 'pepperoni')
pizza.make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
Python读取这个文件时,代码行import pizza让Python打开文件pizza.py,并将其中所有的函数都复制到这个程序中。你看不到复制的代码,因为这个程序运行时,Python再幕后复制这些代码,你只需要知道,在making_pizza.py中,可以使用pizza.py中定义的所有函数。要调用被导入的模块中的函数,可指定导入的模块的名称pizza和函 数名make_pizza(),并用句点分隔它们。这些代码的输出与没有导入模块的原始程序相同:
Making a 16-inch pizza with the following toppings:
- pepperoni
Making a 12-inch pizza with the following toppings:
- mushrooms
- green peppers
- extra cheese
6.2 导入特定的函数
还可以导入模块中的特定函数,这种导入方法的语法如下:
from module_name import function_name
通过用逗号分隔函数名,还可根据需要从模块中导入任意数量的函数:
from module_name import function_0, function_1, function_2
对于前面的making_pizzas.py示例,如果只想导入要使用的函数,代码将类似于下面这样:
from pizza import make_pizza
make_pizza(16, 'pepperoni')
make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
若使用这种语法,调用函数时就无需使用句点。由于我们在import语句中显式地导入了函数make_pizza(),因此调用它时只需指定其名称。
6.3 使用as给函数指定别名
如果要导入的函数的名称可能与程序中现有的名称冲突,或者函数的名称太长,可将函数指定为另一个好辨识的别名,如下所示:
from pizza import make_pizza as mp
mp(16, 'pepperoni')
mp(12, 'mushrooms', 'green peppers', 'extra cheese')
在上面的代码中,将函数make_pizza()指定了别名mp(),这样在调用它时就只需用其别名即可。
6.4 使用as给模块指定别名
除了给函数指定别名外,还可以给模块指定别名,如下所示:
import pizza as p
p.make_pizza(16, 'pepperoni')
p.make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
6.5 导入模块中的所有函数
使用星号(*)运算符可让Python导入模块中的所有函数:
from pizza import *
make_pizza(16, 'pepperoni')
make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
当然在使用并非自己编写的大型模块时,不建议使用这种导入方法,它很可能会导致多个函数名称相同,从而互相覆盖的问题,正确的做法是,要么只导入你需要使用的函数,要么导入整个模块并使用句点表示法。