函数
函数是带名字的代码块,用于 完成具体的工作。要执行函数定义的特定任务,可 调用 该函数。需要在程序中 多次执行同一项任务时,无须反复编写完成该任务的代码,只需要调用执行该 任务的函数,让Python运行其中的代码即可。
任务:
- 学习编写 函数
- 学习向函数传递信息的方式
- 学习如何编写主要任务是显示信息的函 数
- 处理数据并返回一个或一组值的函数
- 如何将函数存 储在称为 模块 的独立文件中,让主程序文件的组织更为有序。
函数的定义与调用
def 函数名(): #可在圆括号内指出函数为完成任务需要什么样的信息
#函数体:规定了该函数的操作以及功能
"""打印hello"""
#文档字符串是一种注释,描述了该函数是做什么的。
print("Hello!") #函数的操作语句
#函数调用
greet_user() #函数名()进行调用
函数传参
可在函数定义的括号内添加参数,可让函数接受你指定的 任何值。
def sayHello(username):
"""打印hello"""
print(f'{username.title()},hello!')
sayHello("yulin")
- 注意区分形参和实参。
传递实参
函数定义中可能包含多个形参,因此函数调用中也可能包含多个实参。向函数传递 实参的方式很多:可使用 位置实参 ,这要求实参的顺序与形参的顺序相同;也可使 用 关键字实参 ,其中每个实参都由变量名和值组成;还可使用列表和字典。
位置实参
调用函数时,Python必须将函数调用中的每个实参都关联到函数定义中的一个形 参。为此,最简单的关联方式是基于实参的顺序。这种关联方式称为 位置实参 。
def describe_pet(animal_type, pet_name):
"""显示宠物的信息。"""
print(f"\n我有一条 {animal_type}.")
print(f"我家{animal_type}的名字叫做{pet_name.title()}.")
describe_pet('泰迪', '雪莉')
#我有一条 泰迪.
#我家泰迪的名字叫做雪莉.
- 调用describe_pet()需要按顺序提供一种动物类型和一个名字
在函数中,可根据需要使用任意数量的位置实参,Python将按顺序将函数调用 中的实参关联到函数定义中相应的形参。
需要保证函数调用中实参的顺序与函数定义中形参的顺序一致。
关键字实参
直接在实参中将名称和值关联起来,避免混淆(关键字实参让你无须考虑函数调用中的实参顺序,还清楚地指出了函数调用中各个值的 用途
函数定义不变,在调用传递参数时,使用“形参=实参”的形式,此时关键字实参的顺序无关紧要,因为Python知道各个值该赋给哪个形参。
describe_pet(animal_type = '泰迪',pet_name='雪莉')
describe_pet(pet_name='雪莉', animal_type = '泰迪')
#上下两条语句等价。
指定默认值
编写函数时,可给每个形参指定默认值 。在调用函数中给形参提供了实参时, Python将使用指定的实参值;否则,将使用形参的默认值。
def describe_pet(animal_type='泰迪',pet_name):
"""显示宠物的信息。"""
print(f"\n我有一条 {animal_type}.")
print(f"我家{animal_type}的名字叫做{pet_name.title()}.")
describe_pet('雪莉')
上面再函数定义时给了动物类型默认值泰迪,pet_name 没有默认值(python中对于没有默认值的形参需要提前),因此需要修改了形参的排列顺序,不然上述代码会报错
报错原因:
- Python依然将这个实参视为位置实参,因此如果函数调用 中只包含宠物的名字,这个实参将关联到函数定义中的第一个形参。这就是需要将 pet_name 放在形参列表开头的原因,正确写法如下:
def describe_pet(pet_name,animal_type='泰迪'):
"""显示宠物的信息。"""
print(f"\n我有一条 {animal_type}.")
print(f"我家{animal_type}的名字叫做{pet_name.title()}.")
describe_pet('雪莉')
#由于没有给animal_type 提供实参,Python将使用默认值'泰迪' 。
describe_pet('雪莉','小狗')
#给animal_type 提供了实参,Python将使用值'小狗' 。
没有指定默认值时,在任何情况下都必须给该形参提供实参。
指定该实参时可采用 位置方式,也可采用关键字方式,可灵活选择。不使用给定的默认值,指定该实参时可以采用位置方式,也可采用关键字方式
返回值-return
函数并非总是直接显示输出,它还可以处理一些数据,并返回一个或一组值。函数 返回的值称为 返回值 。
- 在函数中,可使用return 语句将值返回到调用函数的代码行。
def max(a,b):
if a>b:
return a
else:
return b
print(max(11,2))
print(max(11,max(29,10)))
返回列表和字典
函数可返回任何类型的值,包括列表和字典等较复杂的数据结构。
def sord(a,b):
if a>b:
return [a,b]
else:
return [b,a]
print(sord(1,2))
print(sord(2,1))
#[1,2]
#[2,1]
def build_person(first_name, last_name, age=None):
"""返回一个字典,其中包含有关一个人的信息。"""
person = {'first': first_name, 'last': last_name}
if age:
person['age'] = age
return person
musician = build_person('yu', 'lin', age=27)
print(musician)
#{'first': 'yu', 'last': 'lin', 'age': 27}
#在函数定义中,新增了一个可选形参age ,并将其默认值设置为特殊值None (表示变量没有值)。可将None 视为占位值。在条件测试中,None 相当于False 。如果函数调用中包含形参age 的值,这个值将被存储到字典中。在任何情况下,这个函数都会存储人的姓名,但可进行修改,使其同时存储有关人的其他信息。
传递的参数为列表
将列表传递给函数后,函数就能直接访问其内容。使用函数来提高处理列表的效率。
def max(lists):
max = lists[0]
for list in lists:
if list>max:
max = list
return max
nums = [3,5,4,3,9,7,1,2]
print(max(nums))
#9
- 传递的列表为其地址,函数中修改也会导致原列表改变!
- 在函数中对这个列表所做的任何修 改都是永久性的
def to_0(lists):
for i in range(len(lists)):
lists[i] = 0
return lists
nums = [3,5,4,3,9,7,1,2]
print(to_0(nums))
#[0, 0, 0, 0, 0, 0, 0, 0]
有时候想向函数中传递的列表不做修改。此时需要使用以下方法:
为解决这个问题,可向函数传递列表的副本而非原件。这 样,函数所做的任何修改都只影响副本,而原件丝毫不受影响
#方法一:切片,生成一个列表的副本
function_name(list_name_[:])
传递任意数量的实参–*形参
在Python中 允许函数从调用语句中 收集任意数量的实参。
编写一个函数,将所有的给定的实参相加
def add_all(*nums):
"""所有数相加。"""
print(type(nums))
sum= 0
for num in nums:
sum+=num
return sum
print(add_all(1,2,1,3,2,5,6,7))
print(add_all(1,2,3,4,5))
#<class 'tuple'>
#27
#<class 'tuple'>
#15
#可见*nums创建的一个名为nums的空元组,并将收到的所有值都封装到这个元组中因此不管是一个参数还是多个参数,都可以使用循环来便利
- 你经常会看到通用形参名*args ,它也收集任意数量的位置实参。
结合使用位置实参和任意数量实参
如果要让函数接受不同类型的实参,必须在函数定义中将接纳任意数量实参的形参 放在最后。Python先匹配位置实参和关键字实参,再将余下的实参都收集到最后一 个形参中。
使用任意数量的关键字实参–**形参
函数user_profile() 接受姓名和性别参数,还可以接受任其他未给定的任意数量的关键字实参
def user_profile(name, sex, **user_info):
user_info['name'] = name
user_info['sex'] = sex
return user_info
user = user_profile("yulin",
'男',
location='princeton',
field='physics'
)
print(f'{type(user)}:{user}')
#<class 'dict'>:{'location': 'princeton', 'field': 'physics', 'name': 'yulin', 'sex': '男'}
- 形参 **user_info 中的两个星号让Python创建一个名为user_info 的空字典,并将收到的所有名称值对都放到这个字典中。在这个函数中,可以像访 问其他字典那样访问user_info 中的名称值对
``注意 你经常会看到形参名**kwargs ,它用于收集任意数量的关键字实参。
导入外部函数
使用函数的优点之一是可将代码块与主程序分离。通过给函数指定描述性名称,可 让主程序容易理解得多。你还可以更进一步,将函数存储在称为 模块 的独立文件 中,再将模块 导入 到主程序中。import 语句允许在当前运行的程序文件中使用模 块中的代码。
max.py
def max_list(lists):
max = lists[0]
for list in lists:
if list>max:
max = list
return max
active.py
#导入模块中的特定函数
from max import max_list
#从max.py中导入max_list方法
nums = [3,5,4,3,9,7,1,2]
print(max_list(nums))
#通过用逗号分隔函数名,可根据需要从模块中导入任意数量的函数:
#from module_name import function_0, function_1, function_2,后面直接使用该方法即可function_0()
import max
#导入整个max.py文件
nums = [3,5,4,3,9,7,1,2]
print(max.max_list(nums))
#使用max.py下的方法。将
#其中的所有函数都复制到这个程序中
#如果使用这种import 语句导入了名为module_name.py的整个模块,就可使用下面的语法来使用其中任何一个函数:
#module_name.function_name()
- 通过将函数存储在独立的文件中,可隐藏程序代码的细节,将重点放在程序的高层 逻辑上。这还能让你在众多不同的程序中重用函数。将函数存储在独立文件中后, 可与其他程序员共享这些文件而不是整个程序。知道如何导入函数还能让你使用其 他程序员编写的函数库
使用 as 给函数指定别名
导入函数的名称可能与程序中现有的名称冲突,或者函数的名称太长,可指 定简短而独一无二的 别名
from pizza import make_pizza as mp
#从pizza.py中导入make_pizza方法,并使用mp作为别名,避免冲突,简化代码
#此时方法名make_pizza将失效,只能mp()方法使用它
格式
from module_name import function_name as fn
导入模块中的所有函数
使用星号(* )运算符可让Python导入模块中的所有函数:
from pizza import *
- import 语句中的星号让Python将模块pizza 中的每个函数都复制到这个程序文件 中。由于导入了每个函数,可直接通过名称来调用每个函数,而无须使用句点表示法。
最佳的做法是,要么只导入需要使用的函数,要么导入整个模块并使用句点表示 法。这让代码更清晰,更容易阅读和理解。
所有import 语句都应放在文件开头。唯一例外的情形是,在文件开头使用了注释 来描述整个程序。