目录
一、定义函数
首先函数定义:def + 函数名 +()+ :,函数定义后面的所有缩进体构成函数体,三引号内的文本为文本字符串——描述函数是做什么,print( )是函数体内唯一一行代码,因此greet_user()只做了一项工作:打印Hello!
函数调用让python执行函数的代码,要调用函数只需要指定函数名 +()。函数调用的方式:a.函数名+(),()内可以有内容;b.将函数名+()赋值给一个变量,再打印变量。
def greet_user(): #函数定义
"""显示简单的字符串"""
print("Hello!")
greet_user()
Hello!
1.向函数传递信息
在函数定义def greet_user( )的括号中添加username,可让函数接受你给username指定的任何值。
def greet_user(username):
print(f"Hello, {username}.")
greet_user('sarah')
Hello, sarah.
2.实参和形参
前面定义函数greet_user( )时,变量username是形参,值‘sarah'是实参。形参是可以被顶替的幌子,存在于定义参数中的括号和函数体中;实参是实在可打印出来的,存在于函数调用。形参不需要打引号,实参需要打引号。
在greet_user('jesse')中,将实参’jesse’传递给了函数greet_user(),这个值被赋给了形参username。注意:有时形参和实参不分。
二、传递实参
函数定义中可能包含多个形参,因此函数调用中可能也包括多个实参。向函数传递实参的方式有很多,可使用位置参数,要求形参和实参的顺序相同;也可使用关键字参数,其中每个实参都由变量名和值组成。
1.位置实参
调用函数时,python必须函数调用中的每个实参关联到函数定义中的一个形参。最简单的关联方式是基于实参的顺序,这种关联方式被称为位置实参。
函数定义表明需要一种动物类型和一个名字。在调用函数时也需要按顺序提供一种动物类型和一个名字。
def describe_pet(animal_type,pet_name):
print(f"I have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name}.")
describe_pet('hamaster','harry') #将实参hamaster关联到形参animal_type,将实参harry关联到形参pet_name
I have a hamaster.
My hamaster's name is harry.
多次调用函数:可根据需要调用函数任意次,python将按照顺序将函数调用中的实参关联到函数定义中相应的形参。位置实参的顺序很重要。
def describe_pet(animal_type,pet_name):
print(f"I have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name}.")
describe_pet('hamaster','harry')
describe_pet('dog','willie')
I have a hamaster.
My hamaster's name is harry.
I have a dog.
My dog's name is willie.
2.关键字实参
关键词实参是传递给函数的名称值对。在实参中将名称和值关联起来,所有向函数传递实参时不会混淆。使用关键词实参时,一定要准确指定函数定义中的形参名。
def describe_pet(animal_type,pet_name):
print(f"I have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name}.")
describe_pet(animal_type = 'hamaster',pet_name = 'harry') #形参不需要打引号,实参需要打引号
I have a hamaster.
My hamaster's name is harry.
3.默认值
编写函数时,可以给形参指定默认值。若调用函数时,指定了实参,python将使用指定的实参值;否则,将使用形参的默认值。默认值出现在定义函数中,且要放在后面。
给animal_type指定了默认值,在调用函数时,如果没有给animal_type指定实参,将使用默认值dog。所以函数调用中只包含宠物的名字,然而python依旧将实参视为位置参数,这个实参将关联到定义中的第一个形参。故可以在函数调用时,只提供小狗的名字。
def describe_pet(pet_name,animal_type = 'dog'):
print(f"I have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name}.")
describe_pet(pet_name = 'willie')
#等价于 describe_pet('willie')
I have a dog.
My dog's name is willie.
4.等效的函数调用
def describe_pet(pet_name,animal_type = 'dog'):
print(f"I have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name}.")
describe_pet('willie')
describe_pet(pet_name = 'willie')
describe_pet('harry','hamster')
describe_pet(pet_name = 'harry',animal_type = 'hamaster')
describe_pet(animal_type = 'hamaster',pet_name = 'harry')
5.避免实参错误
若实参多于或少于函数完成工作所需的信息时,将出现实参不匹配错误
def describe_pet(pet_name,animal_type = 'dog'):
print(f"I have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name}.")
describe_pet()
TypeError: describe_pet() missing 1 required positional argument: 'pet_name' #指出函数调用少了1个实参,并指出了相应的实参名称
三、返回值
函数并非总是显示输出,还可以处理数据。函数返回的值称为返回值。在函数中,可使用return语句将值返回到调用函数的代码行。
在函数中,两种打印方式:a.函数体中包括print,函数调用中直接用函数名+();b.函数体中不包括print,是变量的等式,函数体中要return,函数调用中包括print。
1.返回简单值
调用返回值函数时,需提供一个变量,以便将返回的值赋给它。原本只需要输入print("Jimi Hendrix")就可输出,但在需要分别存储大量名和姓的大型程序中,像get_formatted_name()这样的函数非常有用。return语句可将值返回到调用函数的代码行,实质就是调用函数体中有用的那一行full_name = f"{first_name} {last_name}" 再根据其设定实参。return后面都要跟变量,而非函数名
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)
Jimi Hendrix
def get_formatted_name(first_name,last_name):
full_name = f"{first_name} {last_name}"
print(f"{full_name.title()}")
get_formatted_name('jimi','hendrix')
2.让实参变成可选的(将可选的形参设为空字符串+if语句)
让实参变成可选,可以使得只在必要时提供额外信息,使用默认值来让实参变成可选的。
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('john','lee','hooker')
print(musician)
John Lee Hooker
并非所有人都有中间名,若只提供名和姓,它将不能正确运行,为了让中间名可选,可给形参指定一个空的默认值。将形参middle_name的默认值设为一个空字符串,并将其移到形参列表末尾。
def get_formatted_name(first_name,last_name,middle_name = ""): #可选形参
if middle_name: #如果middle_name为True #if语句
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('john','hooker','lee') #若要指定中间名,就必须确保它是最后一个实参,这样才能将位置正确的关联到形参
print(musician)
Jimi Hendrix
John Lee Hooker
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'}
在字典中添加可选形参。将可选形参的默认值设为特殊值None或空字符串(表示变量没有值)。可将None视为占位符,在条件测试中,None相当于False,如果函数调用中包含形参的值,这个值将存储在字典中。
def build_person(first_name,last_name,age = None): #可选形参
person = {'first':first_name,'last':last_name} #创建字典,可选形参先不用加入字典
if age: #对可选形参进行管理,if语句
person['age'] = age #若需要可选形参,再在字典中添加键值对
return person #返回字典
musician = build_person('jimi','hendrix',age = 21)
print(musician)
{'first': 'jimi', 'last': 'hendrix', 'age': 21}
4.结合使用函数和while循环
可将函数同前面介绍的任何python结构结合起来。
def get_formatted_name(first_name,last_name):
full_name = f"{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(f"\nHello,{formatted_name}!")
Please tell me your name,
(enter 'q' at any time to quit)
First name: zuo
Last name: xin
Hello,Zuo Xin!
Please tell me your name,
(enter 'q' at any time to quit)
First name: q
注意:所有交互式代码都可以用文本编辑器编写,在终端上直接运行。运行方法参照第一篇博文(f: —— cd 路径 —— dir查看内容——python +文件)
四、传递列表
将列表传递给函数后,函数就能直接访问其内容。
def greet_users(names):
for name in names:
msg = f"Hello,{name.title()}."
print(msg)
usernames = ['hannah','ty','margot'] #定义了一个用户列表usernames
greet_users(usernames) #调用函数,并将列表传递给了它
Hello,Hannah.
Hello,Ty.
Hello,Margot.
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 {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 = ['dodecahedron','robot pendant','phone case']
completed_models = []
print_models(unprinted_designs,completed_models) #由于已经定义了两个函数,只需调用它们并传入正确的实参即可。
show_completed_models(completed_models)
Printing phone case
Printing robot pendant
Printing dodecahedron
The following models have been printed:
phone case
robot pendant
dodecahedron
每个函数都应只负责一项具体的任务,可以在一个函数中调用另一个函数。编写函数时发现执行的任务太多,可尝试将这些代码划分到两个函数。
2.禁止函数修改列表
即便打印好了所有设计,也要保留原来的未打印的设计列表,以供备案。但由于将所有的设计都移出了unprinted_designs,这个列表变成了空的,原来的列表没有了。为解决这个问题,可向函数传递列表的副本而非原件。用切片表示法创建列表。
print_models(unprinted_designs[:],completed_models)
虽然向函数传递列表的副本可保留原始列表的内容,但除非有充分理由,否则将原始列表传递给函数,因为让函数使用现成列表可避免花时间和内存创建副本,提高效率,尤其是处理大型列表。
五、传递任意数量实参
形参名*toppings中的*星号让Python创建一个名为toppings的空元组,并将收到的所有值都封装到这个元组中
def make_pizza(*toppings):
"""概述要制作的比萨"""
print("\nMaking a pizza with the following toppings: ")
for topping in toppings:
print(f"-{topping}")
make_pizza("pepperoni")
make_pizza("mushrooms","green pepers","extra cheese")
Making a pizza with the following toppings:
-pepperoni
Making a pizza with the following toppings:
-mushrooms
-green pepers
-extra cheese
结合使用位置实参和任意数量实参:函数接受不同类型的实参,必须在函数定义中将接纳任意数量实参的形参放在最后。Python将收到的第一个值赋给形参size,并将其他所有值都存储在元组toppings中。形参名*args,它也收集任意数量的位置实参
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(22,"mushrooms","green pepers","extra cheese")
Making a 16-inch pizza with the following toppings:
-pepperoni
Making a 22-inch pizza with the following toppings:
-mushrooms
-green pepers
-extra cheese
使用任意数量的关键字实参,形参**user_info中的**两个星号让Python创建一个名为user_info的空字典,形参名**kwargs,它用于收集任意数量的关键字实参。
def build_profile(first,last,**user_info):
"""创建字典,包含我们知道的用户一切信息"""
user_info['first_name'] = first #将名和姓加入了字典user_info中,字典添加键值对与函数参数结合
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'}
六、将函数存储在模块中
将函数存储在称为模块的独立文件中,再将模块导入到主程序中,使用import语句
隐藏程序代码的细节,将重点放在程序的高层逻辑上;重用;共享;使用其他程序员编写的函数库
要让函数是可导入的,得先创建模块。模块是扩展名为.py的文件,包含要导入到程序中的代码。
1.导入整个模块
pizza.py文件中只有函数make_pizza( ),在pizza.py所在的目录中创建makeing_pizzas.py的文件
def make_pizza(size,*toppings):
"""概述要制作的比萨"""
print(f"\nMaking a {size}-inch pizza with the following toppings: ")
for topping in toppings:
print(f"-{topping}")
要调用被导入模块中的函数, 指定模块名和函数名,中间用句点分割。
import pizza
pizza.make_pizza(16,'pepperoni')
pizza.make_pizza(22,'mushrooms','green pepers','extra cheese')
Making a 16-inch pizza with the following toppings:
-pepperoni
Making a 22-inch pizza with the following toppings:
-mushrooms
-green pepers
-extra cheese
2.导入特定函数
调用函数时无需使用句点,调用时只需要指定函数名
from pizza import make_pizza
make_pizza(16,'pepperoni')
make_pizza(22,'mushrooms','green pepers','extra cheese')
3.使用as给函数指定别名
导入的函数名称可能与程序中的名称相冲突,或函数名称太长,可用别名:函数另一个名称,外号
from pizza import make_pizza as mp
mp(16,'pepperoni')
mp(22,'mushrooms','green pepers','extra cheese')
4.使用as 给模块命名
import pizza as p
p.make_pizza(16,'pepperoni')
p.make_pizza(22,'mushrooms','green pepers','extra cheese')
5.导入模块中所有函数
用星号(*)运算符可让Python导入模块中的所有函数。因导入了每个函数,无需句点表示。但尽量不要使用这种方法,若模块中有函数的名称与当前项目中使用的名称相同,会出错。
from pizza import *
make_pizza(16,'pepperoni')
make_pizza(22,'mushrooms','green pepers','extra cheese')
要么只导入需要的函数,要么导入整个模块用句点表示法。
七、函数编写指南
应给函数指定描述性名称,且只在其中使用小写字母和下划线。
注释应紧跟在函数定义后面,并采用文档字符串格式。
给形参指定默认值时,等号两边不要有空格。
若形参很多,使函数定义的长度超过了79字符,可在函数定义中输入左括号后按回车键,并在下一行按两次Tab键,将形参列表和只缩进一层的函数体区分开来。
程序或模块包含多个函数,可使用两个空行将相邻的函数分开,这样将更容易知道前一个函数在什么地方结束。
import语句都应放在文件开头,除非开头为注释。