Python 函数参数的传递方式

简介: Python 函数参数的传递方式

Python 中一切皆 对象,而对象又分为 可变类型不可变类型。当将不同类型的对象作为参数传入函数时,往往会产生不同的效果。究其原因,是由于不同类型的对象有着各自不同的特性所导致的。

如果你有其他编程语言的基础,比如 CC++JavaScript 等,那么你也许听说过两种常见的函数传参方式:值传递(pass by value)、引用传递(pass by reference)。

Python 中函数参数的传递方式与大多数编程语言并不相同,既不是 值传递,也不是 引用传递。至于到底使用何种方式进行参数传递,等你阅读完本文就会明白了。不过,在此之前,我们先通过 JavaScript 代码来展示下到底什么是 值传递,什么是 引用传递,这样有助于我们理解 Python 中函数参数的传递方式。

值传递

JavaScript 中,如果函数接收到的参数是原始值类型(数值、字符串、布尔值等),函数参数的传递方式即为 值传递值传递 所表现出来的结果就是:在函数体内部修改传递进来的参数的值,并不会影响函数体外部原对象的值。

var a = 1;
function foo(p) {
    p += 2;
}
foo(a);
console.log(a);  // 1

以上代码中,在函数体内部对变量 p 的值进行了修改,但是并没有影响函数外部原有变量 a 的值。由于是 值传递,所以 p 的值是对原有变量 a 的值的一份拷贝,修改 p 也就不会对 a 产生任何影响。

引用传递

如果函数接收到的参数是引用类型(数组、对象等),函数参数的传递方式即为 引用传递。而 引用传递 所表现出来的结果是:在函数体内部修改传递进来的参数的值,将会直接改变函数体外部原对象的值。

var arr = [1, 2, 3];
function bar(p) {
    p.push(4);
}
bar(arr);
console.log(arr);  // [1, 2, 3, 4]

在这段代码中,同样在函数体内部对变量 p 的值进行了修改,函数外部原有变量 arr 的值跟着一起被改变了。这是因为 p 的值是对原有变量 arr 的值的引用,它们俩实际上指向同一个对象 [1, 2, 3]。只要修改一个变量的值,另一个变量的值就会跟着改变。

值得注意的是,如果将上面的代码稍作修改,改为如下的代码。其结果表现出来的又像是 值传递 的特性。

var arr = [1, 2, 3];
function bar(p) {
    p = [1, 2, 3, 4];
    p.push(5);
}
bar(arr);
console.log(arr);  // [1, 2, 3]

实际上这个示例函数参数的传递方式依然是 引用传递。出现以上结果的原因是,在函数体内部,传递进来的 arr 的值实际上被整体替换成了另一个数组 [1, 2, 3, 4],现在 p 所指向的对象是新的数组 [1, 2, 3, 4],而不是函数体外部 arr 所指向的数组 [1, 2, 3] 了。

Python 中变量与赋值

搞明白了什么是 值传递,什么是 引用传递,我们回到 Python 语言中来。在正式介绍 Python 中函数参数的传递方式之前,让我们先来回顾下什么是 Python 中的 变量,及 赋值 操作。

先来看一小段示例代码。

>>> a = 1
>>> b = a
>>> a = a + 2
>>> a
3
>>> b
1

在 Python 中,a = 1 这句代码实际上执行效果是先在内存中创建了一个 int 类型的对象 1,然后将对象 1 赋值给变量 a。变量 a 就是对象 1 的一个标识,我们可以把它比作一个 标签。当执行 b = a 的时候,可以理解为给对象 1 又贴了一个新的标签 b。当代码执行到 a = a + 2 时,由于 int 类型对象是不可变的,即不能在原对象 1 上做原地加 2 的操作,所以相当于将对象 1 上的标签 a 撕了下来,贴在了一个新的对象 3 上,而对象 1 上原来贴的标签 b 依然在那里。

可以通过流程图来看下整个代码执行过程。

a = 1

b = a

a = a + 2

以上就是 Python 中创建 不可变类型 对象,并将其 赋值变量 的过程。而对于 可变类型 对象的操作会产生不同的结果,下面通过对一个 list 对象操作进行演示。

>>> a = []
>>> b = a
>>> a.append(1)
>>> a
[1]
>>> b
[1]

前面两行代码 a = []b = a 与之前 不可变类型 对象的例子一样,只不过现在 ab 两个标签都贴在了可变对象 [] 上。当执行 a.append(1) 的时候,由于 list可变类型, 所以无需再次创建一个新的列表对象,而是直接在原对象上面做更改操作,因此标签 a 仍然贴在这个对象上,ab 最终依然指向的是同一个 list 对象,并且这个对象由原来的 [] 变成了 [1]

我们还是通过流程图来看下整个代码执行过程。

a = []

b = a

a.append(1)

