8.函数
8.1定义函数
函数定义:使用关键字def,在def后输入函数名以及括号,其中括号内指出函数为完成任务需要什么样的信息,如果函数不需要任何信息就能完成工作,那么也需要输入空括号,最后定义以冒号结尾。
需要调用函数时,依次指定函数名以及圆括号括起来的必要信息即可。简单示例如下:
def greet_user():
print('Hello!')
greet_user()
输出结果为:
Hello!
8.1.1向函数传递信息
当我们在括号内输入完成任务需要的信息时,就可以向函数传递信息并输出。示例如下:
#添加username作为完成函数需要的信息,让函数接受你给username指定的任何值
def greet_user(username):
print(f'Hello,{username.title()}!')
#调用函数,并向它提供执行函数调用print()所需要的信息
greet_user('faxxtty')
输出结果为:
#函数接受你所传递给它的名字,并向这个人发出问候:
Hello,Faxxtty!
8.1.2实参和形参
在以上示例中,变量username就是一个形参(parameter),即函数完成工作所需要的信息。在调用函数中的值‘faxxtty’就是一个实参(argument),也就是调用函数时传递给函数的信息。在调用函数时,要把要让函数使用的信息放在圆括号内,此时python将会把实参赋给形参。
##8.2传递实参
函数调用中可能包含多个实参,向函数传递实参的方式很多,可以使用以下几种:
1、位置实参;使用时要求实参的顺序与形参的顺序相同;
2、关键字实参:使用时要求其中的每个实参都由变量名和值组成;
3、也可以使用列表和字典。
8.2.1位置实参
所谓位置实参,就是指在调用函数时,python必须把函数调用中的每个实参都关联到函数定义中的一个形参,当关联的方式采用基于实参的顺序时,就是使用了位置实参。示例如下:
#定义函数,需要一种动物类型和一个名字
def describe_pet(animal_type,pet_name):
print(f'\nI have a {animal_type}.')
print(f"My {animal_type}'s name is {pet_name.title()}.")
#调用函数,按照形参位置将实参赋给形参
describe_pet('hamster','harry')
输出结果为:
I have a hamster.
My hamster's name is Harry.
可以看到函数按照参数位置进行了赋值。另外,函数的方便之处还在于,只要定义好函数之后,就可以多次调用函数,示例如下:
def describe_pet(animal_type,pet_name):
print(f'\nI have a {animal_type}.')
print(f"My {animal_type}'s name is {pet_name.title()}.")
describe_pet('hamster','harry')
describe_pet('dog','tom')
此时输出结果为:
I have a hamster.
My hamster's name is Harry.
I have a dog.
My dog's name is Tom.
8.2.2关键字实参
在位置实参中,如果没有准确对好各参数的位置,可能会导致赋值发生混乱的情况。为避免这种情况,关键字实参就可以发挥用处。所谓关键字实参就是直接传递给函数的名称值对,它会直接在实参中将名称和值关联起来,无需考虑函数调用中实参的位置顺序,同时也清楚地指出了函数调用中各个值的用途。需要注意的是,在关键字实参的调用中,等号两边不应有空格。示例如下:
def describe_pet(animal_type,pet_name):
print(f'\nI have a {animal_type}.')
print(f"My {animal_type}'s name is {pet_name.title()}.")
describe_pet(animal_type='hamster',pet_name='harry')
输出结果为:
I have a hamster.
My hamster's name is Harry.
在使用关键字实参时,调用函数圆括号内的参数位置就无关紧要,最后一句写成以下也同样可以输出相同的结果:
describe_pet(pet_name='harry',animal_type='hamster')
唯一需要注意的地方是在使用时务必准确指定函数定义中的形参名称。
8.2.3默认值
在定义函数时,可以给每个形参指定默认值。此时,若在调用函数中给形参提供了实参,python将会使用指定的实参值;若没有提供,则使用实参的默认值。因此在给形参指定默认值之后,可以在函数调用中省略相应的实参。需要注意的一点是,在给形参指定默认值时,等号两边不要有空格。示例如下:
def describe_pet(pet_name,animal_type='dog'):
print(f'\nI have a {animal_type}.')
print(f"My {animal_type}'s name is {pet_name.title()}.")
describe_pet(pet_name='harry')
输出结果为:
I have a dog.
My dog's name is Harry.
此处需要注意,使用默认值时,必须先在形参列表中列出没有默认值的形参,再列出有默认值的实参。否则运行将会报错,示例如下:
def describe_pet(animal_type='dog',pet_name):
print(f'\nI have a {animal_type}.')
print(f"My {animal_type}'s name is {pet_name.title()}.")
describe_pet(pet_name='harry')
输出结果为:
File "<stdin>", line 1
def describe_pet(animal_type='dog',pet_name):
^
SyntaxError: non-default argument follows default argument
File "<stdin>", line 1
print(f'\nI have a {animal_type}.')
IndentationError: unexpected indent
File "<stdin>", line 1
print(f"My {animal_type}'s name is {pet_name.title()}.")
IndentationError: unexpected indent
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: describe_pet() missing 1 required positional argument: 'animal_type'
而当先在形参列表中列出没有默认值的形参时,也同样可以使用位置实参来调用函数,示例如下:
def describe_pet(pet_name,animal_type='dog'):
print(f'\nI have a {animal_type}.')
print(f"My {animal_type}'s name is {pet_name.title()}.")
describe_pet('harry')
此时输出结果依然同上的关键字实参。
即便设置了默认值,当要输出的函数实参非默认值时,依然可以调用函数。示例如下:
#位置实参
def describe_pet(pet_name,animal_type='dog'):
print(f'\nI have a {animal_type}.')
print(f"My {animal_type}'s name is {pet_name.title()}.")
describe_pet('harry','cat')
#关键字实参
def describe_pet(pet_name,animal_type='dog'):
print(f'\nI have a {animal_type}.')
print(f"My {animal_type}'s name is {pet_name.title()}.")
describe_pet(pet_name='harry',animal_type='cat')
以上两种方式输出结果相同,均为:
I have a cat.
My cat's name is Harry.
8.3返回值
函数还可以用来处理一些数据,并返回一个或者一组值,函数返回的值就称为返回值。在函数中,使用return语句将值返回到调用函数的代码行。
8.3.1返回简单值
简单示例如下:
def get_formatted_name(first_name,last_name):
full_name = f'{first_name} {last_name}'
return full_name.title()
musician = get_formatted_name('jimi','hendrix')
print(musician)
调用返回值的函数时,需要提供一个变量,以便将返回的值赋给它,次吃将返回值赋给musician,输出结果为:
Jimi Hendrix
8.3.2让实参变成可选的
当想让实参变成可选的值时,可以使用默认值来实现。例如想要返回一个人的姓、名以及中间名,可以编写函数如下:
def get_formatted_name(first_name,middle_name,last_name):
full_name = f'{first_name} {middle_name} {last_name}'
return full_name.title()
musician = get_formatted_name('jimi','lee','hendrix')
print(musician)
只要同时提供三个实参,就可以正常运行以上函数并返回结果,如下:
Jimi Lee Hendrix
但并不是每个人都有中间名,要使只提供姓和名就让以上函数正常运行,此时可以给中间名一个默认空值,由此使得当你没有提供中间名时函数不再使用这个形参。此时将middle_name默认值设置为空字符串,并将其移到形参列表的末尾,示例如下:
def get_formatted_name(first_name,last_name,middle_name=''):
if middle_name:
full_name = f'{first_name} {middle_name} {last_name}'
else:
full_name = f'{first_name} {last_name}'
return full_name.title()
musician = get_formatted_name('jimi','hendrix')
print(musician)
musician = get_formatted_name('jimi','lee','hendrix')
print(musician)
输出结果分别为:
Jimi Hendrix
Jimi Lee Hendrix
8.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'}
8.3.4结合使用函数和while循环
示例如下:
def get_formatted_name(first_name,last_name):
full_name = f'{first_name} {last_name}'
return full_name.title()
while True:
print('\nPlease enter your name:')
print('(enter "q" at any time yo 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(f'\nHello,{formatted_name}!')
输出结果如下:
Please enter your name:
(enter "q" at any time yo quit)
First name:faxxtty
Last name:feng
Hello,Faxxtty Feng!
Please enter your name:
(enter "q" at any time yo quit)
First name:q
8.4传递列表
将列表传递给函数,可以使函数遍历列表中每个元素。示例如下:
def greet_users(names):
for name in names:
message = f'Hello,{name.title()}!'
print(message)
usernames = ['hannah','ty','margot']
greet_users(usernames)
输出结果为:
Hello,Hannah!
Hello,Ty!
Hello,Margot!
8.4.1在函数中修改列表
将列表传递给函数后,可以在函数中修改列表,在函数中对这个列表所作的任何修改都是永久性的。示例如下:
#创建一个包含要打印的设计的列表
unprinted_designs = ['phone case','robot pendant','dodecahedron']
#创建一个空列表。用来装打印完毕的设计
completed_models = []
while unprinted_designs:
#将未打印的设计弹出放入当前打印
current_design = unprinted_designs.pop()
#输出正在打印的设计
print(f'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)
输出结果为:
Printing model:dodecahedron
Printing model:robot pendant
Printing model:phone case
The following models have been printed:
dodecahedron
robot pendant
phone case
对于以上函数,可以通过编写两个函数,每个都做一件具体的工作,来使得效率更高。示例如下:
def print_models(unprinted_designs,completed_models):
"""将每个未打印的设计弹出到当前打印的列表中,
打印每个设计后将其移到已完成打印的列表中。
"""
while unprinted_designs:
current_design = unprinted_designs.pop()
print(f'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 = ['phone case','robot pendant','dodecahedron']
completed_models = []
print_models(unprinted_designs,completed_models)
show_completed_models(completed_models)
输出结果与上例一致。
8.4.2禁止函数修改列表
为了保留原列表内容,使函数修改不影响原列表,可以将列表的副本传递给函数,这样修改的就是列表的副本而非列表本身,可使用**切片表示法[:]**来创建列表的副本。
在以上示例中,只需要将最后一句改成以下即可:
print_models(unprinted_designs[:],completed_models)
##8.5传递任意数量的实参
在预先不知道函数需要接受多个是实参时,可以在形参名前输入一个星号以创建一个空元组 ,将收到的所有值都封装到这个元组中。示例如下:
def make_pizza(*toppings):
print(toppings)
make_pizza('pepperoni')
make_pizza('mushrooms','green peppers','extra cheese')
输出结果为:
('pepperoni',)
('mushrooms', 'green peppers', 'extra cheese')
8.5.1结合使用位置实参和任意数量实参
如果要让函数接受不同类型的实参,必须在函数定义中将接纳任意数量实参的形参放在最后。示例如下:
def make_pizza(size,*toppings):
print(f'\nMaking a {size}-inch pizza with the following toppings:')
for topping in toppings:
print(f'-{topping}')
make_pizza(16,'pepperoni')
make_pizza(12,'mushrooms','green peppers','extra cheese')
输出结果为:
Making a 16-inch pizza with the following toppings:
-pepperoni
Making a 12-inch pizza with the following toppings:
-mushrooms
-green peppers
-extra cheese
8.5.2结合使用关键字实参和任意数量实参
当你知道将收到有关用户信息,但不确定会是什么样的信息时,可以结合使用关键字实参,将函数编写成能够接受任意数量的键值对,在需要存放信息的字典名前输入两个星号。示例如下:
def build_profile(first,last,**user_info):
user_info['first_name'] = first
user_info['last_name'] = last
return user_info
#调用函数,向其传递姓名和两个键值对并将返回的信息赋给变量
user_profile = build_profile('albert','einstein',
location='princeton',
field='physics')
print(user_profile)
输出结果为:
{'location': 'princeton', 'field': 'physics', 'first_name': 'albert', 'last_name': 'einstein'}
注:通用形参名*args,用以收集任意数量的位置实参;通用形参名 *kwargs,用以收集任意数量的关键字实参。