pyhton基础【16】函数进阶二
目录
四.星号拆包
普通方式拆包
使用*拆包
使用**拆包
难点
五.变量引用
引用概念
赋值运算符
引用当做实参
六.函数引用
四.星号拆包
普通方式拆包
假如有以下函数:
def test(a, b, c):print(a + b + c)
现在自己拥有的数据:
nums = [11, 22, 33]
怎样才能在调用test函数的时候,将nums给传递过去呢?
def test(a, b, c):print(a + b + c)nums = [11, 22, 33]
test(nums[0], nums[1], nums[2])
上述代码用的方式虽然能行,但不是很简洁
为了能够用更加简洁的方式实现上述场景需求,Python可以通过*、**将数据拆包后传递
使用*拆包
有时在调用函数时,这个函数需要的是多个参数,而自己拥有的是一个列表或者集合这样的数据,此时就用可以用*拆包
使用方式:
*列表
*元组
*集合
用*拆包的方式实现上述功能:
def test(a, b, c):print(a + b + c)nums = [11, 22, 33]
test(*nums) # 此时的*的作用就是拆包,此时*nums相当于11, 22, 33 即test(11, 22, 33)
如果为数据元组时使用方式与上述代码一致:
def test(a, b, c):print(a + b + c)nums = (11, 22, 33)
test(*nums)
集合类型同上:
def test(a, b, c):print(a + b + c)nums = {11, 22, 33}
test(*nums)
注意:*对列表、元组、集合可以拆包,但一般都是在调用函数时使用
使用**拆包
使用**可以对字典进行拆包,拆包的结果是命名参数
示例:
def test(name, age, address):print(name)print(age)print(address)info = {"name": "小明","age": 18,"address": "兰州"
}test(**info)'''
当前**info相当于以下代码:name='小明'age=18address='兰州'** 主要对字典进行拆包
'''
难点
学习不定长参数时,掌握了*args、**kwargs
现在学习拆包时,也用到了*、**
那它们之间有什么关系呢?
答:没有任何关系,只是长得像罢了
示例一:
def test1(*args, **kwargs):print("----在test1函数中----")print("args:", args)print("kwargs", kwargs)def test2(*args, **kwargs):print("----在test2函数中----")print("args:", args)print("kwargs", kwargs)test1(args, kwargs) # 在函数test1传递参数时没有进行拆包test2(11, 22, 33, name="小明", age=18)运行结果:----在test2函数中----
args: (11, 22, 33)
kwargs {'name': '小明', 'age': 18}
----在test1函数中----
args: ((11, 22, 33), {'name': '小明', 'age': 18})
kwargs {}
示例二:
def test1(*args, **kwargs):print("----在test1函数中----")print("args:", args)print("kwargs", kwargs)def test2(*args, **kwargs):print("----在test2函数中----")print("args:", args)print("kwargs", kwargs)test1(*args, **kwargs) # 对参数进行了拆包test2(11, 22, 33, name="小明", age=18)运行结果:
----在test2函数中----
args: (11, 22, 33)
kwargs {'name': '小明', 'age': 18}
----在test1函数中----
args: (11, 22, 33)
kwargs {'name': '小明', 'age': 18}
五.变量引用
引入
如下代码中,最后b的值为多少?
>>> a = 1
>>> b = a
>>> b
1
>>> a = 2
>>> a
2
>>> b
1
如下代码中,最后b的值为多少?
>>> a = [1, 2]
>>> b = a
>>> b
[1, 2]
>>> a.append(3)
>>> b
[1, 2, 3]
引用概念
引用:就是内存地址
那地址是什么呢?可以理解为存放数据的空间在内存中的编号
例如:
a = 100怎样知道它的地址呢?id(a)可以直接将上述的结果打印:print(id(a))运行结果(在不同机器上输出的地址可能不相同):4347271232
当我们知道了原来引用就是地址之后,再来看如下代码:
a = [1, 2]我们可以用id(a)取它的地址:print(id(a)) # 获取变量存储的引用(地址)是多少接下来定义变量b并且赋值:b = a此时输出变量b的引用:print(id(b))运行结果(不同机器上的内存地址可能不相同):4558971360
4558971360
这说明,此时变量a、b存储的引用都是相同的
由此我们可以得出一个结论:Python中的变量并不是真正存储数据,而是存储的数据所在内存中的地址,我们一般称之为引用
既然变量a、b都指向同一个列表,那么接下来:
a.append(3)
此时变量a、b指向的同一个列表中多了一个数据,即此时列表为[1, 2, 3]
所以a、b此时用print输出相同的结果。
补充内容:
大家自己试试看a=257, b=257时它们的id还是否会相等。事实上Python为了优化速度,使用了小整数对象池,避免为整数频繁申请和销毁内存空间。而Python对小整数的定义是[-5, 257),只有数字在-5到256之间它们的id才会相等,超过了这个范围就不行了,同样的道理,字符串对象也有一个类似的缓冲池,超过区间范围内自然不会相等了。
赋值运算符
赋值运算符=,之前为了更好的理解变量,把a=100理解为变量a中存放了100,事实上变量a存储是100的引用
也就是说:在Python中只要用=那么就表示=左边的变量存储了一个新的引用
大白话讲:就是=左边的变量指向了右边的数据。
想想下面的代码运行的结果是什么?
a = [1, 2]
b = a
b.append(3)
b = [100, 200, 300]print(b)运行结果:
[100, 200, 300]而不是:
[1, 2, 3]
引用当做实参
Python中调用函数时,传递实参实际上都是是引用,即传递的都是地址
只要是传递的引用,那么也就是说在函数中是可以直接对指向的数据进行修改
def test(p):# 此时变量p也指向nums指向的列表p.append(44)print("在函数test中,p=", p)nums = [11, 22, 33]
print("调用test函数之前,nums=", nums)
test(nums) # 此时将列表的引用当做了实参进行传递
print("调用test函数之后,nums=", nums)运行结果:
调用test函数之前,nums = [11, 22, 33]
在函数test中,p = [11, 22, 33, 44]
调用test函数之后,nums = [11, 22, 33, 44]
六.函数引用
阅读如下代码,思考会输出什么结果
def test1():print("我是test1函数...")def test2():print("我是test2函数...")test1()test1 = test2
test1()运行结果如下:
我是test1函数...
我是test2函数...
你可能会惊讶,为什么第九行调用test1函数输出的是我是test1函数...,反而到了第十二行再次调用test1函数时变成了我是test2函数...
上述问题的原因核心点是:在Python中即使是函数名也是一个变量名,只不过这个变量没有指向普通的数据,而是指向了一段代码;也就是说如果定义了一个函数名字叫做test1就好比是一个变量名test1指向了那个代码块而已,所以当上述代码第十一行test1 = test2时,就相当于让test1变量不在指向原本的代码块,而是指向新的代码块即test2指向的代码块,所以当第十二行执行test1函数时,会输出我是test2函数...
引用的作用
看完上述的引入知识后,相信你会对什么是函数的引入有一个大体的认知了
在此简单总结:所谓函数名当做引用,其实是指在Python中所有的函数名实际上是一个变量名,只不过这个变量名指向的不是常见的数据,而是一段代码,当我们用函数名()是实际上就是让指向的这块代码开始执行,当我们只用函数名时其实就是这个函数的引用
记住:既然函数名也是变量名,那么就可以给它赋值获取它的引用给别的变量
总结:
1. 使用def定义的函数名,实际就是个变量名它存储了函数的引用
2. 如果将另外一个变量,例如b保存了函数的引用,即也指向了同一个函数,那么b()就是调用函数