阅读目录

  • 可变对象与不可变对象
  • 函数默认参数陷阱
  • 默认参数原理
  • 避免
  • 修饰器方法
  • 扩展
  • 参考

请看如下一段程序:

def extend_list(v, li=[]): li.append(v) return li list1 = extend_list(10) list2 = extend_list(123, []) list3 = extend_list('a') print(list1) print(list2) print(list3) print(list1 is list3)

请先猜想打印的结果:

是不是这样:

[10]
[123] [a] False

但是,实际的打印效果

请看如下解释:

<!-- lang: python -->
# 函数的定义相当于一次类型构造,默认值只在此时解析一次。 # 而函数调用时不会重新执行默认参数的构造。所以,如果使用了字典,列表这样的可变类型。 # 而又要在函数体内修改它,可能会出现意想不到的效果. def a(b=[]): b.append('hi') print b In [11]: a() ['hi'] In [12]: a() ['hi', 'hi'] In [13]: a(['2']) ['2', 'hi'] In [14]: a() ['hi', 'hi', 'hi'] In [15]: a.func_defaults Out[15]: (['hi', 'hi', 'hi'],) # 解决方法:参数默认值使用None赋值 def(b = None): b = b or [] pass # 类属性也有类似问题 class A(object): x = [] def __init__(self, c): self.x.append(c) # 这里的x搜索到类级别的x了而非实例的, # 因实例级别的x未事先定义 In [36]: a1, a2 = A(1), A(2) In [37]: a1.x, a2.x Out[37]: ([1, 2], [1, 2]) # 解决方法, 实例级别的属性事先定义 class B(object): x = [] def __init__(self, c): self.x = [] # 此处实例属性有x,所以先搜索到此 self.x.append(c) In [38]: b1, b2 = B(1), B(2) In [39]: b1.x, b2.x Out[39]: ([1], [2])

python可变对象做默认参数陷阱

可变对象与不可变对象

python中,万物皆对象。python中不存在所谓的传值调用,一切传递的都是对象的引用,也可以认为是传址。

python中,对象分为可变(mutable)和不可变(immutable)两种类型。

元组(tuple)、数值型(number)、字符串(string)均为不可变对象,而字典型(dictionary)和列表型(list)的对象是可变对象。

对于可变对象来说,传址是可以改变原对象的值的,对于不可变对象来说,传址相当于多了一个指向该值(不可变)的指针

不可变对象

可变对象

函数默认参数陷阱

下面这一段程序

#! /usr/bin/env python # -*- coding: utf-8 -*- class demo_list: def __init__(self, l=[]): self.l = l def add(self, ele): self.l.append(ele) def appender(ele): obj = demo_list() obj.add(ele) print obj.l if __name__ == "__main__": for i in range(5): appender(i)

输出结果是多少?

[0]
[0, 1] [0, 1, 2] [0, 1, 2, 3] [0, 1, 2, 3, 4]

而不是想象的

[0]
[1] [2] [3] [4]

而如果想达到第二种效果,只需将obj = demo_list() 改为obj = demo_list(l=[]) 即可

默认参数原理

官方文档中的一句话:

Default values are computed once, then re-used.

默认值是被重复使用的

Default parameter values are evaluated when the function definition is executed. This means that the expression is evaluated once, when the function is defined, and that the same “pre-computed” value is used for each call.

所以当默认参数值是可变对象的时候,那么每次使用该默认参数的时候,其实更改的是同一个变量

当python执行def语句时,它会根据编译好的函数体字节码和命名空间等信息新建一个函数对象,并且会计算默认参数的值。函数的所有构成要素均可通过它的属性来访问,比如可以用funcname属性来查看函数的名称。所有默认参数值则存储在函数对象的defaults_属性中,它的值为一个列表,列表中每一个元素均为一个默认参数的值

其中默认参数相当于函数的一个属性

Functions in Python are first-class objects, and not only a piece of code.

我们可以这样解读:函数也是对象,因此定义的时候就被执行,默认参数是函数的属性,它的值可能会随着函数被调用而改变。其他对象不都是如此吗?

避免

使用可变参数作为默认值可能导致意料之外的行为。为了防止出现这种情况,最好使用None值,并且在后面加上检查代码

def __init__(self, l=None): if not l: self.l = [] else: self.l = l

在这里将None用作占位符来控制参数l的默认值。不过,有时候参数值可能是任意对象(包括None),这时候就不能将None作为占位符。你可以定义一个object对象作为占位符,如下面例子:

sentinel = object() def func(var=sentinel): if var is sentinel: pass else: print var

修饰器方法

Python cookbook中也提到了这个方法,为了避免对每一个函数中每一个可能为None的对象进行一个if not l的判断,使用可更优雅的修饰器方法

import copy
def freshdefault(f): fdefaults = f.func_defaults def refresher(*args,**kwds): f.func_defaults = deepcopy(fdefaults) return f(*args,**kwds) return refresh

这段代码也再次认证了默认参数是函数的一个属性这一事实

扩展

