前言
本章内容很多!真的是漫长的一章啊!!
学习tips: 在学习新知识或者处理复杂逻辑/多步骤习题时,相信很多新手会陷入大脑混乱、不知所措中。新手常见的问题有:
1. 混淆控制语句、函数和变量:控制流用于控制程序的执行流程,函数是一段可重用的代码,而变量是用于存储值的标识符。确保理解它们之间的区别对于正确编写和调用代码至关重要。
2. 代码逻辑和调用的理解: 在一些代码示例中,新手可能遇到了一些逻辑错误,比如函数调用的位置和方式不正确。理解代码的执行流程以及函数如何被调用是至关重要的。
3. 变量覆盖: 在代码中使用了相同的变量名来表示不同的实体,这可能导致混淆。确保变量名的一致性,不要在不同的上下文中使用相同的名称。
4. 对特定语法和功能的理解: 比如我对函数返回值的使用和调用有些混淆,这都会阻碍我对代码的理解和使用。
5. 语法错误和调试: 在编写代码时,可能会遇到语法错误或逻辑错误。学会使用调试工具(如 `print` 语句、调试器)来检查代码的执行流程,有助于找出错误并进行修复。
在近八章学习中,我找到了整理清楚并且不让大脑过多负载的办法。面对全新代码时,要仔细看书中对每一个代码的解释。在看懂解释之后,在自己的大脑里用1.2.3.的方式复盘代码逻辑(可以选择写注释在代码中作为提示)。这样能够确保编写代码的独立自主性。
def formatted_name(first_name,last_name):
formatted_name = first_name+' '+ last_name
return formatted_name.title()
students = formatted_name('Haifei',"Wang")
print(students)
#1. 使用函数建立总体name变量
#2. 返回变量
#3. 创建一个新变量储存返回值。
同样地,做习题时会遇到大段要求。其实要求越多,越证明题目编写者给了越多的提示。可以把一段话切分成不同点,确认自己的代码能够完成各类要求。
【函数是什么】:函数是带名字的代码块,用于完成具体的工作。要执行函数定义的特定任务,可调用该函数。需要在程序中多次执行同一项任务时,你无需反复编写完成该任务的代码,而只需调用执行该任务的函数,让Python运行其中的代码。你将发现,通过使用函数,程序的编写、阅读、测试和修复都将更容易。
【学什么】:你会学习向函数传递信息的方式。(1)如何编写主要任务是显示信息的函数。(2)用于处理数据并返回一个或一组值的函数。(3)将函数存储在被称为模块的独立文件中,让主程序文件的组织更为有序。
1.定义函数 def
def=definition 定义
def great_user():#定义一个函数,下方所有缩进构成函数体。
"""显示问候语:""" #文本注释,三引号,描述函数做什么。
print("Hello!") #函数的工作
great_user() #函数调用让Python执行函数的代码。要调用函数,可依次指定函数名以及用括号括起的必要信息,
(1)使用关键字def来告诉Python你要定义一个函数。这是函数定义,向Python指出了函数名,还可能在括号内指出函数为完成其任务需要什么样的信息。在这里,函数名为greet_user(),它不需要任何信息就能完成其工作,因此括号是空的(即便如此,括号也必不可少)。最后,定义以冒号结尾。紧跟在def greet_user():后面的所有缩进行构成了函数体。
(2)三引号:文档字符串(docstring)的注释,描述了函数是做什么的。文档字符串用三引号括起,Python使用它们来生成有关程序中函数的文档。
(3)代码行print("Hello!")是函数体内的唯一一行代码,greet_user()只做一项工作:打印Hello!。
(4)要使用这个函数,可调用它。函数调用让Python执行函数的代码。要调用函数,可依次指定函数名以及用括号括起的必要信息。由于这个函数不需要任何信息,因此调用它时只需输入greet_user()即可。和预期的一样,它打印Hello!。
【向函数传递信息】
为此,可在函数定义defgreet_user()的括号内添加username。通过在这里添加username,就可让函数接受你给username指定的任何值.
def great_user(username):#定义一个函数,下方所有缩进构成函数体。
"""显示问候语:""" #文本注释,三引号,描述函数做什么。
print(f"Hello {username.title()}!") #函数的工作
great_user('Ashley') #函数调用让Python执行函数的代码。要调用函数,可依次指定函数名以及用括号括起的必要信息,
代码greet_user('Ashley')调用函数greet_user(),并向它提供执行print语句所需的信息。这个函数接受你传递给它的名字,并向这个人发出问候:Hello Ashley!
【实参和形参】
在函数greet_user()的定义中,变量username是一个形参——函数完成其工作所需的一项信息。在代码greet_user('ashley')中,值'ashley'是一个实参。实参是调用函数时传递给函数的信息。我们调用函数时,将要让函数使用的信息放在括号内。在greet_user('ashely')中,将实参'ashley'传递给了函数greet_user(),这个值被存储在形参username中。
【练习】
8-1 消息:编写一个名为display_message()的函数,它打印一个句子,指出你在本章学的是什么。调用这个函数,确认显示的消息正确无误。
def display_message():
"""本章中你学到了什么:"""
print('Function.')
display_message()
8-2 喜欢的图书:编写一个名为favorite_book()的函数,其中包含一个名为title的形参。这个函数打印一条消息,如One of my favorite books is Alice in Wonderland。调用这个函数,并将一本图书的名称作为实参传递给它。
def favorite_book(title):
"""What's your favorite book?"""
print(f'One of my favorite books is {title.title()}.')
favorite_book('Alice in Wonderland')
2. 传递实参
向函数传递实参的方式很多:(1)可使用位置实参,这要求实参的顺序与形参的顺序相同;(2)也可使用关键字实参,其中每个实参都由变量名和值组成;(3)还可使用列表和字典。下面来依次介绍这些方式。
【位置实参】
def animal_lists(category,name):
"""What's your pet's name?"""
print(f"My {category}'s name is {name.title()}.")
animal_lists('pig','feifei')
animal_lists('dog','zjk')
该函数定义表明,需要一种动物类型和一个名字, 在函数体内,使用了这两个形参来显示宠物的信息。实参’pig’储存在动物类型中,’feifei’储存在名字中。同时,可以调用函数多次,只需再次调用animal_lists()即可。
调用函数多次是一种效率极高的工作方式。我们只需在函数中编写描述宠物的代码一次,然后每当需要描述新宠物时,都可调用这个函数。
位置实参的顺序很重要,不要储存错了。
【关键词实参】
关键字实参是传递给函数的名称—值对。你直接在实参中将名称和值关联起来了,因此向函数传递实参时不会混淆(不会得到名为Pig的feifei这样的结果)。关键字实参让你无需考虑函数调用中的实参顺序,还清楚地指出了函数调用中各个值的用途。
def animal_lists(category,name):
"""What's your pet's name?"""
print(f"My {category}'s name is {name.title()}.")
animal_lists(category='pig',name='feifei')
关键字实参的顺序无关紧要,因为Python知道各个值该存储到哪个形参中。
def animal_lists(category,name):
"""What's your pet's name?"""
print(f"My {category}'s name is {name.title()}.")
animal_lists(name='feifei',category='pig')
结果都是:My pig's name is Feifei.
【默认值】
在调用函数中给形参提供了实参时,Python将使用指定的实参值;否则,将使用形参的默认值。因此,给形参指定默认值后,可在函数调用中省略相应的实参。使用默认值可简化函数调用,还可清楚地指出函数的典型用法。
def animal_lists(name, category='dog',):#把默认值放到最后。
"""clarify the information of your pet."""
print(f"My {category}'s name is {name.title()}.")
animal_lists(name='feifei')
My dog's name is Feifei.
报错:parameter without a default follows parameter with a default
这个错误信息通常是指在函数或方法的参数列表中,具有默认值的参数(有默认值的参数)之后跟着一个没有默认值的参数(没有默认值的参数)。这在某些编程语言中可能会导致问题,因为调用函数时,你需要先提供没有默认值的参数,然后才能提供有默认值的参数。
另外,Python依然将这个实参视为位置实参,因此如果函数调用中只包含宠物的名字,这个实参将关联到函数定义中的第一个形参。
使用这个函数的最简单的方式是,在函数调用中只提供小狗的名字:
animal_lists('feifei')
【避免实参错误】
读懂Traceback的报错提示。
【练习】
8-3 T恤:编写一个名为make_shirt()的函数,它接受一个尺码以及要印到T恤上的字样。
def make_shirt(size, font):
"""Show T-shirt's information:"""
print("\n The T-shirt's size and font are:")
print(f"The size is {size}, and the font is {font}.")
make_shirt('Medium','Simsun')
这个函数应打印一个句子,概要地说明T恤的尺码和字样。
使用位置实参调用这个函数来制作一件T恤;
再使用关键字实参来调用这个函数。
def make_shirt(size, font):
"""Show T-shirt's information:"""
print("\n The T-shirt's size and font are:")
print(f"The size is {size}, and the font is {font}.")
make_shirt(size='Medium',font='Simsun')
8-4 大号T恤:修改函数make_shirt(),使其在默认情况下制作一件印有字样“I love Python”的大号T恤。调用这个函数来制作如下T恤:一件印有默认字样的大号T恤、一件印有默认字样的中号T恤和一件印有其他字样的T恤(尺码无关紧要)。
def make_shirt(size, font='I love Python'):
"""Show T-shirt's information:"""
print(f"The T-shirt's size and font are:The size is {size}, and the font is {font}.")
make_shirt(size='Large')
make_shirt(size='Medium')
make_shirt(size='Medium',font='Simsun')
8-5 城市:编写一个名为describe_city()的函数,它接受一座城市的名字以及该城市所属的国家。
这个函数应打印一个简单的句子,如Reykjavik is in Iceland。
给用于存储国家的形参指定默认值。
为三座不同的城市调用这个函数,且其中至少有一座城市不属于默认国家。
def describe_city(name,country='China'):
print(f"{name.title()} is in {country.title()}.")
describe_city('Beijing')
describe_city('Wuhan')
describe_city('Amsterdam','Dutch')
3. 返回值 return
函数并非总是直接显示输出,相反,它可以处理一些数据,并返回一个或一组值。函数返回的值被称为返回值。
在函数中,可使用return语句将值返回到调用函数的代码行。返回值让你能够将程序的大部分繁重工作移到函数中去完成,从而简化主程序。
def formatted_name(first_name,last_name):
formatted_name = first_name+' '+ last_name
return formatted_name.title()
students = formatted_name('Haifei',"Wang")
print(students)
#1. 使用函数建立总体name变量
#2. 返回变量
#3. 创建一个新变量储存返回值。
调用返回值的函数时,需要提供一个变量,用于存储返回的值。在这里,将返回值存储在了变量students中。输出为整洁的姓名:Haifei Wang.
如果还是有些困惑,不如看一下更简单的解释:
如果我们把函数想象成一个自动售卖机,那我们购买到的饮料就是返回值。
def vending_machine(choice):
if choice =='1':#记得加引号
return'一瓶可乐'
elif choice=='2':
return'一袋薯片'
elif choice=='3':
return'一个雪糕'
else:
return'nothing'
choice=input('欢迎使用自动贩卖机,请输入编号:')
print(f'你购买的是:{vending_machine(choice)}。')
【让实参变成可选的】
def formatted_name(first_name,last_name,middle_name=' '):
if middle_name:
formatted_name = f'{first_name} {middle_name} {last_name}'
else:
formatted_name = f'{first_name} {last_name}'
return formatted_name.title()
students = formatted_name('Haifei',"Wang")
print(students)
students = formatted_name('Haifei','Wang','Pig')#最后一个是中间名
print(students)
Haifei Wang
Haifei Pig Wang
在函数体中,我们检查是否提供了中间名。Python将非空字符串解读为True,因此如果函数调用中提供了中间名,if middle_name将为True。如果提供了中间名,就将名、中间名和姓合并为姓名,然后将其修改为首字母大写格式,并返回到函数调用行。在函数调用行,将返回的值存储在变量musician中;然后将这个变量的值打印出来。 如果还要指定中间名,就必须确保它是最后一个实参,这样Python才能正确地将位置实参关联到形参。
如果没有提供中间名,middle_name将为空字符串,导致if测试未通过,进而执行else代码块:只使用名和姓来生成姓名,并将设置好格式的姓名返回给函数调用行。在函数调用行,将返回的值存储在变量students中;然后将这个变量的值打印出来。
习题:
def func(x):
if x<=1:
return 1 #如果输入 x 小于等于 1,函数返回 1(这是阶乘的终止条件)。
else:
return xfunc(x-1) #如果输入 x 大于 1,函数返回 x 乘以 func(x-1) 的结果。
print(func(4))
#func(4) = 4 func(3)
# = 4 3 func(2)
# = 4 3 2 func(1)
# = 4 3 2 1
#= 24
【返回字典】
def build_person(first_name,last_name):
"""返回一个字典,包含一个人的信息"""
person={'first name':first_name,'last name':last_name}
return person
musician=build_person('haifei','wang')
print(musician)
函数build_person()接受名和姓,并将这些值封装到字典中。
存储first_name的值时,使用的键为'first',而存储last_name的值时,使用的键为'last'。最后,返回表示人的整个字典。
打印这个返回的值,此时原来的两项文本信息存储在一个字典中:{'first name': 'haifei', 'last name': 'wang'}
【while循环:储存用户输入】
return储存之后,再while
def formatted_name(first_name,last_name):
full_name = f'{first_name} {last_name} ' #不理解它的用处
return full_name
while True:
print('Please tell me your name:')
f_name=input("First name:")
l_name=input("Last name:")
new_formatted_name=formatted_name(f_name,l_name)
print(f"Hello, {new_formatted_name}.")
full-name相当于局部变量。
停止 if-break
def formatted_name(first_name,last_name):
full_name = f'{first_name} {last_name} ' #不理解它的用处
return full_name
while True:
print('Please tell me your name:')
print("Enter 'q' if you want to quit.")
f_name=input("First name:")
if f_name=='q':
break
l_name=input("Last name:")
if l_name=='q':
break
new_formatted_name=formatted_name(f_name,l_name)
print(f"Hello, {new_formatted_name}.")
【练习】
8-6 城市名:编写一个名为city_country()的函数,它接受城市的名称及其所属的国家。至少使用三个城市-国家对调用这个函数,并打印它返回的值。
【报错】
#城市名:编写一个名为city_country()的函数,它接受城市的名称及其所属的国家。
# #这个函数应返回一个格式类似于下面这样的字符串
#至少使用三个城市-国家对调用这个函数,并打印它返回的值。
def city_country(city,country):
full_name= f'{city.name()},{country.name()}'
return full_name
new_name=full_name('beijing','china')
print(new_name)
处理几个问题:
1.函数调用的语法是 function_name(argument1, argument2, ...),而不是variable_name(argument1, argument2, ...)。在你的代码中,full_name 是一个字符串,而不是一个函数,因此 full_name('beijing', 'china') 是无效的。
2.开头大写是.title(),我总是写错成.name()
3.你在函数内部使用了 return 语句,它会导致函数在执行到 return 时立即退出,因此后面的代码(如new_name=full_name('beijing','china'))将不会被执行。你可能想要将这些行放在函数调用之前。
修改:
def city_country(city,country):
full_name= f'{city.title()},{country.title()}'
return full_name #return会立刻返回,不会接着执行后续的函数。所以new_name没有缩进
new_name=city_country('beijing','china') #必须用func函数调用。
print(new_name)
new_name=city_country('shanghai','china') #必须用func函数调用。
print(new_name)
new_name=city_country('tokyo','jepan') #必须用func函数调用。
print(new_name)
#8-7 专辑:编写一个名为make_album()的函数,它创建一个描述音乐专辑的字典。#这个函数应接受歌手的名字和专辑名,并返回一个包含这两项信息的字典。#使用这个函数创建三个表示不同专辑的字典,并打印每个返回的值,以核实字典正确地存储了专辑的信息。
def make_album(singer,album):
music_album={'singer name':singer,'album name':album} #'singer_name'不变。
return music_album
list=make_album('Taylor Swift','1989')
print(list)
list=make_album('Eason Chen','淘汰')
print(list)
list=make_album('Jay Zhou','青花瓷')
print(list
#给函数make_album()添加一个可选形参,以便能够存储专辑包含的歌曲数。如果调用这个函数时指定了歌曲数,就将这个值添加到表示专辑的字典中。调用这个函数,并至少在一次调用中指定专辑包含的歌曲数。
def make_album(singer,album,number=None):
if number==None:
music_album={'singer name':singer,'album name':album}
return music_album
else:
music_album={'singer name':singer,'album name':album,'number':number}
return music_album
album1=make_album('Taylor Swift','1989','8')
print(album1)
album2=make_album('Eason Chen','淘汰')
print(album2)
album3=make_album('Jay Zhou','青花瓷')
print(album3)
{'singer name': 'Taylor Swift', 'album name': '1989', 'number': '8'}
{'singer name': 'Eason Chen', 'album name': '淘汰'}
{'singer name': 'Jay Zhou', 'album name': '青花瓷'}
8-8 用户的专辑:在为完成练习8-7编写的程序中,编写一个while循环,让用户输入一个专辑的歌手和名称。获取这些信息后,使用它们来调用函数make_album(),并将创建的字典打印出来。在这个while循环中,务必要提供退出途径。
def make_album(singer,album,number=None):
if number==None:
music_album={'singer name':singer,'album name':album}
return music_album
else:
music_album={'singer name':singer,'album name':album,'number':number}
return music_album
while True:
singer=input("请输入歌手名字(或者输入'quit'退出):")
if singer.lower()=='quit':
break
album=input("请输入专辑名字:")
number=input("请输入专辑中歌曲数量(可选择,没有请按enter键):")
if number:
album=make_album(singer,album,number)
else:
album=make_album(singer,album)
print(album)
请输入歌手名字(或者输入'quit'退出):陈奕迅
请输入专辑名字:淘汰
请输入专辑中歌曲数量(可选择,没有请按enter键):
{'singer name': '陈奕迅', 'album name': '淘汰'}
请输入歌手名字(或者输入'quit'退出):Taylor
请输入专辑名字:1989
请输入专辑中歌曲数量(可选择,没有请按enter键):10
{'singer name': 'Taylor', 'album name': '1989', 'number': '10'}
请输入歌手名字(或者输入'quit'退出):quit
【加入break】的办法
在input下一行加入if, break。
4. 传递列表
将列表传递给函数后,函数就能直接访问其内容。下面使用函数来提高处理列表的效率。
下面的示例将一个名字列表传递给一个名为greet_users()的函数,这个函数问候列表中的每个人。
def greating_lists(names):#建立函数 # 问候
'''给列表中的用户打招呼'''
for name in names:
print(f'Hello! {name.title()}.')
usernames=['feifei','ashley','tony']# 发送列表
greating_lists(usernames)#调用列表-实参
在这个代码中,实参是函数调用中的 `usernames`,它传递给了 `greet_users` 函数。具体来说,`usernames` 是一个包含字符串元素的列表,即 `[‘feifei’,’tony’,’ashley’]`。这个列表被传递给 `greet_users` 函数,然后在函数内部,通过 `for` 循环遍历列表中的每个元素,并对每个元素执行一些操作,生成问候消息并打印出来。
【在函数中修改列表-两个函数】
主程序:
unprinted_designs = ['iphone case','robot pendant','dodecahedron']
completed_models = []
print_models(unprinted_designs,completed_models)
show_completed_models(completed_models)
我们创建了一个未打印的设计列表,还创建了一个空列表,用于存储打印好的模型。接下来,由于我们已经定义了两个函数,因此只需调用它们并传入正确的实参即可。我们调用print_models()并向它传递两个列表;像预期的一样,print_models()模拟打印设计的过程。接下来,我们调用show_completed_models(),并将打印好的模型列表传递给它,让其能够指出打印了哪些模型。描述性的函数名让别人阅读这些代码时也能明白,虽然其中没有任何注释。
这个程序还演示了这样一种理念,即每个函数都应只负责一项具体的工作。第一个函数打印每个设计,而第二个显示打印好的模型;这优于使用一个函数来完成两项工作。编写函数时,如果你发现它执行的任务太多,请尝试将这些代码划分到两个函数中。别忘了,总是可以在一个函数中调用另一个函数,这有助于将复杂的任务划分成一系列的步骤。
【禁止函数修改列表】
有时候,需要禁止函数修改列表。例如,假设像前一个示例那样,你有一个未打印的设计列表,并编写了一个将这些设计移到打印好的模型列表中的函数。你可能会做出这样的决定:即便打印所有设计后,也要保留原来的未打印的设计列表,以供备案。
本来打印了之后,unprinted designs 就没了
function_name (list_name[:]) 使用切片之后,可以保留原来的unprinted_designs
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(unprinted_designs)
结果:
Printing model:dodecahedron
Printing model:robot pendant
Printing model:iphone case
The following models have been printed:
dodecahedron
robot pendant
iphone case
['iphone case', 'robot pendant', 'dodecahedron']
去掉切片后的结果:
Printing model:dodecahedron
Printing model:robot pendant
Printing model:iphone case
The following models have been printed:
dodecahedron
robot pendant
iphone case
[]
虽然向函数传递列表的副本可保留原始列表的内容,但除非有充分的理由需要传递副本,否则还是应该将原始列表传递给函数,因为让函数使用现成列表可避免花时间和内存创建副本,从而提高效率,在处理大型列表时尤其如此。
【练习】
8-9 魔术师:创建一个包含魔术师名字的列表,并将其传递给一个名为show_magicians()的函数,这个函数打印列表中每个魔术师的名字。
def show_magicians(magicians):
for magician in magicians:
print(magician)
if __name__ == "__main__":
# 创建包含魔术师名字的列表
magicians_list = ["feifei", "ashley", "tony"]
# 调用show_magicians()函数并传递列表
print("魔术师列表:")
show_magicians(magicians_list)
8-10 了不起的魔术师:在你为完成练习8-9而编写的程序中,编写一个名为make_great()的函数,对魔术师列表进行修改,在每个魔术师的名字中都加入字样“the Great”。调用函数show_magicians(),确认魔术师列表确实变了。
def show_magicians(magicians):
for magician in magicians:
print(magician)
def make_great_magicians(magicians):
for i in range(len(magicians)):
magicians[i]=f'The Great {magicians[i]}.'
print(magicians[i])
if __name__ == "__main__":
# 创建包含魔术师名字的列表
magicians_list = ["feifei", "ashley", "tony"]
# 调用show_magicians()函数并传递列表
print("原始魔术师列表:")
show_magicians(magicians_list)
print("新的魔术师列表:")
make_great_magicians(magicians_list)
# 调用show_magicians()函数显示修改后的魔术师列表
8
-11 不变的魔术师:修改你为完成练习8-10而编写的程序,在调用函数make_great()时,向它传递魔术师列表的副本。由于不想修改原始列表,请返回修改后的列表,并将其存储到另一个列表中。分别使用这两个列表来调用show_magicians(),确认一个列表包含的是原来的魔术师名字,而另一个列表包含的是添加了字样“the Great”的魔术师名字。
def show_magicians(magicians):
for magician in magicians:
print(magician[:])
def make_great_magicians(magicians):
for i in range(len(magicians)):
magicians[i]=f'The Great {magicians[i]}.'
print(magicians[i])
if __name__ == "__main__":
# 创建包含魔术师名字的列表
magicians_list = ["feifei", "ashley", "tony"]
# 调用show_magicians()函数并传递列表
print("原始魔术师列表:")
show_magicians(magicians_list)
print("新的魔术师列表:")
make_great_magicians(magicians_list)
# 调用show_magicians()函数显示修改后的魔术师列表
print("最初魔术师列表:")
show_magicians(magicians_list[:])
原始魔术师列表:
feifei
ashley
tony
新的魔术师列表:
The Great feifei.
The Great ashley.
The Great tony.
最初魔术师列表:
The Great feifei.
The Great ashley.
The Great tony.
5.传递任意数量的实参(*)
有时候,你预先不知道函数需要接受多少个实参,好在Python允许函数从调用语句中收集任意数量的实参。
def feifei_behaviors(*behavior):#通过加星号调用多个函数
print(f'飞飞正在:{behavior}')
feifei_behaviors('拉粑粑')
feifei_behaviors('吃粑粑','吃屎','被茵茵看着拉屎')
下面的函数只有一个形参*behavior,但不管调用语句提供了多少实参,这个形参都将它们统统收入囊中。
def feifei_behaviors(*behaviors):#通过加星号调用多个函数
print(f'飞飞正在:')
for behavior in behaviors:
print(f' {behavior}')
feifei_behaviors('拉粑粑')
feifei_behaviors('吃粑粑','吃屎','被茵茵看着拉屎')
飞飞正在:
拉粑粑
飞飞正在:
吃粑粑
吃屎
被茵茵看着拉屎
不管收到的是一个值还是三个值,这个函数都能妥善地处理。
【结合使用位置实参和任意数量实参】
def behaviors(name,*behaviors):#通过加星号调用多个函数
print(f'{name}正在:')
for behavior in behaviors:
print(f' {behavior}')
behaviors('Tony','学习')
behaviors('飞飞','吃粑粑','吃屎','被茵茵看着拉屎')
基于上述函数定义,Python将收到的第一个值存储在形参name中,并将其他的所有值都存储在元组behaviors中。在函数调用中,首先指定表示name的实参,然后根据需要指定任意数量的行为。
【使用任意数量的关键字实参】
你知道你将收到有关用户的信息,但不确定会是什么样的信息。在下面的示例中,函数build_profile()接受名和姓,同时还接受任意数量的关键字实参:
我们将名和姓加入到这个字典中,因为我们总是会从用户那里收到这两项信息。
之后,我们遍历字典user_info中的键—值对,并将每个键—值对都加入到字典profile中。最后,我们将字典profile返回给函数调用行。
def build_profile(first,last,**user_info):#**可变关键字参数,除了First和last
"""创建一个字典,其中包含我们知道的有关用户的一切"""
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-12 三明治:
#编写一个函数,它接受顾客要在三明治中添加的一系列食材。这个函数只有一个形参(它收集函数调用中提供的所有食材),
# 并打印一条消息,对顾客点的三明治进行概述。
# 调用这个函数三次,每次都提供不同数量的实参。
def pizza(*toppings):
print("The pizza contains:")
for topping in toppings:
print(f'{topping}')
pizza('Baconic')
pizza('Baconic','Fruit')
pizza('Baconic','Fruit','Chicken')
8-13 用户简介:复制前面的程序user_profile.py,在其中调用build_profile()来创建有关你的简介;调用这个函数时,指定你的名和姓,以及三个描述你的键-值对。
def build_profile(first,last,**user_info):#**可变关键字参数,除了First和last
"""创建一个字典,其中包含我们知道的有关用户的一切"""
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('Ashhley','Zhang',
age='22',
field='public heath')
print(user_profile)
8-14 汽车:编写一个函数,将一辆汽车的信息存储在一个字典中。这个函数总是接受制造商和型号,还接受任意数量的关键字实参。这样调用这个函数:提供必不可少的信息,以及两个名称—值对,如颜色和选装配件。
#8-14 汽车:编写一个函数,将一辆汽车的信息存储在一个字典中。
# 这个函数总是接受制造商和型号,还接受任意数量的关键字实参。
# 这样调用这个函数:提供必不可少的信息,以及两个名称—值对,如颜色和选装配件。
def car_profile(producer,type,**user_info):#**可变关键字参数,除了First和last
"""创建一个字典,其中包含我们知道的有关用户的一切"""
profile = {}
profile['producer'] = producer
profile['type'] = type
for key,value in user_info.items():
profile[key] = value
return profile
user_profile = car_profile('BMW','5-generation',
color='white',
cost='10w')
print(user_profile)
6. 将函数存储在模块中
函数的优点之一是,使用它们可将代码块与主程序分离。通过给函数指定描述性名称,可让主程序容易理解得多。你还可以更进一步,将函数存储在被称为模块的独立文件中,再将模块导入到主程序中。import语句允许在当前运行的程序文件中使用模块中的代码。
【导入整个模块import】无需冒号
可以在另一个文件里 通过import直接调取(文档直接使用和迁移) 不需要冒号
【导入特定的函数 from import】
from module_name import function_name:
pizza.py文件中:
def lababa(name,numbers):
"""概述要制作的比萨"""
print(f"{name} 拉了质量为{numbers}kg的粑粑。")
def study(name, hours):
print(f"{name} 学了{hours}小时。")
建立一个新文件:
import pizza #调用pizza程序
pizza.lababa('feifei','2')#调用lababa方法
pizza.study('tony','24') #调用study方法
feifei 拉了质量为2kg的粑粑。
tony 学了24小时。
from pizza import lababa #调用pizza程序中的lababa方法
lababa('feifei','2')#调用lababa方法
lababa('godfly','10')#调用lababa方法
feifei 拉了质量为2kg的粑粑。
godfly 拉了质量为10kg的粑粑。
【给函数指定别名 from import as】
如果要导入的函数的名称可能与程序中现有的名称冲突,或者函数的名称太长,可指定简短而独一无二的别名——函数的另一个名称,类似于外号。要给函数指定这种特殊外号,需要在导入它时这样做。
from pizza import lababa as lb #调用pizza程序中的lababa方法
lb('feifei','2')#调用lababa方法
lb('godfly','10')#调用lababa方法
【给模块指定别名 import as】
p. function
import pizza as p #改变模块的名字
p.lababa('feifei','2')#调用lababa方法
p.lababa('godfly','10')#调用lababa方法
【导入模块中的所有函数*】
from pizza import *
然而,使用并非自己编写的大型模块时,最好不要采用这种导入方法:如果模块中有函数的名称与你的项目中使用的名称相同,可能导致意想不到的结果:Python可能遇到多个名称相同的函数或变量,进而覆盖函数,而不是分别导入所有的函数。
最佳的做法是,要么只导入你需要使用的函数,要么导入整个模块并使用句点表示法。
7. 函数编写指南
(1)所有的import语句都应放在文件开头,唯一例外的情形是,在文件开头使用了注释来描述整个程序。
(2)应给函数指定描述性名称,且只在其中使用小写字母和下划线。描述性名称可帮助你和别人明白代码想要做什么。给模块命名时也应遵循上述约定。每个函数都应包含简要地阐述其功能的注释,该注释应紧跟在函数定义后面,并采用文档字符串格式。
(3)给形参指定默认值时,等号两边不要有空格。
user_profile = car_profile('BMW','5-generation',
color='white',
cost='10w')
对于函数调用中的关键字实参,也应遵循这种约定:
animal_lists(category='pig',name='feifei')
(4)长度与缩进:
PEP 8(https://www.python.org/dev/peps/pep-0008/)建议代码行的长度不要超过79字符,这样只要编辑器窗口适中,就能看到整行代码。如果形参很多,导致函数定义的长度超过了79字符,可在函数定义中输入左括号后按回车键,并在下一行按两次Tab键,从而将形参列表和只缩进一层的函数体区分开来。
(5)如果程序或模块包含多个函数,可使用两个空行将相邻的函数分开,这样将更容易知道前一个函数在什么地方结束,下一个函数从什么地方开始。
【练习】
8-15 打印模型:
#8-15 打印模型:将示例print_models.py中的函数放在另一个名为printing_functions.py的文件中;
# 在print_models.py的开头编写一条import语句,并修改这个文件以使用导入的函数。
import printing_function as pf
pf.lababa('ashley')
pf:
def lababa(name):
print(f'{name}正在拉粑粑')
lababa('godfly')
8-16 导入:选择一个你编写的且只包含一个函数的程序,并将这个函数放在另一个文件中。在主程序文件中,使用下述各种方法导入这个函数.
#import module_name
#from module_name import function_name
#from module_name import function_name as fn
#import module_name as mn
#from module_name import *
import printing_function
printing_function.lababa('ashley')
from printing_function import lababa
lababa('ashley')
from printing_function import lababa as lb
lb('ashley')
import printing_function as pf
pf.lababa('ashley')
from printing_function import*
lababa('ashley')
8-17 函数编写指南:选择你在本章中编写的三个程序,确保它们遵循了本节介绍的函数编写指南。
小结
在本章中,你学习了:
(1)如何编写函数,以及如何传递实参,让函数能够访问完成其工作所需的信息;
(2)如何使用位置实参和关键字实参,以及如何接受任意数量的实参;
(3)显示输出的函数和返回值的函数;如何将函数同列表、字典、if语句和while循环结合起来使用。
(4)你还知道了如何将函数存储在被称为模块的独立文件中,让程序文件更简单、更易于理解。
(5)最后,你学习了函数编写指南,遵循这些指南可让程序始终结构良好,并对你和其他人来说易于阅读。
程序员的目标之一是,编写简单的代码来完成任务,而函数有助于你实现这样的目标。它们让你编写好代码块并确定其能够正确运行后,就可置之不理。确定函数能够正确地完成其工作后,你就可以接着投身于下一个编码任务。
(1)多次使用:函数让你编写代码一次后,想重用它们多少次就重用多少次。需要运行函数中的代码时,只需编写一行函数调用代码,就可让函数完成其工作。需要修改函数的行为时,只需修改一个代码块,而所做的修改将影响调用这个函数的每个地方。
(2)容易阅读:使用函数让程序更容易阅读,而良好的函数名概述了程序各个部分的作用。相对于阅读一系列的代码块,阅读一系列函数调用让你能够更快地明白程序的作用。
(3)函数还让代码更容易测试和调试:如果程序使用一系列的函数来完成其任务,而其中的每个函数都完成一项具体的工作,测试和维护起来将容易得多:你可编写分别调用每个函数的程序,并测试每个函数是否在它可能遇到的各种情形下都能正确地运行。经过这样的测试后你就能信心满满,深信你每次调用这些函数时,它们都将正确地运行。