如果在调用一个函数时,没有传递默认参数,则函数内的默认参数是对函数的默认参数属性__defaults__的引用,

def func(arg1=[]): arg1.append(2)

调用func时如果没有传参,上面的arg1就是func.__defaults__[0]的引用

没传递默认参数,会发生以下情况

由于func.__defaults__[0]是可变类型,导致每一次调用func,arg1都会对func.__defaults__[0]进行操作(func.__defaults__[0].append(2),

这样在有些情况下会导致逻辑出错的,例如

def func(arg1=[]): if(arg1==[]): print'arg1 is empty' arg1.append(1) else: print'arg1 is not empty'print arg1 func() # arg1 is empty

func() #arg1 is not empty [1]

第二次调用func的时候,并没有传递参数arg1,但是第一次调用时,函数内部已经修改了__defaults__

这是为啥呢?为何第二次调用不重置arg1为[]?

因为

Python的默认参数只会在函数定义时被确定,而不是每次调用时重新确定,所以,一旦在函数中修改了默认参数,则再随后的调用中都会生效

由于有这个特性,在定义函数时,如果默认参数使用可变的对象类型,如上例子,则很可能导致逻辑出错,

所以,如不是特别需要,则不允许在函数内部对默认参数引用的func.__defaults__属性进行修改,如何能让一个对象不被修改?那就是在操作arg1前取消它对__defaults__的引用

以上例子改动一下

def func(arg1=[]): if(arg1==[]): print'arg1 is empty' arg1=[] arg1.append(1) else: print'arg1 is not empty'print arg1

上例中,在用户没有传递默认参数arg1时,函数内部会给arg1变量重新赋值,让arg1去引用我们想用的对象[],这样arg1就不会修改func.__defaults__了

如果是默认参数是有值的情况,可以这样操作

def func(arg1=[1,2,3]): if(arg1==[1,2,3]): print'is [1,2,3]' arg1=[1,2,3] #重点是这里,取消arg1对__defaults__属性的引用,防止arg1修改__defaults__ arg1.append(1) else: print'not [1,2,3]'print arg1

以上太啰嗦,下例模仿了python官方例子,使用不可变类型(例如None)作为默认参数,逻辑简洁,推荐使用

def append_to(element, to=None): #默认参数to定义时为None,但函数逻辑中进行进一步重新赋值为想使用的默认值

if to is None: to = [1,2,3] to.append(element) return to

总结:

防止默认参数修改函数的__defaults__,需要:

1.定义默认参数时,最好使用不可变类型.

2.如果默认参数一定要使用可变类型,那就在函数内部对默认参数重新赋值为可变类型的具体值.

python定义函数时默认参数注意事项的更多相关文章

  1. python定义函数时的参数&调用函数时的传参

    一.定义函数: 1.位置参数:直接定义参数 2.默认参数(或者关键字参数):参数名 = "默认值" 3.位置参数必须在默认参数之前 二.调用函数: 1.按位置传,直接写参数的值 2 ...

  2. python定义函数时的默认返回值

    python定义函数时,一般都会有指定返回值,如果没有显式指定返回值,那么python就会默认返回值为None, 即隐式返回语句: return None 执行如下代码 def now(): prin ...

  3. python中函数的默认参数陷阱问题

    其实也不能说是陷阱,只是一个不容易注意到的地方,尤其是有其他java/c++类编程语言经验的人员,这里涉及到python的一个特点,所以笔者说是陷阱只是一个噱头而已. def test(item, b ...

  4. python定义函数时,形参前加*和**的意义

    转发:https://blog.csdn.net/qq_34806812/article/details/82017839 1.加*表示接受一个tuple类型(元组),如: 2.加**表示接受一个di ...

  5. Python 中函数的 收集参数 机制

    定义函数的时候,在参数前加了一个 * 号,函数可以接收零个或多个值作为参数.返回结果是一个元组. 传递零个参数时函数并不报错,而是返回一个空元组.但以上这种方法也有局限性,它不能收集关键字参数. 对关 ...

  6. Python函数的默认参数的设计【原创】

    在Python教程里,针对默认参数,给了一个“重要警告”的例子: def f(a, L=[]): L.append(a) return L print(f(1)) print(f(2)) print( ...

  7. 在python函数中默认参数的一些坑

    一.默认参数 python为了简化函数的调用,提供了默认参数机制: 这样在调用pow函数时,就可以省略最后一个参数不写: 在定义有默认参数的函数时,需要注意以下: 必选参数必须在前面,默认参数在后: ...

  8. 对C++虚函数使用默认参数的注意事项

    本文为大便一箩筐的原创内容,转载请注明出处,谢谢:http://www.cnblogs.com/dbylk/ 备忘一个关于虚函数的小知识点 使用多态调用一个类型中定义的虚函数时,编译器会根据指针的当前 ...

  9. 【C/C++】函数的默认参数/函数的占位参数/函数重载/注意事项

    函数的默认参数 返回值类型 函数名(参数=默认值){} #include <iostream> using namespace std; int func(int a = 10, int ...

随机推荐

  1. BAT-把当前用户以管理员权限运行

    相关资料: http://jingyan.baidu.com/article/72ee561a5dc24fe16138df95.html 网友求助:联想Y400,Win8系统 怎样获得管理员身份 要求 ...

  2. PHP——字符串

    <?php //strlen("aaa");取字符串的长度 *** echo strlen("aaaaa"); echo "<br /&g ...

  3. call_usermodehelper内核中运行用户应用程序

    init是用户空间第一个程序,在调用init前程序都运行在内核态,之后运行init时程序运行到用户态. 操作系统上,一些内核线程在内核态运行,它们永远不会进入用户态.它们也根本没有用户态的内存空间.它 ...

  4. Laravel 5.1 中创建自定义 Artisan 控制台命令实例教程

    1.入门 Laravel通过Artisan提供了强大的控制台命令来处理非浏览器业务逻辑.要查看Laravel中所有的Artisan命令,可以通过在项目根目录运行: php artisan list 对 ...

  5. 解决cookie跨域访问.2

    v一.前言 随着项目模块越来越多,很多模块现在都是独立部署.模块之间的交流有时可能会通过cookie来完成.比如说门户和应用,分别部署在不同的机器或者web容器中,假如用户登陆之后会在浏览器客户端写入 ...

  6. 关于Spring MVC Controller 层的单元测试

    关于Spring MVC Controller 层的单元测试 测试准备工作: 1.搭建测试Web环境 2.注入Controller 类 3.编写测试数据 测试数据的文件名一定要与测试类的文件名相同,比 ...

  7. iOS音频播放 (三):AudioFileStream 转

    原文出处 :http://msching.github.io/blog/2014/07/09/audio-in-ios-3/ 前言 本来说好是要在第三篇中讲AudioFileStream和AudioQ ...

  8. glibc升级小记

    2015年元月最后几天,glibc幽灵漏洞来袭,引用 中华财经网的报道 稍做介绍: Linux glibc函数库日前曝出名为GHOST(幽灵)的高危漏洞,漏洞编号是CVE-2015-0235.攻击者可 ...

  9. jQuery实现提交按钮点击后变成正在处理字样并禁止点击的方法

    本文实例讲述了jQuery实现提交按钮点击后变成正在处理字样并禁止点击的方法.分享给大家供大家参考.具体实现方法如下: 这里主要通过val方法设置按钮的文字,并用attr方法修改disabled属性实 ...

  10. IOC和AOP的一些基本概念

    IOC和AOP的一些基本概念介绍 IOC 介绍 IOC 一.什么是IOC IoC就是Inversion of Control,控制反转.在Java开发中,IoC意味着将你设计好的类交给系统去控制,而不 ...