add by zhj: 文章写的很好,其实只要默认参数在函数中只读不写,那默认值就不会被修改,可变类型做默认参数就不会有问题

方法二中,当result is None时,修改result的指向,不再指向默认参数对象,而是赋值一个新的对象。如下,可以看到,result的id变化了

In [4]: def f(p=None, q=[]):
...: print id(p), id(q)
...: if p is None:
...: p = []
...: print id(p)
...: In [5]: f()
9568656 140309648126608
140309648094632 In [6]: f()
9568656 140309648126608
140309648074944

原文:https://blog.csdn.net/sinat_38068807/article/details/85677419

说明:默认参数值在函数被定义时已经计算出来,而不是在程序运行时。Python 程

序员经常犯的一个错误是把可变的数据类型(例如列表或者字典)当作默认参数值

(一)出现的问题

在下面的例子中,函数 buggy() 在每次调用时,添加参数 arg 到一个空的列表 result ,然
后打印输出一个单值列表。但是存在一个问题:只有在第一次调用时列表是空的,第二次
调用时就会存在之前调用的返回值

def buggy(arg, result=[]):
result.append(arg)
print(result) print('--------1--------')
buggy('a')
print('--------2--------')
buggy('b') # 期望得到 ['b']

执行结果:

--------1--------
['a']
--------2--------
['a', 'b']

(二)解释并测试

1.默认参数值在函数被定义时已经计算出来,而不是在程序运行时

2.只要函数调用时没有传递新的列表来覆盖默认参数列表,函数就会使用定义时的那个列表,并且操作依次叠加

3.上面两次调用中,都没有传递新的列表,程序会调用定义函数时保存的默认参数,并在上一次的基础上进行操作叠加,即:列表在append的时候会在 result原来的基础上append追加值,所以会产生以上结果.

我们通过打印列表的ID进行辨识来看看:

def buggy(arg, result=[]):
print(id(result))
result.append(arg)
print(result) print('--------1--------')
buggy('a')
print('--------2--------')
buggy('b') # expect ['b']

结果:

--------1--------
12205768
['a']
--------2--------
12205768
['a', 'b']

我们会发现ID值是相同的;

说明两次执行时使用的都是开始定义函数时的默认参数 ,进行了操作叠加

4.下面我们传递新的列表看看:

def buggy(arg, result=[]):
print(id(result))
result.append(arg)
print(result) print('--------1--------')
buggy('a')
print('--------2--------')
buggy('b', []) # 传递了新的列表

结果:

--------1--------
18497224
['a']
--------2--------
18504648
['b']

发现,列表id不同,并且得到了我们期望的值

(三)解决方法

方法1

# 如果写成下面的样子就会解决刚才的问题:

def works(arg):
result = []
result.append(arg)
print(result) works('a')
works('b')

结果:

['a']
['b']

方法2:

# 这样的修改也为了表明是第一次调用跳过一些操作:

def nonbuggy(arg, result=None):
if result is None:
result = []
result.append(arg)
print(result) nonbuggy('a')
nonbuggy('b')

结果:

['a']
['b']

