8.1 定义函数
1 | def greet_user(): |
输出结果为:
1 | Hello! |
使用关键字def来告诉Python,要定义一个函数。这是函数定义,向Python指出了函数名,还可能在圆括号内指出函数为完成任务需要什么样的信息。
用三对引号括起来的文本称为文档字符串(docstring)的注释,描述了函数是做什么的。
8.1.1 向函数传递信息
1 | def greet_user(username): |
输出结果为:
1 | Hello,zhangsan! |
8.1.2 实参和形参
在函数greet_user()的定义中,变量username是一个形参(parameter),即函数完成工作所需的信息。在代码greet_user(“zhangsan”)中,值“zhangsan”是一个实参(argument),即调用函数时传递给函数的信息。
8.2 传递实参
向函数传递实参的方式很多:
- 使用位置实参,这要求实参的顺序与形参的顺序相同;
- 使用关键字实参,其中每个实参都由变量名和值组成;
- 使用列表和字典。
8.2.1 位置实参
调用函数时,Python必须将函数调用中的每个实参都关联到函数定义中的一个形参。为此,最简单的关联方式就是基于实参的顺序。这种关联方式称为位置实参。
1 | def describe_person(person_name, person_age): |
输出结果为:
1 | my name is zhangsan,i am 24 yesrs old~ |
多次调用函数
1
2
3
4
5def describe_person(person_name, person_age):
print(f"my name is {person_name},i am {person_age} yesrs old~")
describe_person("zhangsan", 24)
describe_person("lisi", 30)输出结果为:
1
2my name is zhangsan,i am 24 yesrs old~
my name is lisi,i am 30 yesrs old~位置实参的顺序很重要
使用位置实参来调用函数时,如果实参的顺序不正确,结果可能出乎意料:
1
2
3
4def describe_person(person_name, person_sex):
print(f"my name is {person_name},i am {person_sex}")
describe_person("male", "zhangsan")输出结果为:
1
my name is male,i am zhangsan
8.2.2 关键字实参
关键字实参是传递给函数的名称值对。因为直接在实参中将名称和值关联起来,所以向函数传递实参时不会混淆。关键字实参让你必须考虑函数调用中的实参顺序,还清楚地指出了函数调用中各个值的用途。
1 | def describe_person(person_name, person_sex): |
输出结果为:
1 | my name is zhangsan,i am male |
注意:使用关键字实参时,务必准确指定函数定义中的形参名。
8.2.3 默认值
编写函数时,可给每个形参指定默认值。在调用函数中给形参提供了实参时,Python将使用指定的实参数;否则,将使用形参的默认值。因此形参指定默认值后,可在函数调用中省略相应的实参。使用默认值可简化函数调用,还可清楚第指出函数的典型用法。
1 | def describe_person(person_name, person_sex = 'male'): |
输出结果为:
1 | my name is zhangsan,i am male |
使用默认值时,必须先在形参列表中列出没有默认值的形参,再列出有默认值的形参。这让Python依然能够正确地解读位置实参。
8.2.4 等效的函数调用
鉴于可混合使用位置实参,关键字实参和默认值,通常有多种等效的函数调用方式。
1 | def describe_person(person_name, person_sex = 'male'): |
输出结果为:
1 | my name is zhangsan,i am male |
8.3 返回值
函数并非总是直接显示输出,它还可以处理一些数据,并返回一个或一组值。函数返回的值称为返回值。
8.3.1 返回简单值
1 | def get_formatted_name(first_name, last_name): |
输出结果为:
1 | Zhang San |
8.3.3 返回字典
函数可返回任何类型的值,包括列表和字典等较复杂的数据结构。
1 | def build_person(first_name, last_name): |
输出结果为:
1 | {'first': 'zhang', 'last': 'san'} |
在条件测试中,None相当于False。
8.4 传递列表
1 | def greet_users(names): |
输出结果为:
1 | Hello zhangsan |
8.4.1 在函数中修改列表
将列表传递给函数后,函数就可对其进行修改。在函数中对这个列表所做的任何修改都是永久性的。
1 | def greet_users(names): |
输出结果为:
1 | ['zhangsan', 'lisi', 'wangwu'] |
8.4.2 禁止函数修改列表
如果想在函数中操作列表而不影响原列表,可将列表的副本传递给函数,可以这样做:
1 | function_name(list_name[:]) |
切片表示法[:]创建列表的副本。
虽然向函数传递列表的副本可保留原始列表的内容,但除非有充分的理由,否则还是应该将原始列表传递给函数。这是因为让函数使用现成的列表可以避免花时间和内存创建副本,从而提高效率,在处理大型列表时尤其如此。
8.5 传递任意数量的实参
有时候,预先不知道函数需要接受多少个实参,好在Python允许函数从调用语句中收集任意数量的实参。
1 | def greet_users(*names): |
输出结果为:
1 | Hello zhangsan |
形参名*names中的星号让Python创建一个名为names的空元组,并将收到的所有值都封装到这个元组中。
8.5.1 结合使用位置实参和任意数量实参
如果要让函数接受不同类型的实参,必须在函数定义中将接纳任意数量实参的形参放在最后。Python先匹配位置实参和关键字实参,再将余下的实参都收集到最后一个形参中。
1 | def make_pizza(size, *toppings): |
输出结果为;l
1 | Making a 16-inch pizza with the following topping: |
经常i看到通用形参名*args,它也收集任意数量的位置实参。
8.5.2 使用任意数量的关键字实参
有时候,需要接受任意数量的实参,但预先不知道传递给函数的会是什么样的信息。在这种情况下,可将函数编写成能够接受任意数量的键值对——调用语句提供了多少就接受多少。
1 | def build_profile(first, last, **user_info): |
输出结果为:
1 | {'location': 'chongqing', 'field': 'computer science', 'first_name': 'zhang', 'last_name': 'san'} |
形参**user_info中的两个星号让Python创建一个名为user_info的空字典,并将接收到的所有名称值对都放到这个字典中。
经常会看到形参名**kwargs,它用于收集任意数量的关键字实参。
8.6 将函数存储在模块中
使用函数的优点之一是可将代码块与主程序分离。通过给函数指定描述性名称,可让主程序容易理解得多。还可以更进一步,将函数存储在称为模块的独立文件中,再将模块导入到主程序中。
8.6.1 导入整个模块
模块是扩展名为.py的文件,包含要导入到程序中的代码。
1 | import module_name |
只需要编写一条import语句并在其中指定模块名,就可在程序中使用该模块中的所有函数。如果使用这种import语句导入了名为module_name.py的整个模块,就可以使用下面的语法来使用其中的任何一个函数:
1 | module_name.function_name() |
8.6.2 导入特定的函数
还可以导入模块中的特定函数。
1 | from module_name import function_name |
通过用逗号分隔函数名,可根据需要从模块中导入任意数量的函数:
1 | from module_name import function_0, function_1, function_2 |
由于在import语句中显示地导入了函数,调用时只需指定其名称即可。
8.6.3 使用as给函数指定别名
如果要导入函数的名称可能与程序中现有的名称冲突,或者函数的名称太长,可指定简短而独一无二的别名:函数的另一个名称,类似于外号。要给函数取这种特殊外号,需要在导入它时指定。
1 | from module_name import function_name as fn |
8.6.4 使用as给模块指定别名
还可以给模块指定别名。
1 | import module_name as mn |
8.6.5 导入模块中的所有函数
使用星号(*)运算符可让Python导入模块中的所有函数:
1 | from module_name import * |
8.7 函数编写指南
应给函数指定描述性名称,且只在其中使用小写字母和下划线。
给形参指定默认值时,等号两边不要有空格。对于函数调用中的关键字实参,也应遵循这种约定。