目录
一、定义函数
二、传递实参
三、返回值
四、传递列表
五、传递任意数量实参
六、将函数存储在模块中
七、函数编写指南
首先函数定义:def + 函数名 +()+ :,函数定义后面的所有缩进体构成函数体,三引号内的文本为文本字符串——描述函数是做什么,print( )是函数体内唯一一行代码,因此greet_user()只做了一项工作:打印Hello!
函数调用让python执行函数的代码,要调用函数只需要指定函数名 +()。函数调用的方式:a.函数名+(),()内可以有内容;b.将函数名+()赋值给一个变量,再打印变量。
def greet_user(): #函数定义 """显示简单的字符串""" print("Hello!") greet_user()
Hello!
在函数定义def greet_user( )的括号中添加username,可让函数接受你给username指定的任何值。
def greet_user(username): print(f"Hello, {username}.") greet_user('sarah')
Hello, sarah.
前面定义函数greet_user( )时,变量username是形参,值‘sarah'是实参。形参是可以被顶替的幌子,存在于定义参数中的括号和函数体中;实参是实在可打印出来的,存在于函数调用。形参不需要打引号,实参需要打引号。
在greet_user('jesse')中,将实参’jesse’传递给了函数greet_user(),这个值被赋给了形参username。注意:有时形参和实参不分。
函数定义中可能包含多个形参,因此函数调用中可能也包括多个实参。向函数传递实参的方式有很多,可使用位置参数,要求形参和实参的顺序相同;也可使用关键字参数,其中每个实参都由变量名和值组成。
调用函数时,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.
关键词实参是传递给函数的名称值对。在实参中将名称和值关联起来,所有向函数传递实参时不会混淆。使用关键词实参时,一定要准确指定函数定义中的形参名。
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.
编写函数时,可以给形参指定默认值。若调用函数时,指定了实参,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.
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')
若实参多于或少于函数完成工作所需的信息时,将出现实参不匹配错误
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。
调用返回值函数时,需提供一个变量,以便将返回的值赋给它。原本只需要输入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')
让实参变成可选,可以使得只在必要时提供额外信息,使用默认值来让实参变成可选的。
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
要返回字典,只需要在函数体中创建字典。
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}
可将函数同前面介绍的任何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.
列表传递给函数后,函数就可对列表进行修改,且是永久性的,所有可以高效的处理大量数据。需要打印的设计放在一个列表中,打印后移到另一个列表中,不适用函数的情况下的代码:
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
每个函数都应只负责一项具体的任务,可以在一个函数中调用另一个函数。编写函数时发现执行的任务太多,可尝试将这些代码划分到两个函数。
即便打印好了所有设计,也要保留原来的未打印的设计列表,以供备案。但由于将所有的设计都移出了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的文件,包含要导入到程序中的代码。
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
调用函数时无需使用句点,调用时只需要指定函数名
from pizza import make_pizza make_pizza(16,'pepperoni') make_pizza(22,'mushrooms','green pepers','extra cheese')
导入的函数名称可能与程序中的名称相冲突,或函数名称太长,可用别名:函数另一个名称,外号
from pizza import make_pizza as mp mp(16,'pepperoni') mp(22,'mushrooms','green pepers','extra cheese')
import pizza as p p.make_pizza(16,'pepperoni') p.make_pizza(22,'mushrooms','green pepers','extra cheese')
用星号(*)运算符可让Python导入模块中的所有函数。因导入了每个函数,无需句点表示。但尽量不要使用这种方法,若模块中有函数的名称与当前项目中使用的名称相同,会出错。
from pizza import * make_pizza(16,'pepperoni') make_pizza(22,'mushrooms','green pepers','extra cheese')
要么只导入需要的函数,要么导入整个模块用句点表示法。
应给函数指定描述性名称,且只在其中使用小写字母和下划线。
注释应紧跟在函数定义后面,并采用文档字符串格式。
给形参指定默认值时,等号两边不要有空格。
若形参很多,使函数定义的长度超过了79字符,可在函数定义中输入左括号后按回车键,并在下一行按两次Tab键,将形参列表和只缩进一层的函数体区分开来。
程序或模块包含多个函数,可使用两个空行将相邻的函数分开,这样将更容易知道前一个函数在什么地方结束。
import语句都应放在文件开头,除非开头为注释。