python函数把可变数据类型当默认参数值的问题(转)的更多相关文章

  1. python函数中的位置参数、默认参数、关键字参数、可变参数区别

    一.位置参数 调用函数时根据函数定义的参数位置来传递参数. #!/usr/bin/env python # coding=utf-8 def print_hello(name, sex): sex_d ...

  2. python基础之可变数据类型与不可变数据类型

    一.什么可变数据类型和不可变数据类型 可变数据类型:value值改变,id值不变:不可变数据类型:value值改变,id值也随之改变. 二.如何确定一种数据类型是可变的还是不可变的 根据可变数据类型与 ...

  3. python中不可变数据类型和可变数据类型

    在学习python过程中我们一定会遇到不可变数据类型和可变数据类型. 1.名词解释 以下所有的内容都是基于内存地址来说的. 不可变数据类型: 当该数据类型的对应变量的值发生了改变,那么它对应的内存地址 ...

  4. Python 函数(可变参数)

    在python函数中,可以定义可变参数,顾名思义,可变参数就是,传入的参数是可变的例如,给定一组数字a,b,c...  请计算a2 + b2 + c2 + …… 要定义出这个函数,我们必须确定输入的参 ...

  5. python 函数传递可变参数的用法

    可变参数 在Python函数中,还可以定义可变参数.顾名思义,可变参数就是传入的参数个数是可变的,可以是1个.2个到任意个,还可以是0个. 我们以数学题为例子,给定一组数字a,b,c……,请计算a2 ...

  6. python中的可变数据类型和不可变数据类型

    1.不可变数据类型:数值.字符串.元组 不允许变量的值发生变化,如果变量的值变化了,那么就是新建了一个对象:对于相同值的对象,在内存中只有一个对象. 2.可变数据类型:列表.字典 允许变量的值发生变化 ...

  7. day14 Python函数之可变长参数

    函数参数 1.形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元.因此,形参只在函数内部有效.函数调用结束返回主调用函数后则不能再使用该形参变量 2.实参可以是常量.变量.表 ...

  8. 【转】Python函数默认参数陷阱

    [转]Python函数默认参数陷阱 阅读目录 可变对象与不可变对象 函数默认参数陷阱 默认参数原理 避免 修饰器方法 扩展 参考 请看如下一段程序: def extend_list(v, li=[]) ...

  9. Python面试题目之Python函数默认参数陷阱

    请看如下一段程序: def extend_list(v, li=[]): li.append(v) return li list1 = extend_list(10) list2 = extend_l ...

随机推荐

  1. 【python】md5加密方法相关使用

    md5方法在hashlib库中,使用前需要先导入.它的主要方法为update,copy,以及转换为二进制,十六进制. 用法说明: Help on HASH object: class HASH(bui ...

  2. 有道云笔记Markdown上传本地图片的方法

    有道云笔记截图&保存   方法有多种,例如:开通有道云笔记VIP会员.先将图片文件上传到有道云笔记后使用图片的分享链接.说到底还是使用的 Markdown 的图片功能 ![图片名称](图片链接 ...

  3. Java Spring Boot VS .NetCore (六) UI thymeleaf vs cshtml

    Java Spring Boot VS .NetCore (一)来一个简单的 Hello World Java Spring Boot VS .NetCore (二)实现一个过滤器Filter Jav ...

  4. Win下必备神器之Cmder

    诚言,对于开发码字者,Mac和Linux果断要比Windows更贴心;但只要折腾下,Windows下也是有不少利器的.之前就有在Windows下效率必备软件一文中对此做了下记载:其虽没oh-my-zs ...

  5. Spring Conditional注解使用小结

    今天我们来总结下Conditional注解的使用. Conditional注解 增加配置类Config package condition; import org.springframework.co ...

  6. Python 中文(大写)数字转阿拉伯数字(转)

    # constants for chinese_to_arabic CN_NUM = { '〇' : 0, '一' : 1, '二' : 2, '三' : 3, '四' : 4, '五' : 5, ' ...

  7. 关于python3.6上传文件时报错:HTTPSConnectionPool(host='***.org', port=443): Max retries exceeded with url: /post (Caused by SSLError(SSLError(1, '[SSL: CERTIFICATE_VERIFY_FAIL解决办法

    第一个报错: 最近在练习post请求中上传文件时遇到了一个奇葩事情,两台电脑上写了一模一样的代码,一个运行正常,另一个一片红. 最后了解了一下原因以及解决办法.先记录下关键代码: files = {& ...

  8. Visual GC提示"不受此JVM支持“解决方案(配置jstatd)

    Visual GC提示"不受此JVM支持“,如果想使用这个插件,就需要配置jstatd连接方式,下面来看jstatd的配置: 1.配置安全策略文件路径$JAVA_HOME/jre/lib/s ...

  9. 2019-2-20C#开发中常用加密解密方法解析

    C#开发中常用加密解密方法解析 一.MD5加密算法 我想这是大家都常听过的算法,可能也用的比较多.那么什么是MD5算法呢?MD5全称是 message-digest algorithm 5[|ˈmes ...

  10. Django——Ajax

    1.Ajax简介 AJAX(Asynchronous Javascript And XML)--"异步的JavaScript与XML". Ajax使用Javascript语言与服务 ...