函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。函数能提高应用的模块性,和代码的重复利用率。Python提供了许多内建函数,比如print()。但也可以自己创建函数,这被叫做用户自定义函数。
def student_name(name):
"打印学生的名字"
print('姓名:', name)
return {
'姓名':name}
rst = student_name('Alice')
rst
函数运行结果如下:
姓名: Alice
{
'姓名': 'Alice'}
# 返回多个值
def student_name_and_age():
"记录学生的名字和年龄"
name = input('请输入姓名\n')
age = int(input('请输入年龄\n'))
print(f'姓名:{name};年龄:{age}')
return name,age
rst = student_name_and_age()
输入姓名和年龄后,函数运行结果如下:
请输入姓名
请输入年龄
姓名:Molly;年龄:19
注:不同于C++语言,Python可以返回多个值
下面来查看一下,rst 的类型,是元组类型
print(rst) #('Molly', 19)
type(rst) #结果为tuple类型
也可以分别返回多个值,如下所示
name, age = student_name_and_age()
print(name,age) #Molly 19
在实际应用中,经常使用函数的嵌套调用。
## 函数的嵌套调用
def worker(s):
rst = 10 / float(s)
return rst
def group_leader(s):
rst = worker(s) * 2
return rst
def CTO(s):
return group_leader(s)
CTO('4') #运行结果为5.0
函数的参数包括以下几种参数,下面分别进行介绍。
位置参数是最简单的一种函数调用的方式。位置参数须以正确的顺序传入函数、数量必须和声明时的一样。
def student_name_and_age(name, age):
print('姓名:%s 年龄 %s' %(name, age))
student_name_and_age('张三', 18)
函数调用结果如下:
姓名:张三 年龄 18
调用函数时,缺省参数的值如果没有传入,则被认为是默认值。
def student_name_and_age(name, age='不愿透露'):
"设置默认参数"
print('姓名:%s 年龄 %s' %(name, age))
student_name_and_age('张三')
运行结果如下:
姓名:张三 年龄 不愿透露
也可以为默认参数赋值
student_name_and_age('张三', 18)
运行结果如下:
姓名:张三 年龄 18
顾名思义,可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个,这些可变参数在函数调用时自动组装为一个tuple。
def all_student_names(*names):
for name in names:
print('姓名:', name)
all_student_names('张三','李四','王五')
运行结果如下:
姓名: 张三
姓名: 李四
姓名: 王五
也可以用位置参数调用的方法,实现上述函数的功能
def all_student_names(names):
for name in names:
print('姓名:', name)
names = ('张三','李四','王五')
all_student_names(names)
运行结果如下:
姓名: 张三
姓名: 李四
姓名: 王五
关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。
def student_info(name, age, **kw):
print(f'我的名字叫:{name},年龄:{age},其它信息:{kw}')
student_info('张三', 18, height=180)
运行结果如下:
我的名字叫:张三,年龄:18,其它信息:{
'height': 180}
还可以通过字典的key值对输出值进行限制
def student_info(name, age, **kw):
print(f'我的名字叫:{name},年龄:{age},其它信息:{kw}')
if 'city' in kw:
print('来自:', kw['city'])
student_info('张三', 18, height=180, city='北京')
运行结果如下:
我的名字叫:张三,年龄:18,其它信息:{
'height': 180, 'city': '北京'}
来自: 北京
下面来介绍一个关键字参数应用的场景。原始需求:要求编写代码输出某人的姓名、年龄、语文成绩和数学成绩。实现代码如下:
def score_info(name, yuwen, shuxue):
print(name, '的语文成绩', yuwen)
print(name, '的数学成绩', shuxue)
def person_info(name, age, yuwen, shuxue):
print('姓名:', name, '年龄',age)
score_info(name, yuwen, shuxue)
person_info('张三', 18, 65, 60)
运行结果如下:
姓名: 张三 年龄 18
张三 的语文成绩 65
张三 的数学成绩 60
此时提出新的需求:在原有输出基础上,再输出英语成绩。最简单的方法就是:在person_info函数中传入英语成绩,在person_info函数中传入参数,在score_info函数中传入参数并增加英语成绩输出语句。需要改动的地方很多,如果需要增加新的需求工作量很大。
如果采用关键字参数,可以用如下代码实现:
def score_info(name, **kw):
if '语文成绩' in kw:
print(name, '的语文成绩', kw['语文成绩'])
if '数学成绩' in kw:
print(name, '的数学成绩', kw['数学成绩'])
def person_info(name, age, **kw):
print('姓名:', name, '年龄',age)
score_info(name, **kw)
score_cfg = {
'语文成绩':65, '数学成绩':60}
person_info('张三', 18, **score_cfg)
用关键字参数 kw 代替位置参数,这样因为需求改动代码,工作量会小很大。如果想要加入打印英语成绩的功能,则只需要改变关键字参数score_cfg的内容,并在函数score_info中增加打印英语成绩的语句。person_info函数完全无需改变,因为**kw不关心传入内容是什么。第三方库涉及到层层调用和传参,它背后的实现原理与此类似。
如果要限制关键字参数的名字,就可以用命名关键字参数。* 后面的参数不仅需要提供值还需要提供参数名。这样可以避免代码版本迭代后,忘记位置参数对应的含义,导致输出错误的情况发生。
def print_person_info(name, age, *, height, weight):
print('我的名字叫:', name, '年龄:', age,'身高', height, '体重', weight)
print_person_info('张三', 18, height=180, weight=75)
运行结果如下:
我的名字叫: 张三 年龄: 18 身高 180 体重 75
在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。
下面给出几个实例:
def student_info(name, age=18, *books, **kw):
print('我的名字叫:', name, '年龄:', age,'其它信息:',kw)
if 'city' in kw:
print('来自:', kw['city'])
for book in books:
print('我有',book,'书')
student_info('张三', 18, '语文','数学','计算机', city='北京', height=180, weight=75)
运行结果如下:
我的名字叫: 张三 年龄: 18 其它信息: {
'city': '北京', 'height': 180, 'weight': 75}
来自: 北京
我有 语文 书
我有 数学 书
我有 计算机 书
如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了:
def student_info(name, age=18, *books, city, **kw):
print('我的名字叫:', name, '年龄:', age,'其它信息:',kw)
print('来自:', city)
for book in books:
print('我有',book,'书')
student_info('张三', 18, '语文','数学','计算机', city='北京', height=180, weight=75)
运行结果如下:
我的名字叫: 张三 年龄: 18 其它信息: {
'height': 180, 'weight': 75}
来自: 北京
我有 语文 书
我有 数学 书
我有 计算机 书
注:为了避免奇怪的错误发生,建议尽量减少使用参数组合。
下面介绍变量的作用域和global变量。变量分为以下两种:
下面给出几2个变量使用的例子:
#例1
name = '张三'
def print_my_name():
name='李四'
print(name)
print_my_name() #运行结果:李四
函数优先使用局部变量,在没有局部变量的情况下,使用全局变量。因此例1运行结果为李四,例2运行结果为张三。
#例2
name = '张三'
def print_my_name():
print(name)
print_my_name() #运行结果:张三
注意:定义在函数内部的变量,函数结束之后自动消亡。如果再次使用函数内部的变量将会报错。
def get_my_name():
new_name = '赵四'
get_my_name()
new_name
报错信息如下:
---------------------------------------------------------------------------NameError Traceback (most recent call last)<ipython-input-47-50225d753478> in <module>
3 new_name = '赵四'
4 get_my_name()
----> 5 new_name
NameError: name 'new_name' is not defined
下面这个例子可以进一步加深我们对局部变量和全局变量的理解。我们希望下面的代码可以先输出“我的名字曾经是张三”,然后再输出“我的名字现在是李四”。
def change_my_name():
print('我的名字曾经是', name)
name = '李四'
print('我的名字现在是', name)
name = '张三'
change_my_name()
name
结果运行之后报错,报错信息如下:
---------------------------------------------------------------------------UnboundLocalError Traceback (most recent call last)<ipython-input-49-9452ee1a9be8> in <module>
1 name = '张三'
----> 2 change_my_name()
3 name
<ipython-input-48-a750cf076394> in change_my_name()
1 def change_my_name():
----> 2 print('我的名字曾经是', name)
3 name = '李四'
4 print('我的名字现在是', name)
UnboundLocalError: local variable 'name' referenced before assignment
报错信息显示局部变量’name’在赋值之前被引用。但根据“函数优先使用局部变量,在没有局部变量的情况下,使用全局变量。”的原则,全局变量name已经被赋值为张三了,应该不会报错呀。
这和Python的机制有关,一旦在函数体内部对同名的全局变量赋值,则同名的全局变量就变为局部变量,且未被赋值。因此会报错。如果使用global变量就可以解决这个问题。
def change_my_name():
global name
print('我的名字曾经是', name)
name = '李四'
print('我的名字现在是', name)
name = '张三'
change_my_name()
name
运行结果如下,没有报错。
我的名字曾经是 张三
我的名字现在是 李四
'李四'
本文主要介绍了函数的定义、函数参数的传递,以及变量的作用域。函数的定义中具体介绍了如何定义一个函数,函数的调用以及函数的返回值。函数参数的传递中详细介绍了几种参数的调用,变量部分介绍了局部变量、全局变量和global变量。下一篇文章将介绍高阶Python函数。