由以上两个示例可以看出,实际上在 Python 中 变量 本身并没有所谓的 类型,我们可以把它当作 标签 来理解,而 变量 所指向的 对象 才有 类型 的区分。对于 不可变类型 来说,改变 变量 的值,实际上是在对 变量 作重新赋值的操作;而对于 可变类型,改变 变量 的值,实际上是直接修改它所指向的 对象 的值。

Python 中函数参数的传递方式

经过了前面的铺垫,现在可以正式介绍 Python 中函数参数的传递方式了。其实 Python 中唯一支持的函数参数的传递方式叫 对象的引用传递(call by object reference)。函数的 形参 将获得传递进来的 实参 的引用副本。

结合 Python 中变量与赋值就很容易理解这种传参方式了。Python 中一切皆 对象,而 变量对象 的关系是,变量 会通过指向一个 对象 来引用这个 对象 的值,所以函数传参时,并不需要根据数据类型来决定使用 值传递 还是 引用传递,只需要将 实参变量 的引用拷贝一份给 形参变量 就可以了,即让 形参实参 指向同一个对象。

下面分别来看两个示例,第一个示例传递给函数 不可变类型 参数,第二个示例传递给函数 可变类型 参数。

a = 1
def foo(p):
    p += 2
foo(a)
print(a)  # 1
li = [1, 2, 3]
def bar(p):
    p.append(4)
bar(li)
print(li)  # [1, 2, 3, 4]

两个示例的打印结果也证实了上面我们对 Python 中函数参数传递方式的分析。实际上,拿这两段示例代码跟最开始介绍 值传递引用传递 时所写的 JavaScript 代码进行比较,你会发现其实它们得到的竟然是同一种结果。

无论在 Python 中,还是在 JavaScript 中,对于 可变类型不可变类型 当作参数传入函数时,执行完函数体内部的代码后,最终体现出来的结果是相同的。但你要明白,这两种语言对于函数参数传递方式的处理机制是完全不同的,只不过它们最终体现出来的结果相同。

相关文章
|
4月前
|
存储 JavaScript Java
(Python基础)新时代语言!一起学习Python吧!(四):dict字典和set类型;切片类型、列表生成式;map和reduce迭代器;filter过滤函数、sorted排序函数;lambda函数
dict字典 Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度。 我们可以通过声明JS对象一样的方式声明dict
325 1
|
4月前
|
算法 Java Docker
(Python基础)新时代语言!一起学习Python吧!(三):IF条件判断和match匹配;Python中的循环:for...in、while循环;循环操作关键字;Python函数使用方法
IF 条件判断 使用if语句,对条件进行判断 true则执行代码块缩进语句 false则不执行代码块缩进语句,如果有else 或 elif 则进入相应的规则中执行
561 2
|
4月前
|
Java 数据处理 索引
(numpy)Python做数据处理必备框架!(二):ndarray切片的使用与运算;常见的ndarray函数:平方根、正余弦、自然对数、指数、幂等运算;统计函数:方差、均值、极差;比较函数...
ndarray切片 索引从0开始 索引/切片类型 描述/用法 基本索引 通过整数索引直接访问元素。 行/列切片 使用冒号:切片语法选择行或列的子集 连续切片 从起始索引到结束索引按步长切片 使用slice函数 通过slice(start,stop,strp)定义切片规则 布尔索引 通过布尔条件筛选满足条件的元素。支持逻辑运算符 &、|。
283 0
|
5月前
|
设计模式 缓存 监控
Python装饰器:优雅增强函数功能
Python装饰器:优雅增强函数功能
316 101
|
5月前
|
缓存 测试技术 Python
Python装饰器:优雅地增强函数功能
Python装饰器:优雅地增强函数功能
258 99
|
5月前
|
存储 缓存 测试技术
Python装饰器:优雅地增强函数功能
Python装饰器:优雅地增强函数功能
271 98
|
5月前
|
缓存 Python
Python中的装饰器:优雅地增强函数功能
Python中的装饰器:优雅地增强函数功能
|
6月前
|
Python
Python 函数定义
Python 函数定义
684 155
|
7月前
|
PHP Python
Python format()函数高级字符串格式化详解
在 Python 中,字符串格式化是一个重要的主题,format() 函数作为一种灵活且强大的字符串格式化方法,被广泛应用。format() 函数不仅能实现基本的插入变量,还支持更多高级的格式化功能,包括数字格式、对齐、填充、日期时间格式、嵌套字段等。 今天我们将深入解析 format() 函数的高级用法,帮助你在实际编程中更高效地处理字符串格式化。
674 0
|
5月前
|
JSON 缓存 开发者
淘宝商品详情接口(item_get)企业级全解析:参数配置、签名机制与 Python 代码实战
本文详解淘宝开放平台taobao.item_get接口对接全流程,涵盖参数配置、MD5签名生成、Python企业级代码实现及高频问题排查,提供可落地的实战方案,助你高效稳定获取商品数据。

推荐镜像

更多