参数的传递
函数通常都有参数,用于将外部的实际数据传入函数内部进行处理。但是,在处理不同数据类型的参数时,会有不同的情况发生。这一切都是因为以下两点。
Python的函数参数传递的是实际对象的内存地址。
Python的数据类型分可变数据类型和不可变数据类型。
看下面的例子:
a=1deffunc(a):print("在函数内部修改之前,变量a的内存地址为:%s"%id(a))a=2print("在函数内部修改之后,变量a的内存地址为:%s"%id(a))print("函数内部的a为:%s"%a)print("调用函数之前,变量a的内存地址为:%s"%id(a))func(a)print("函数外部的a为:%s"%a)
打印结果为:
调用函数之前,变量a的内存地址为:在函数内部修改之前,变量a的内存地址为:在函数内部修改之后,变量a的内存地址为:函数内部的a为:2函数外部的a为:1
为什么当a=2之后,函数内外的a的内存地址就不一样了呢?也就是说此后函数内外的a是两个不同的对象了。
这是因为,当作为参数,a被传入函数时,将数字对象1的地址传递给了函数内部的a。执行第一句内部代码时,此时内部的a和外面的a其实是一个东西,因此打印出了同样的内存地址。而当a=2被执行后,创建了一个新的内部变量a,并赋值2,将数字对象2的内存地址赋给变量a。我们知道,首先,赋值语句具有创建新变量的功能,其次,函数由于存在作用域的概念(后面会介绍),在其内部的变量不受外部变量的影响,可以独立使用变量,相当于新的命名空间。因此,此时的a和外面的a没有一毛钱关系了,是两个不同的变量。同时,由于数字1和2是不可变的数字类型对象,是两个独立的,不同内存地址的对象,因此再次打印内存地址,当然就不一样了。
上面的解释可能不太好理解。其实,很多时候,我们被这种类似的问题困惑是因为函数参数的命名不恰当造成的。如果我们把上面的参数名改为b,可能就好理解多了(注意其中文字的变化)。执行结果是一样的。
a=1deffunc(b):print("在函数内部修改之前,变量b的内存地址为:%s"%id(b))b=2print("在函数内部修改之后,变量b的内存地址为:%s"%id(b))print("函数内部的b为:%s"%b)print("调用函数之前,变量a的内存地址为:%s"%id(a))func(a)print("函数外部的a为:%s"%a)
刚才说的是不可变类型参数,如果是可变类型的,比如列表呢?
a=[1,2,3]deffunc(b):print("在函数内部修改之前,变量b的内存地址为:%s"%id(b))b.append(4)print("在函数内部修改之后,变量b的内存地址为:%s"%id(b))print("函数内部的b为:%s"%b)print("调用函数之前,变量a的内存地址为:%s"%id(a))func(a)print("函数外部的a为:%s"%a)
执行结果是:
调用函数之前,变量a的内存地址为:在函数内部修改之前,变量b的内存地址为:在函数内部修改之后,变量b的内存地址为:函数内部的b为:[1,2,3,4]函数外部的a为:[1,2,3,4]
调用函数时将列表对象a的地址传递给了函数内部的变量b。b.append(4)的时候,根据传进来的内存地址,找到[1,2,3]这个列表对象,在它的后面添加了4。
可以看出,此时的a和b实际指向了同一个对象。为什么会这样?因为最关键的b.append(4)这句代码,它不同于“=”赋值语句,不会创建新的变量,而列表作为可变类型,具有append方法,这个方法只是对列表的一种调用而已。因此,a和b实际还是同一个对象。
那么,如果用数字类型调用append方法,会是什么结果呢?很明显,这是不行的,因为数字类型没有append方法,不是Python官方不给它设计,而是因为数字类型是不可变类型,永远不能有append方法。
以上就是Python函数基础的详解,私信回复,免费领取Python编程全套学习资料,包含全套视频教程、项目源码、学习路线图等,赶快私信吧。