python中函数的默认值只会被执行一次,(和静态变量一样,静态变量初始化也是被执行一次)。Python可以通过函数的默认值来实现静态变量的功能。

转载于:https://www.cnblogs.com/fmgao-technology/p/9105346.html

Python函数默认参数陷阱相关推荐

  1. python 函数 默认参数

    python 函数 默认参数 def add(a=1, b=2): # a,b设置默认参数c = a + breturn c c = add(a=2) # 如果不填,就是默认参数 print(c) 4

  2. 软件测试学习 之 Python 函数默认参数

    转载说明 作者:珞樱缤纷 出处:博客园 博文:Python进阶-函数默认参数 Python进阶-函数默认参数 写在前面 如非特别说明,下文均基于Python3 一.默认参数 python为了简化函数的 ...

  3. [python]函数默认参数顺序问题

    python 函数参数定义有四类: 1.必选参数:调用函数时候必须赋值的参数. a,须以正确的顺序传入函数 b,调用时的数量必须和声明时的一样 def exa(x):return x#b作为参数进入函 ...

  4. python 函数默认参数的小坑

    默认参数和可变对象 在执行def语句时,默认参数的值只被解析并保存一次,而不是每次在调用函数的时候.这通常是你想要的那样,但是因为默认值需要在每次调用时都保持同样对象,你在试图改变可变的默认值(mut ...

  5. python函数默认参数_Python中函数的默认参数问题

    前几天,运营反馈了一个BUG,某些数据在写入数据库后,其时间字段出现异常,与当前时间相差较多. 由于代码是不是我写的,所以开始一遍阅读代码一遍排查问题. 在主流程中,仅仅发现了一个对时间赋值的语句,并 ...

  6. python函数默认参数位置_二十二、Python函数参数类型(位置、关键字、默认、不定长参数)...

    调用函数时可使用的参数类型 在调用Python函数时可使用的参数类型主要有以下几种: 必要参数(位置参数) 关键字参数 默认参数 不定长参数 必要参数(位置参数) 在Python中, 必要参数必须以正 ...

  7. Python函数默认参数为空列表

    示例:  -测试命名比较随意- # foo?对象 def add(foo=[]):"""传入的参数为变量foo,指向的[]在定义函数之前创建,而不是每次执行前重新创建一个 ...

  8. python函数参数定义顺序_[python]函数默认参数顺序问题

    1.python2.python3 三者顺序是:位置参数.默认参数.*args def foo(x,y=1,*args):passfoo (1,2,3,4,5) // 其中的x为1,y=1的值被2替换 ...

  9. python函数默认参数作用域

    当def函数参数默认值为对象时,例如列表[],字典{} 示例1:猜测一下,会输出什么??? def ddd(a,b=[]):b.append(a)return bprint(ddd(1)) print ...

最新文章

  1. s-sar命令(System Activity Reporter系统活动情况报告)
  2. matlab偶极矩电场强度分布图_物理-电磁学|第三讲|静电场中的电介质
  3. Oracle 用户 对 表空间 配额(quota ) 说明
  4. 今天,终于又有时间更新飞鸽传书了。
  5. 一只小蜜蜂(HDU-2044)
  6. 初中位似图形作图_教师资格证面试中,哪些篇目最容易抽到?(初中数学篇)...
  7. Apache Commons DbUtils 入门
  8. arm linux装wine,Ubuntu下安装wine详细介绍
  9. 如何用python分析大数据_Twitter数据挖掘:如何使用Python分析大数据
  10. SQL单行函数-通用函数
  11. 程序员面试金典——3.4汉诺塔
  12. linux杂项设备+设备节点,linux driver ------ platform模型,通过杂项设备(主设备号是10)注册设备节点...
  13. 适应图像_目标检测的渐进域自适应,优于最新SOTA方法
  14. setTimeout 方法用于在指定的毫秒数后调用函数或计算表达式
  15. 基于SpringBoot实现二手交易商城
  16. Win1909+vs2019+Windows 10 WDK 2004(10.0.19041.1) + Windows 10 SDK 2004(10.0.19041.1)环境搭建
  17. python教你如何把自己的微信变成机器人
  18. 只需一个损失函数,一个超参数即可压缩BERT,MSRA提模型压缩新方法
  19. 51单片机延时程序的理解
  20. 《时代》杂志:元宇宙将如何塑造我们的未来?

热门文章

  1. 中国水产饲料市场发展深度调研及十四五前景预测报告2022年版
  2. 中国工程机械制造行业运营状况及发展方向预测报告2021-2027年
  3. 地摊经济和夜经济-国情讲坛·周荣江:城市生态谋定治理转型
  4. JavaScript 正则表达式
  5. springmvc 文件上传和拦截器
  6. easyUI Combobox自定义调整支持中文模糊查询
  7. 【转】Java中字符串中子串的查找共有四种方法(indexof())
  8. SQL Server 2008|2012 阻止保存要求重新创建表的更改
  9. Swift入门篇-循环语句
  10. 6台WEBLOGIC集群备份方案的讨论