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.如果默認參數一定要使用可變類型,那就在函數內部對默認參數重新賦值為可變類型的具體值.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM