Python函数缺省参数的 “ 坑 ” (与C++对比学习)

我们都知道Python函数的缺省参数可以降低我们调用函数的成本,但是一般我们的缺省参数都是不可变对象,如果是可变对象,我们对其多次调用会发生什么呢?

python 复制代码
def func(arr=[]):
    arr.append('Hello')
    print(arr)


func()
func()
func()    

这貌似很奇怪,因为在学习C++时,打印出来的信息应该都是一致的,如下:

cpp 复制代码
#include <iostream>
#include <vector>
void func(std::vector<int> arr = std::vector<int>())
{
    arr.push_back(1);
    for(auto& e : arr)
    {
        std::cout << e << " ";
    }
    std::cout << std::endl;
}
int main()
{
    func();
    func();
    func();
    return 0;
}

这是因为在C++中,只有在调用该函数的时候,才会创建对应的缺省参数的对象,所以每次调用都会在栈上创建一个新的vector对象,但是大家一定会观测到每次都地址都是一致的,但是无需担心,因为 arr 的作用域也只是在函数内部,每次调用的时候都是需要重新创建对象的。

cpp 复制代码
void func(std::vector<int> arr = std::vector<int>())
{
    arr.push_back(1);
    std::cout << &arr << std::endl;
}

在Python中,如果你定义了一个函数,并在定义函数参数的时候,为其制定了缺省参数,,那么这个缺省参数就会被维护起来,存储到了函数对象的属性中,直到程序结束或者函数对象被删除。所以我们每次调用的时候,都是在访问同一个缺省参数的对象,因为上面的缺省参数对象是一个可变对象,对其进行append操作就会改变对象的内容,所以就会观测到上面的现象了。
我们也可以观测一下这个缺省参数对象的地址:

python 复制代码
def func(arr=[]):
    arr.append('Hello')
    print("id = %d" % (id(arr)))
    # print(arr)


func()
func()
func()

我们可以观测到对象的id都是一致的,所以也可以证明这几次函数调用的缺省参数对象都是同一个

那如何解决这类问题?

python 复制代码
def func(arr=None):
    if arr is None:
        arr = []
        arr.append('Hello')
        print("id = %d" % (id(arr)))
        print(arr)


func()
func()
func()

这样设计就没有问题了,因为如果arr是一个空类型None,就会在函数内部重新被赋值成list列表,而此时list列表对象的生命周期和作用域都在函数内,即调用完函数就会被销毁,所以在打印的时候即使id值相同,也是不同对象。

相关推荐
笨鸟先飞,勤能补拙6 小时前
AI 赋能网络安全:技术全景、成熟度评估与实战案例
人工智能·python·安全·web安全·网络安全·sqlite·github
微学AI6 小时前
一根针指向所有方向:挂谷猜想对 LLM Agent 技能-记忆架构的启示
开发语言·人工智能·架构·挂谷猜想
似的8356 小时前
一步一步学习使用FireMonkey动画() 使用TAnimator类创建动画
linux·学习·nginx
长和信泰光伏储能7 小时前
京津冀光伏发电:绿色能源的未来之路
python·能源
fanged7 小时前
总线学习3--SPI番外(TODO)
学习
豆瓣鸡7 小时前
算法日记 - Day3
java·开发语言·算法
浦信仿真大讲堂7 小时前
从重复操作到自动化闭环:如何让 CST 与 Python 真正协同起来
python·自动化·cst·仿真软件·达索软件
韭菜炒鸡肝天8 小时前
VTK开发笔记(一):VTK介绍,Qt..+VSx+VTK.编译
开发语言·笔记·qt
Gu Gu Study8 小时前
ScoutLoop开放域深度研究引擎(agent的初步设计想法)
人工智能·python
小王C语言8 小时前
【7. 实现登录注册模块】:实现会话管理、注册/登录/退出 API
网络·c++