题目

任何长时间学习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. python入门经典必备推荐基础教程
  2. 揭秘码云:全球第二大代码托管平台的核心架构
  3. C#日期格式化(转)
  4. vba 日期加一年_VBA究竟值不值得审计学?
  5. 资讯|WebRTC M98 更新
  6. hashmap,hashTable concurrentHashMap 是否为线程安全,区别,如何实现的
  7. 【转】什么是CORS
  8. 研究综述 | 多关系知识图谱表示学习综述
  9. (转)详解JS位置、宽高属性之一:offset系列
  10. 匈牙利命名法、骆驼命名法、帕斯卡(pascal)命名法 C#命名规范
  11. EasyRecovery15绿色版免安装数据恢复软件
  12. 【CTFhub】彩蛋篇_持续更新
  13. ANSYS or Abaqus? 一个过来人的工作感悟
  14. speedoffice表格如何冻结窗格?
  15. html照片360度旋转展示,纯js实现360度旋转预览图片特效
  16. android 加速度 重力,安卓获取重力加速度例子
  17. 为什么女程序员那么少,我觉得程序员应该是最适合女性的职位
  18. java 几种生成海报的方式
  19. VUE模拟实现双向绑定
  20. 巨大的市场潜力,细数2019国内云计算新排名

热门文章

  1. linux切换用户时 su-,Linux切换用户(su)
  2. Windows IPC 连接详解
  3. Browser speed discrepancies
  4. 单片机加密の硬件加密和软件加密
  5. 2016开门红 亿赛通中标中信银行助建电子文档安全
  6. 基于selenium+scrapy爬取复仇者联盟4豆瓣影评数据
  7. 大咖云集!9月18日 Imagination Technologies 受邀参加2020中关村论坛
  8. java消息总线ibus_IBUS智能照明总线系统的应用
  9. mvnw命令启动spring boot项目时出现警告Unrecognised tag: ‘blocked’ (position: START_TAG seen …\r\n …
  10. 题库(3)_计算圆周率Π