zoukankan      html  css  js  c++  java
  • python定义函数时默认参数注意事项

    如果在调用一个函数时,没有传递默认参数,则函数内的默认参数是对函数的默认参数属性__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.如果默认参数一定要使用可变类型,那就在函数内部对默认参数重新赋值为可变类型的具体值.

  • 相关阅读:
    Android之rild进程启动源码分析
    ListView使用详解,listActivity使用方法
    打开其他android应用代码
    Android剖析和运行机制
    自定义Dialog(图片,文字说明,单选按钮)----类ListPreference实现(2)
    Internet采用哪种网络协议?该协议的主要层次结构?Internet物理地址和IP地址转换采用什么协议?
    引用与指针有什么区别?
    在C/C++中static有什么用途?
    软件验收测试包括
    自底向上集成
  • 原文地址:https://www.cnblogs.com/ch459742906/p/7710385.html
Copyright © 2011-2022 走看看