Python入门 — 函数
目录
一、定义函数
1、参数
2、关键字实参
3、默认值
二、返回值
三、传递列表
1、函数修改列表
2、禁止函数修改列表
四、传递任意数量的实参
1、结合位置实参和任意数量的实参
2、任意数量的关键字实参
五、将函数存储在模块中
1、导入整个模块
2、导入特定的函数
3、使用 as 给函数指定别名
4、使用 as 给模块指定别名
5、导入模块中的所有函数
函数编写规范:
函数是带名字的代码块,用于完成具体的工作任务。。当需要在程序中多次执行同一项任务时,无须反复编写完成该任务的代码,只需要调用执行该任务的函数。
一、定义函数
def first_hello():
print("Hello, world!")
# 调用函数
first_hello()
这个程序展示了最简单的函数结构。第一行代码使用关键字 def 来告诉 Python,你要定义一个函数,并向 Python 指出了函数名 first_hello,还可以在括号内指出函数为完成任务需要什么样的信息,即参数。最后,定义以冒号结尾
1、参数
# 定义时,username 是形参
def greet_user(username):
print(f"Hello, {username.title()}!")
# 调用时,Jack 是实参
greet_user('Jack')
在定义 greet_user() 函数时,要求给变量 username 指定一个值。变量 username 是一个形参,即函数完成工作所需的信息。在调用函数时,我们将要让函数使用的信息放在括号内。在 greet_user('Jack') 这个示例中,我们将实参'Jack' 传递给函数 greet_user(),这个值被赋给了形参 username。
如果参数个数较多,一定要注意,在传递参数的时候要对应形参的顺序。如果实参的顺序不正确,结果可能会出乎意料。
def describe_pet(type, name):
print(f"\n我有一只{type}")
print(f"{type}的名字是{name.title()}.")
describe_pet('狗', '小黄')
输出结果:
我有一只狗
狗的名字是小黄.
2、关键字实参
关键字实参是传递给函数的名值对。这样会直接在实参中将名称和值关联起来,关键字实参可以无须考虑函数调用中的实参顺序,也能清楚地指出了函数调用中各个值的用途。
def describe_pet(type, name):
print(f"\n我有一只{type}")
print(f"{type}的名字是{name.title()}.")
describe_pet(type = '狗', name = '小黄')
describe_pet() 函数还和之前一样,但这次调用这个函数时,向 Python 明确地指出了各个实参对应的形参,关键字实参的顺序无关紧要,因为 Python 知道各个值该被赋给哪个形参。
3、默认值
在编写函数时,可以给每个形参指定默认值。如果在调用函数中给形参提供了实参,Python 将使用指定的实参值;否则,将使用形参的默认值。调用 describe_pet() 时,描述的大多是小狗,就可将形参 type 的默认值设置为 '狗'。
def describe_pet(name, type = '狗'):
print(f"\n我有一只{type}")
print(f"{type}的名字是{name.title()}.")
describe_pet(name = '小黄')
注意:在这个函数的定义中,修改了形参的排列顺序。由于给 type 指定了默认值,无须通过实参来指定动物类型,因此函数调用只包含一个实参——名字。但是,Python 依然将这个实参视为位置实参,如果函数调用只包含动物的名字,这个实参将被关联到函数定义中的第一个形参,所以需要调换顺序。
注意:当使用默认值时,必须在形参列表中先列出没有默认值的形参,再列出有默认值的形参。
二、返回值
函数可以处理一些数据,并返回一个或一组值。函数返回的值称为返回值。在函数中,可以使用 return 语句将值返回到调用函数的那行代码。
def build_person(first_name, last_name):
# 返回字典
person = {'first': first_name, 'last': last_name}
return person
man = build_person('小', '黄')
print(man)
输出结果:
{'first': '小', 'last': '黄'}
如果要扩展,添加更多的 man 的信息,比如说年龄、工作职业等等,可以如下:
def build_person(first_name, last_name, age=None):
# age 是带默认值的
person = {'first': first_name, 'last': last_name}
if age:
person['age'] = age
return person
man = build_person('jimi', 'hendrix', age=22)
print(man)
输出结果:
{'first': 'jimi', 'last': 'hendrix', 'age': 22}
在函数定义中,新增了一个可选形参 age,其默认值被设置为特殊值 None(表示变量没有值)。可将 None 视为占位值。在条件测试中,None 相当于 False。
三、传递列表
def greet_users(names):
for name in names:
msg = f"Hello, {name.title()}!"
print(msg)
usernames = ['li', 'liu', 'guo']
greet_users(usernames)
函数会向列表中的每个人发出问候:将 greet_users() 定义成接受一个名字列表,并将其赋给形参 names。在函数外,先定义一个用户列表 usernames,再调用 greet_users() 并将这个列表传递给它。
1、函数修改列表
# 首先创建一个列表
unprinted_designs = ['phone', 'robot', 'car']
completed_models = []
# 打印每个设计后,都将其移到列表 completed_models
while unprinted_designs:
current_design = unprinted_designs.pop()
print(f"打印ing: {current_design}")
completed_models.append(current_design)
# 显示打印好的所有模型
print("\n打印好啦,看看吧:")
for completed_model in completed_models:
print(completed_model)
输出结果:
打印ing: car
打印ing: robot
打印ing: phone打印好啦,看看吧:
car
robot
phone
其实可以整理一下上述代码,让其看起来更舒服,如下:
def print_models(unprinted_designs, completed_models):
while unprinted_designs:
current_design = unprinted_designs.pop()
print(f"打印ing: {current_design}")
completed_models.append(current_design)
def show_completed_models(completed_models):
print("\n打印完啦,看看吧:")
for completed_model in completed_models:
print(completed_model)
unprinted_designs = ['phone', 'robot', 'car']
completed_models = []
print_models(unprinted_designs, completed_models)
show_completed_models(completed_models)
结果与上述结果一致,定义了两个函数,第一个函数负责处理打印设计的工作,第二个函数负责输出打印完成的设计。
2、禁止函数修改列表
现在我们需要满足这样的条件,即便打印了所有的设计,也要保留原来的未打印的设计列表,作为存档。但由于打印后,所有的设计都移出了 unprinted_designs,这个列表变成了空的——原来的列表没有了。那么我们可以向函数传递列表的副本而不是原始列表。这样,函数所做的任何修改都只影响副本,而丝毫不影响原始列表。
要将列表的副本传递给函数,可以这样:切片表示法 [:] 创建列表的副本
function_name(list_name[:])
在上述代码中,即
print_models(unprinted_designs[:], completed_models)
请注意:虽然向函数传递列表的副本可保留原始列表的内容,但除非有充分的理由,否则还是应该将原始列表传递给函数。这是因为,让函数使用现成的列表可避免花时间和内存创建副本,从而提高效率,在处理大型列表时更是如此。
四、传递任意数量的实参
有时候预先不知道函数需要接受多少个实参,但是Python 允许函数从调用语句中收集任意数量的实参。
def make_pizza(*t):
print(t)
make_pizza('pep')
make_pizza('mushrooms', 'green', 'cheese')
形参名 *t 中的星号让 Python 创建一个名为 toppings 的元组,该元组包含函数收到的所有值。
输出结果:
('pep',)
('mushrooms', 'green', 'cheese')
1、结合位置实参和任意数量的实参
def make_pizza(size, *t):
print(size)
print(t)
make_pizza(16, 'pep')
make_pizza(18, 'mushrooms', 'green', 'cheese')
输出结果:
16
('pep',)
18
('mushrooms', 'green', 'cheese')
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('aa', 'bb', location='princeton', field='physics')
print(user_profile)
形参 **user_info 中的两个星号让 Python 创建一个名为 user_info 的字典,该字典包含函数收到的其他所有名值对。
输出结果:
{'location': 'princeton', 'field': 'physics', 'first_name': 'aa', 'last_name': 'bb'}
你可能有这样的疑问,为什么打印出来的字典的顺序和想像的不一样呢?
在代码中,build_profile 函数使用了 **user_info 参数来接收关键字参数。这意味着所有额外的关键字参数(如 location 和 field )都会打包成一个字典 user_info。
当你在函数体内添加 first_name和 last_name键后,字典 user_info 的内容是这样构造的:
- 开始时,user_info 只有 location 和 field 这两个键值对,因为在传递参数的时候就已经加入字典了,而aa 和 bb 是在函数体中才加入的字典,所以在后面
- 然后你向该字典中增加了 first_name和 last_name。
五、将函数存储在模块中
让我们更进一步,将函数存储在称为模块的独立文件中,再将模块导入(import)主程序。通过将函数存储在独立的文件中,可隐藏程序代码的细节,将重点放在程序的高层逻辑上。这还能让你在众多不同的程序中复用函数。
1、导入整个模块
要让函数是可导入的,得先创建模块。模块是扩展名为 .py 的文件,包含要导入程序的代码。创建一个包含 make_dog() 函数的模块,文件名为:dog.py
def make_dog(size, *t):
print(f"\n做个{size}高的小狗")
for tt in t:
print(f"- {tt}")
在 dog.py 所在的目录中创建一个名为 making_dog.py 的文件。这个文件先导入刚创建的模块,再调用。
import dog
# 导入模块后,调用
dog.make_dog(20, 'aa', 'bb')
输出结果:
做个20高的小狗
- aa
- bb
只需编写一条 import 语句 并在其中指定模块名,就可在程序中使用该模块中的所有函数。
2、导入特定的函数
可以只导入模块中的特定函数,使用如下语句:
from module_name import function_name
# 或者 多个函数,逗号分隔函数名
from module_name import function_0, function_1, function_2
注意:使用这种语法,在调用函数时则无须使用句点。由于在 import 语句中显式地导入了 function_0 函数,因此在调用时只需指定其名称即可。
3、使用 as 给函数指定别名
要导入的函数的名称太长或者可能与程序中既有的名称冲突,可指定简短而独一无二的别名。
from dog import make_dog as doge
# 通用语句
from module_name import function_name as fn
4、使用 as 给模块指定别名
import module_name as mn
5、导入模块中的所有函数
from module_name import *
# 并不是推荐这种写法,了解即可
函数编写规范:
# 在给形参指定默认值时,等号两边不要有空格:
def function_name(parameter_0, parameter_1='default value')
# 函数调用中的关键字实参也应遵循这种约定
function_name(value_0, parameter_1='value')