python函数之可变默认参数

2023-10-31

一个 Python Bug 干倒了估值 1.6 亿美元的公司
今天在CSDN首页看到这篇文章,不仅感概:

水能载舟,亦能覆舟

作为一家仰仗技术出身的公司,最终却因为技术的问题而断崖式地走向没落,实在令人唏嘘。技术既能让一家公司崛起,但使用不当、糊里糊涂或者想当然地去使用,可能一个小小的问题也足以摧毁一家公司。当然,在这里也不过多地聊这个故事,感兴趣的可以点文章链接详细看看。我就从技术的角度简单剖析下这里面出现的bug及其背后的原理。

问题剖析

这个问题涉及到python函数定义中的可变默认参数,那什么是可变默认参数呢?就拿文章中提到的函数举例:

def foo(l=[]):
    l.append(1)
    print(l)

在函数foo中,参数l是有默认值的,所以是一个默认参数,并且默认值是一个空列表[],而列表是属于可变对象,即不可散列的对象,因此参数l就是一个可变默认参数。

在函数定义中,使用可变(不可散列unhashable)对象作为默认值的参数,就是可变默认参数

那么,在函数中使用可变默认参数会有什么问题呢?就像上面的函数foo,很多人可能会想当然地认为,当不传递参数,多次调用函数foo()的时候,输出的结果都是一样的,都是[1],但实际上偏偏想法,该函数的行为与我们预期的不符合:

在这里插入图片描述

可以看到,后面函数调用的输出确实不符合我们的预期,所以问题在哪里。其实只要搞清楚了python对函数的默认参数的管理机制和调用逻辑,这个问题就迎刃而解了。

首先,我们看看函数参数的默认值存在哪里,使用dir看看函数对象的属性:

In [7]: dir(foo)
Out[7]:
['__annotations__',
 '__call__',
 '__class__',
 '__closure__',
 '__code__',
 '__defaults__',
 '__delattr__',
 '__dict__',
 '__dir__',
 '__doc__',
 '__eq__',
 '__format__',
 '__ge__',
 '__get__',
 '__getattribute__',
 '__globals__',
 '__gt__',
 '__hash__',
 '__init__',
 '__init_subclass__',
 '__kwdefaults__',
 '__le__',
 '__lt__',
 '__module__',
 '__name__',
 '__ne__',
 '__new__',
 '__qualname__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__']

注意到,这里面有个__defaults__,就是缺省、默认的意思,输出其内容:

In [8]: foo.__defaults__
Out[8]: ([1, 1, 1, 1, 1],)

但我们调用函数的时候,它的值也会随之改变:

In [9]: foo()
[1, 1, 1, 1, 1, 1]

In [10]: foo.__defaults__
Out[10]: ([1, 1, 1, 1, 1, 1],)

In [11]: foo()
[1, 1, 1, 1, 1, 1, 1]

In [12]: foo.__defaults__
Out[12]: ([1, 1, 1, 1, 1, 1, 1],)

In [13]: foo()
[1, 1, 1, 1, 1, 1, 1, 1]

In [14]: foo.__defaults__
Out[14]: ([1, 1, 1, 1, 1, 1, 1, 1],)

我们重新定义foo函数,在看看其__defaults__属性的值:

In [15]: def foo(l=[]):
    ...:     l.append(1)
    ...:     print(l)
    ...:

In [16]: foo.__defaults__
Out[16]: ([],)

再做个实验,向__defaults__中的列表对象添加一个数1024,再调用函数,看看结果如何:

In [17]: foo.__defaults__[0].append(1024)

In [18]: foo.__defaults__
Out[18]: ([1024],)

In [19]: foo()
[1024, 1]

结果不出所料,在函数中向列表添加元素,其实就是向__defaults__中的列表对象添加元素,也就是说函数中的l变量和__defaults__中的第一个元素引用的是同一个列表对象。所以从以上的分析可以看出函数对象的默认参数值确实是存放在其__defaults__属性中。

到这里,我们应该大致了解了python函数默认参数的一些原理:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

