题目

任何长时间学习Python的人都会遇到下面的问题。

def foo(a=[]):

a.append(5)

return a

Python初学者期望这个函数总是会返回一个只包含一个元素的列表:[5],结果并非如此。

>>> foo()

[5]

>>> foo()

[5, 5]

>>> foo()

[5, 5, 5]

>>> foo()

[5, 5, 5, 5]

>>> foo()

我的主管曾遇到过这个问题,并称其为语言的“戏剧性设计缺陷”。我回答说这个行为可能另有深意,如果不理解内部实现,那确实令人费解。但是,我没法解释:在函数定义中绑定默认参数的原因是什么,为什么不是在函数执行时?我怀疑这种方式是否具有实际用处(就如在C中使用静态变量而没有引发bug)。

这里有一个有趣的例子:

>>> def a():

... print("a executed")

... return []

...

>>>

>>> def b(x=a()):

... x.append(5)

... print(x)

...

a executed

>>> b()

[5]

>>> b()

[5, 5]

默认参数在函数定义时就已经计算好了。

回答一

事实上,这并不是一个设计缺陷,而且与内部实现、性能无关。

这仅仅是因为一个事实:在Python中函数是一等公民,而不只是代码片段。

继续深入思考,你会觉得这是合理的:函数也是对象,在定义时被执行得到的对象;默认参数类似“成员数据”,因此它们的状态在多次调用后会发生改变——就如在任何其他对象里一样。

我觉得这篇文章简洁明了,如果想对函数对象是如何工作的有更好的理解,也建议阅读。

为什么会这样

默认参数值会被计算,当且仅当其所属的def语句被执行。

def是Python中的可执行语句,而且默认参数是在def语句环境里被计算。如果执行def语句多次,每次它将会产生新的函数对象(默认参数也会重新计算)

替代方法

使用占位符代替修改默认值,None是个很好的选择。

def myfunc(value=None):

if value is None:

value = []

# modify value here

具体是怎么执行的

当Python执行def语句时,它需要一些已经生成的部分(包括函数体和当前命名空间的编译代码)创建一个新的函数对象。默认参数也是在这时候被计算的。

各个部分作为函数对象的属性:

>>> function.func_name

'function'

>>> function.func_code

00BEC770, file "", line 1>

>>> function.func_defaults

([1, 1, 1],)

>>> function.func_globals

{'function': 0x00BF1C30>,

'__builtins__': '__builtin__' (built-in)>,

'__name__': '__main__', '__doc__': None}

因为我们可以访问到默认参数,因此可以改变它们

>>> function.func_defaults[0][:] = []

>>> function()

[1]

>>> function.func_defaults

([1],)

另一种重置默认参数的方法时简单地重新执行相同的def语句。Python将会创建创建新的绑定给这个函数对象,重新计算默认参数,像之前一样将函数对象赋值给同一个变量。但是话说回来,当且仅当你知道你在做什么时才这么去使用。

python默认参数 可变对象_最小经验原则(POLA)与可变默认参数相关推荐

  1. python默认参数 可变对象_当心Python函数可变默认参数(list,set,dict…)的陷阱

    绝大多数情况下,Python是一个干净具有一致性的语言.然而,有些少数情况会让初学者感到困惑.其中有些情况是有意识的但会成为潜在的莫名其妙,而有些可以说是语言赘肉.下面我们看看使用可变默认参数(Mut ...

  2. python哪些是可变对象_什么是Python可变对象和不可变对象

    什么是Python可变对象和不可变对象 发布时间:2020-07-22 09:59:15 来源:亿速云 阅读:60 作者:Leah 这篇文章运用简单易懂的例子给大家介绍什么是Python可变对象和不可 ...

  3. python可变对象 不可变对象_【Python】可变对象和不可变对象

    在 Python 中一切都可以看作为对象.每个对象都有各自的 id, type 和 value. id: 当一个对象被创建后,它的 id 就不会在改变,这里的 id 其实就是对象在内存中的地址,可以使 ...

  4. java创建一个不可变对象_使用不可变对象创建值对象

    java创建一个不可变对象 在回答我最近的文章中AutoValue:生成的不可变的值类 , 布兰登认为,这可能是有趣的,看看如何AutoValue比较项目Lombok和Immutables和凯文借调这 ...

  5. python函数赋值给对象_【Python核心编程笔记】一、Python中一切皆对象

    Python中一切皆对象本章节首先对比静态语言以及动态语言,然后介绍 python 中最底层也是面向对象最重要的几个概念-object.type和class之间的关系,以此来引出在python如何做到 ...

  6. java创建一个不可变对象_如何在Java中创建不可变类?

    java创建一个不可变对象 Today we will learn about the immutable class in Java. What are immutable classes? The ...

  7. 不可变集合相比可变集合_简单的基准测试:不可变集合VS持久集合

    不可变集合相比可变集合 通常,您需要向集合中添加新元素. 因为您是一个优秀而谨慎的开发人员,所以您希望尽可能保持不变. 因此,向不可变集合中添加新元素将意味着您必须创建一个新的不可变集合,其中包含原始 ...

  8. python方法大全参数是对象_向对象方法Python传递太多参数

    所以我想我有一个非常简单的案子,但我完全不明白为什么它不能执行.在 这是我的来源-这是我的主.py我通过执行'python'来运行的文件主.py'从命令行:import player import e ...

  9. python中可迭代对象_什么是python中的可迭代对象(iterable object)?

    我们经常在打印报错信息中和英文的文档中看到iter这个词根,可以组合成iterable/iterate等派生词.这个iter可以翻译成"迭代",这样iterable object的 ...

最新文章

  1. tm matlab,[转载]关于matlab中textread
  2. linux php进程端口占用,linux如何查看端口占用情况
  3. STC8G1K单片机软件执行时间物理测量
  4. 用vector实现一个变长数组
  5. 【Python】【入门】一文带你掌握Python27入门 ~
  6. android关机菜单修改,Android4.4关机菜单添加重启系列选项
  7. 从Exchange 通往Office 365系列(十六)添加域名到Office 365
  8. 史陶比尔与机器人之父
  9. python语言学习零基础教学视频_Python告白小白视频教程(零基础入门)
  10. 关联查询数据重复怎么办_在设计数据表的时候,是一个宽表好,还是多个维度表好?...
  11. concurrently同时开启多个监听服务
  12. 【win32汇编】0x04 第一个窗口程序
  13. Spark 基础 —— sc.broadcast
  14. 36 Unicode和字节字符串
  15. 3.1. 一元、多元逻辑回归、tensorflow2实现——python实战
  16. OpenCV46:立体图像的深度图|Depth Map
  17. Qt/C++ 网易云api 在线播放音乐
  18. passing 'const xxx ' as 'this' argument discards qualifiers [-fpermissive]
  19. 空间域图像增强(matlab实现)
  20. u盘的大小在计算机无法显示,U盘格式化后插入电脑打不开,不显示U盘大小怎么解决?...

热门文章

  1. FPGA模拟PS2接口的方法
  2. 汇顶科技外包java_【汇顶科技有限公司Java面试】2020春季校招后端Java-看准网
  3. 微信小程序学习-组件Map-地图初始定位
  4. 多字节、UTF-8、Unicode之间的转换
  5. 智牛股_第5章_Netty+PowerDesigner
  6. 真正射影像(TrueOrtho)的生产和应用
  7. 【MSP430G2553】图形化开发笔记(5) UART 串口及printf
  8. 触发器实现当一个表中字段改变时同时改变另一个表中字段值
  9. Linux压缩解压tar.gz和zip包命令汇总
  10. 关于移动端音乐没有自动播放的问题