函数的参数传递
位置的参数传递
就是我们通常使用的方式,一对一对应
例子
def fun_01(x, y, z):
return x, y, z
print(fun_01(1,2,3))
输出:
(1, 2, 3)
不多讲
关键字参数传递
把参数的名称与值绑定在一起
实例
def connect(num1,num2):
return num1/num2
print(connect(num1 = 1,num2 = 2))
print(connect(num2 = 1,num1 = 2))
输出
0.5
2.0
参数默认值
也是很好理解,就是参数设置一个默认值,这跟我们定义变量没赋值时,默认为0(int类型)是类似的。
def sum(a,b,c=20):
return a + b + c
print(sum(10,10))
print(sum(10,10,10))
输出
40
30
可变参数(难点、重点)
可变参数就是传入函数的参数是可变的,
语法格式如下:
def functionname([formal_args,] *args, **kwargs):
"函数_文档字符串"
function_suite
return [expression]
- 以星号(*)开始的变量args会存放所有未命名的变量参数,args为元祖
- 以**开始的变量kwargs会存放命名参数,即形如key=value的参数,kwargs为字典
例子
# *args的使用
def test1(*args):
print(args)
# **kwargs的使用
def test2(**kwargs):
print(kwargs)
# 两者的混用
def test3(*args,**kwargs):
print(args)
print(kwargs)
print("*args的使用")
test1(1,2,3,'a','b','c')
print("**kwargs的使用")
test2(a = 1, b = 2,c = 3, d = 4)
print("两者的混用")
test3(1,2,3,a = 4,b = 5)
输出
*args的使用
(1, 2, 3, 'a', 'b', 'c')
**kwargs的使用
{'a': 1, 'b': 2, 'c': 3, 'd': 4}
两者的混用
(1, 2, 3)
{'a': 4, 'b': 5}
从以上我们可以看出
- 使用*可以将未命名的参数打包成元组类型
- 使用**可以将命名的参数打包成字典类型
闭包
函数的引用
先来看一段代码
def fun():
print("hello world")
fun()
fun
输出
hello world
<function __main__.fun()>
从这里我们可以看出,使用fun()和fun的结果完全不一样,原因是fun()表示调用fun()这个函数,会执行其中的代码,而fun表示一个变量,它引用的是一个函数块,引用一个函数(我认为就是一种指向),当然也可以多个函数指向同一个函数块
如:
def fun():
print("hello world")
fun()
fun_new = fun
fun_new()
输出
hello world
hello world
我们可以看出输出结果是一样的。
什么是闭包
先举个例子
def test(one):
def test_in(two):
print(one + two)
return test_in
test(100)
满足闭包的三个条件
- 嵌套在函数里面
- test_in中的变量是外部函数test的参数one
- 外部函数test返回值是内部函数test_in的引用
我们输出下结果
<function __main__.test.<locals>.test_in(two)>
我们会发现它输出的是一个引用值,这是因为我们只调用了test()函数,但实际上并没有调用test_in函数,所以返回的就是一个引用值
def test(one):
def test_in(two):
print(one + two)
return test_in
test_new = test(100)
test_new(100)
当我们这样写的时候,就成功调用test_in函数
至于作用,我百度搜下也还不是很清楚,按我的想法就是可以重复使用
def test(one):
def test_in(two):
print(one + two)
return test_in
test_new = test(10)
#这样可以隐藏内部调用,调用者可以不关心内部如何调用的
test_new(100)
test_new(200)
装饰器
装饰器本质就是一个Python函数,它可以在不改动其他函数的前提下,对函数的功能进行扩充。通常情况下,装饰器用于以下场景:
- 引入日志
- 函数执行时间统计
- 执行函数前预备处理
- 执行函数后清理功能
- 权限校验
- 缓存
先举个简单的例子
def fun_one():
print("fun_one")
现在有这个一个需求就是在函数中输出一句话,表示函数正在执行,这时候可以这么实现
def fun_one():
print("fun_one")
print("fun_one is running")
如果只有一个函数需要表示正在执行的话,我们这样写无疑是简便的,但如果还有其他函数也要表示函数正在运行呢,如果有10000个函数,那岂不是要多出大量重复代码,这样是不合算的,所以为了减少代码重复,我们可以创建一个新的函数专门记录函数,如下:
def print_logo():
print("函数正在运行")
def fun_one():
print("fun_one")
print_logo()
上述代码虽然可以实现功能,但破坏了原有代码的逻辑结构。如果要求已经实现的函数,不能修改,只能扩展,即遵守“封闭开放”原则,那就不允许修改的,在源代码基础上进行扩展,能够更好的维护,如果对源代码直接进行更改的话,会导致后期越来越难以维护,最终有可能演变成“屎山”。
类似这样
截图来源于:http://www.javashuo.com/article/p-yuqcxibh-x.html
而装饰器可以满足上述要求,在Python中,装饰器的语法屎以@开头,下面屎简单的装饰器使用