python函数之可变默认参数 的相关文章

  • 如何在GPU支持下运行python代码

    我创建了一个 Flask 服务 用于接受以相机 URL 作为参数的请求 用于在相机框架中查找对象 桌子 椅子等 我已经在 Flask 中编写了用于接受 POST 请求的代码 app route rest detectObjects meth
  • 如何从本地模式下运行的 pyspark 中的 S3 读取数据?

    我正在使用 PyCharm 2018 1 使用 Python 3 4 并通过 virtualenv 中的 pip 安装 Spark 2 3 本地主机上没有安装hadoop 因此没有安装Spark 因此没有SPARK HOME HADOOP
  • 如何计算 numpy 数组中元素的特定范围

    我有一个像这样的数组 import numpy as np data np array 0 0 0 1 1 1 0 0 0 0 1 1 1 1 1 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0
  • 使用 scipy.signal.spectrogram 在 pyqtgraph 中绘制 wavfile 的频谱

    我有一个用于音乐和语音分析的 PyQt 加 pyqtgraph 程序 我想绘制 wav 文件的频谱 使用 scipy python 包计算 我可以在 matplotlib 中完成 但由于 matplotlib 的性能 我需要切换到 pyqt
  • 如何并行安装/编译 pip 要求(使 -j 等效)

    我的 pip 要求中有很多软件包需要安装 我想并行处理它们 我知道 例如 如果我想要n并行作业来自make我必须写make j n 是否有满足 pip 要求的等效命令 Thanks 有时 pip 使用 make 来构建依赖项 如果在开始之前
  • 对 numpy 数组的每 n 个元素求平均值

    我有一个 numpy 数组 我想创建一个新数组 它是每个连续三元组元素的平均值 因此 新数组的大小将是原始数组的三分之一 举个例子 np array 1 2 3 1 2 3 1 2 3 应该返回数组 np array 2 2 2 谁能建议一
  • 使用 LSTM 进行时间序列模式识别(python)

    我的应用场景和上一个类似时间序列中的模式识别 https stackoverflow com questions 11752727 pattern recognition in time series By processing a tim
  • 字符串中数字的连续相加

    我是一名正在学习 python 的新程序员 并且在如何完成此任务方面遇到了困难 所以本质上我有一个从文件导入的数字字符串需要读取 并且需要将第一个数字的总和添加到第二个数字并将其转换为正确的 ascii 字符 因此 例如 如果我正在读取字符
  • Django 视图集没有属性“get_extra_actions”

    我第一次使用 Django 我正在尝试构建一个 API 我正在遵循一些教程和示例 它工作正常 但在安装所有要求和项目后 我现在正在 Raspberry Pi 中运行该项目失败并出现以下错误 Performing system checks
  • xlwt 可以在单元格中创建一个包含标题和链接变量的超链接吗?

    例如 如何更改以下行 使 test 为变量 T 且 http google com http google com 是变量L ws write 0 0 xlwt Formula test HYPERLINK http google com
  • 无法启动 Windows 快捷方式

    我正在尝试使用 python 启动 Windows 我已经尝试了 os system subprocess call os startfile 等多种方法 但总是收到错误消息 指出路径不存在 我知道路径是正确的 因为我尝试在 CMD EXE
  • Python Twisted 与 Cmd 模块集成

    我喜欢Python的Twisted http twistedmatrix com and Cmd http docs python org library cmd html 我想一起使用它们 我已经完成了一些工作 但到目前为止我还没有弄清楚
  • 使用 python3 查找表情符号的宽度

    我尝试使用 python 中的模式打印字母 A def printA length height symbol a for i in range length for i in range height for i in range hei
  • 使用 python 聚合 elasticsearch-dsl 中的字段

    有人可以告诉我如何编写 Python 语句来聚合 求和和计数 有关我的文档的内容吗 SCRIPT from datetime import datetime from elasticsearch dsl import DocType Str
  • numpy 相关系数错误 - RuntimeWarning:true_divide 中遇到无效值

    当我尝试查找数据系列之间的相关性时 出现以下错误 gt gt gt i 1 1 1 gt gt gt j 2 2 2 gt gt gt import numpy as np gt gt gt np corrcoef i j usr loca
  • 禁用或限制 /o/applications(django rest 框架、oauth2)

    我目前正在使用 Django Rest 框架编写 REST API 并使用 oauth2 进行身份验证 使用 django oauth toolkit 我对他们俩都很满意 他们做的正是我想要的 然而 我有一个担忧 我正在将我的应用程序传递到
  • 如何将 bisect.insort_left 与键一起使用?

    文档缺少示例 你如何使用bisect insort left 基于密钥 尝试根据键插入 bisect insort left data brown 7 将插入放在data 0 从文档 bisect insort left a x lo 0
  • 仅将唯一行插入 SQLite (python)

    我在用着cursor executemany将 CSV 文件中的批量行插入到 SQLite 表中 根据主键字段 其中一些行预计会重复 当我执行该命令时 可以预见的是 我会收到完整性错误 并且不会插入任何内容 如何有选择地仅插入非重复行 而无
  • 子进程调用,它们是并行完成的吗?

    我一直在谷歌搜索这个问题的答案 但似乎没有一个答案 谁能告诉我如果subprocess模块是否并行调用 Python 文档建议它可用于生成新进程 但没有提及它们是否并行 如果它们可以并行完成 您能否给我举一个例子或将我链接到一个例子 这取决
  • pyodbc 无法正确处理 unicode 数据

    我确实使用 pyodbc 成功连接了 MySQL 数据库 并且它可以很好地处理 ascii 编码的数据 但是当我打印使用 unicode utf8 编码的数据时 它引发了错误 UnicodeEncodeError ascii codec c

