函数的定义
Python中的函数是一段组织好的、可重复使用的、用来实现单一或相关联功能的代码块。函数能提高应用的模块性,和代码的重复可用性。你已经知道Python提供了许多内建函数,比如print()。但你也可以自己创建函数,这被称为用户自定义函数。
自定义函数
假设,我们现在求一个半径为6.5的圆的面积,怎么求?
正常编写是不是先给一个整数型半径,然后求半径与PI的乘积:
PI = 3.14
#求⚪的面积
r = 5.6
s = PI * r * r
print(s)
这样,我们就求得了圆的面积。好的,那现在半径变了,求一个半径为8、为10、为20的圆的面积,我们反复的将半径给替换掉是不是很麻烦呢?可不可以有一个函数能够让我输入半径就能直接得到圆的面积呢?那我们自己来定义一个求圆面积的的函数看看:
我们该怎么定义一个函数呢?
函数定义的规则:
- 函数代码块以 def 关键词开头,后接函数名称和圆括号 ()
- 如果需要传入参数(变量),可在圆括号内定义
- 函数的第一行语句可以选择性地使用文档字符串——用于存放函数说明
- 函数内容以冒号 : 起始,并且缩进
- 可选择性地使用return返回一个值给调用方,不 return 相当于返回 None
- 注意:在Python中不需要定义返回值类型,可自动推断
格式
def circle_area(r):
''' #'''内的内容用于提示输入和输出是什么,可以省略
:param r: 输入半径
:return: 返回圆的面积
'''
s = PI * r * r
print(s)
-------------
circle_area(r) #调用函数
我们来试试调用函数:
import json
if __name__ == '__main__': #学到这,我们得习惯模拟main函数的概念,在main中输入
circle_area(5.7)
circle_area(10)
------------------------
输出结果:
102.0186
314.0
这样一个函数就被我们定义完成了。
参数
在调用函数时,函数可以通过参数来接收信息。
定义函数时的参数有:必选参数、默认参数、可变参数、关键字参数等。下面让我们来介绍一下:
必选参数
又名位置参数,必须在调用函数的时候给定值,调用函数时必须按顺序提供,不多不少。比如计算x的n次方:
def power(x,n):
p = 1
while n > 0 :
n = n - 1
p = p * x
return p
其中,x,n就是必须要输入的参数。定义函数可以输入多个必选参数。
默认参数
同样以计算x的n次方为例,假设我们只想计算不同x的二次方,按上述的方法需要重复输入n = 2、,太过复杂,不妨直接将n定死,即将它设置为默认参数:
def power(x,n = 2):
p = 1
while n > 0 :
n = n - 1
p = p * x
return p
如此,我们只需要更改x的值,就可得到它的二次方值:
print(power(6))
------------------
输出结果:
36
注意:
- 必选参数在前,默认参数在后,否则Python的解释器会报错
- 函数有多个参数时,把变化大的参数放前面,变化小的参数放后面,变化小的参数就可以作为默认参数
可变参数
对于一些问题,我并不明确一开始要输入多少个参数,比如计算一组数据的和,我不确定要输入几个参数时,可以使用可变参数。
可变参数允许传入0个或任意个参数,可变参数在函数调用时自动组装为一个tuple。
表示形式:
*+名字,一般都是 *args(不强制),就是一个可变参数,数据存放在了元组里。
比如:计算一组数据的平方和:
def calc(*num_list): #这样我们就可以输入多个数据
print(num_list)
summ = 0
for i in num_list:
summ += i ** 2
print(summ)
调用:
calc(1,2,3,4,5,6,7,8,9)
------------
输出结果:
285
注意:
- 可变参数在函数内部作为元组处理。
- 可变参数必须位于所有位置参数之后。
关键字参数
可变参数允许传入0个或任意个参数,可变参数在函数调用时自动组装为一个tuple,而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。
表示形式:
**kwargs 关键字参数 一般传入时需要带入参数名称 以字典的形式接收
比如:将城市、工作、身高、体重和住址通过字典形式输出:
def personal_info(**kwargs):
print(kwargs)
调用:
personal_info(city='hf', job='AI engineer', weigth=180, height=170, address="汤臣一品")
------------------------
输出结果:
{'city': 'hf', 'job': 'AI engineer', 'weigth': 180, 'height': 170, 'address': '汤臣一品'}
组合使用
函数参数的组合使用:必选参数、默认参数、可变参数、关键字参数
def params_all(a, b, c=0, *args,**kwargs):
print(a, b, c, args, d, e, kwargs)
pass #占位符,还没想好函数如何定义时占位不报错
调用:
params_all(1, 2, 3, 4, 5, 6, f=9, h=10)
-------------------------
输出结果:
1 2 3 (4, 5, 6) {'f': 9, 'h': 10}
命名空间namespace
![
- 局部 函数内部找变量
- 全局 在整个代码之前去寻找
- 内置 python内置的模块去寻找
- 可以向上寻找,但不可以向下下沉寻找:即局部可以去全局、内建找,但是它们不能去局部找。
我们来看一个内置函数sum():
print(sum([1, 2, 3, 4, 5]))
----------------
输出结果:
15
对于上述sum()在寻找作用域时的过程:先在局部找(没有)-- 再去全局找(也没有)-- 最后在内置中找到了内置函数sum(),然后进行对应操作。那现在我们先定义一个sum变量:
sum = 10 #不是关键字,可以设置变量,但是最好避免这样命名,此处为示范
print(sum([1, 3, 4, 5]))
那么此时,sum还可以正常求和嘛?看看输出结果:
print(sum([1, 3, 4, 5]))
TypeError: 'int' object is not callable
结果报错,是因为sum先在局部中寻找,找到了sum = 10表示整数型,找到了就用,但是此时的sum并没有求和功能。覆盖了内置模块中的sum函数,变成一个常量,没有具体的意义。
故而报错。
局部作用域
局部找到数据就使用局部作用域内的数据,比如:
#局部
def aaa():
m = 10
n = 20
print(n, x, m)
调用:
n = 9
x = 11
aaa()
--------------
输出结果:
20 11 10 #可以向上找寻变量,先找到谁就先用谁
全局作用域
#局部
def aaa():
m = 10
n = 20
print(n, x, m)
#输出一个m
print(m) #没有m值输出,因为这在全局作用域,不能下沉到局部寻找
闭包函数
闭包(Closure)是函数式编程中的一个重要概念,它出现在支持嵌套函数的编程语言中,如Python、JavaScript等。闭包允许一个函数访问并操作函数外部的变量,即使该函数在其外部函数的作用域之外执行。
让我们看看一个闭包函数:
# 闭包函数
# outer 数据enclosing 闭包函数外的函数
def outer():
o_count = 1
print(o_count)
# inner 属于局部作用域
def inner():
i_count = 2
print(i_count,o_count)
return inner
上述代码中,
def outer():
o_count = 1
print(o_count)
#我可以将print输出写成:print(o_count,i_count)吗?
很显然是不可以的,因为inner 属于局部作用域,outer无法下沉寻找。
总结
本篇介绍了:
- 如何自定义函数
- 自定义函数需要用到的参数:必选参数(调用时必须给值)、默认参数、可变参数、关键字参数
- 命名空间namespace:局部、全局、内置作用域以及闭包函数。作用域的寻找只能从低到高,不能向下下沉寻找。