随机推荐

  • SpringBoot + MyBatis 结合 MVC框架设计 第2关:使用SpringBoot + MyBatis实现一个最简单的注册功能

    目录 任务描述 相关知识 项目创建 MVC框架 使用MVC分层实现注册 编程要求 测试说明 参考代码 任务描述 本关任务 使用SpringBoot MyBatis实现一个最简单的注册功能的小程序 相关知识 为了完成本关任务 你需要掌握 1
  • 俄语网站大全

    俄文网站大全 发表日期 2008年1月21日 已经有447位读者读过此文 转帖一些俄文网站 当然不排除一些网址可能已经打不开了 朋友们可以有选择的浏览 俄文网址 搜索引擎 语言 文学 http www weblist ru 汉俄通 http
  • FastDFS的三大误解

    FastDFS的三大误解 本篇文章转载于 FastDFS 作者 余庆 大佬的 FastDFS分享与交流 公众号 整理个别同学对FastDFS的三个误解 我将逐一澄清 误解一 FastDFS不易安装和配置 网上有人吐槽说 FastDFS 是他
  • 如何使用M33D1一体式在线氨氮传感器

    一 应用环境说明 M33D1一体式在线氨氮传感器是一种基于PVC膜制作的的铵离子选择电极 用于测量水中的铵离子含量 带有温度补偿 确保测量快速 简单 精确和经济 本册中详细介绍了氨氮传感器的技术参数 通讯协议和使用维护等内容 1 信号输出
  • String 类简述笔记

    前言 string是C java VB等编程语言中的字符串 用双引号引起来的几个字符 如 Abc 一天 字符串是一个特殊的对象 属于引用类型 在java C 中 String类对象创建后 字符串一旦初始化就不能更改 因为string类中所有
  • spring boot学习之自定义starter启动器

    starter启动器的目标 引入maven包即可自动装配配置 个人理解 如jdbc引入即可操作数据库 实现 1新建springboot工程编写实现类 2编写配置类 3配置 4打包 4新建工程引入使用
  • 移动端rem适配方案(解决1px 兼容问题)

    div style width 7 5rem height 2rem background red div
  • 使用openssl合成pfx格式证书的国密证书

    目前 openssl也已经开始支持国密协议 这边使用的是openssl 1 1 1k 进行的测试 下面记录一下自己的测试步骤 下载地址 https www openssl org source 安装编译方法参考下面地址 我也是参考下面进行安
  • JAVA学习日记(2)--找出某一个范围内完数

    完数 5分 题目内容 一个正整数的因子是所有可以整除它的正整数 而一个数如果恰好等于除它本身外的因子之和 这个数就称为完数 例如6 1 2 3 6的因子是1 2 3 现在 你要写一个程序 读入两个正整数n和m 1 lt n
  • 入门stm32简单电灯实验

    看原理图找内置LED接线 stm32f103 我这边是接的 PE5 外设时钟使能寄存器的相关配置 因为LED1接的是PE5 所以GBIO端口E 查看中文手册获取GPIOE寄存器起始地址0x4001 1800 通过查看系统架构 可以发现GPI
  • 【开发环境】Windows下搭建TVM编译器

    关于搭建TVM编译器的官方文档 Install from Source tvm 0 14 dev0 documentation apache org 1 安装Anaconda 首先我们需要安装Anaconda 因为其中包含着我们所需要的各类
  • QPalette的详细使用示例

    1 功能简介 QPalette是Qt中的调色板类 它提供的setColor 函数可改变控件的颜色 其原型为 void QPalette setColor ColorRole acr const QColor acolor 其中 ColorR
  • 一篇完整学习JUC并发编程(包含实例源码)

    文章目录 JUC并发编程 1 什么是JUC 2 线程和进程 并发 并行 线程有几个状态 6个 wait sleep区别 3 Lock锁 传统sychronized锁卖票实例 使用Lock锁卖票实例 sychnorized 和 lock锁区别
  • 循序渐进地代码重构

    对于如何进行代码重构 一直有着很多种说法 很多人都认为应该将重构代码放在backlog里 但是其实 这并不是一个理想的方法 在项目刚刚开始的时候 你的代码很干净 即使有的时候需要小小的绕一下路 但是这个时候我们可以轻松 平稳的添加功能 这个
  • sql年月日的取值

    一个月第一天的SQL 脚本 SELECT DATEADD mm DATEDIFF mm 0 getdate 0 本周的星期一 SELECT DATEADD wk DATEDIFF wk 0 getdate 0 一年的第一天 SELECT D
  • 使用eclipse将项目达成war包并部署至服务器

    一 eclipse将ssm项目打成war包 1 右击要打war包的项目 选择Export 2 选中Web文件下的WAR file点击Next 3 点击Browse 选择打war包存放的地址 点击Finish开始打包 将打好的War包部署至服
  • 常用的几款抓包工具

    常用的几款抓包工具 标签 软件测试软件测试方法软件测试学习 原创来自于我们的微信公众号 软件测试大师 最近很多同学 说面试的时候被问道 有没有用过什么抓包工具 其实抓包工具并没有什么很难的工具 只要你知道你要用抓包是干嘛的 就知道该怎么用了
  • Pandas基础操作(上)

    文章目录 一 Pandas文件读取 1 pandas数据读取 1 读取纯文本文件 1 1 读取csv 使用默认的标题行 逗号分隔符 1 2 读取txt文件 自己指定分隔符 列名 2 读取excel文件 3 读取sql文件 二 pandas的
  • Centos7升级内核——图文详尽版

    Linux是一种开源电脑操作系统内核 它是一个用C语言写成 符合POSIX标准的类Unix操作系统 Linux最早是由芬兰 Linus Torvalds为尝试在英特尔x86架构上提供自由的类Unix操作系统而开发的 该计划开始于1991年
  • python函数之可变默认参数

    文章目录 问题剖析 元组的使用 一个 Python Bug 干倒了估值 1 6 亿美元的公司 今天在CSDN首页看到这篇文章 不仅感概 水能载舟 亦能覆舟 作为一家仰仗技术出身的公司 最终却因为技术的问题而断崖式地走向没落 实在令人唏嘘 技