python語(yǔ)言陷阱

python語(yǔ)言陷阱

python作為一門(mén)動(dòng)態(tài)語(yǔ)言,除了擁有強(qiáng)大的表達(dá)能力和高效的開(kāi)發(fā)效率外,它還有著一些語(yǔ)言層面的陷阱。

可變參數(shù)作為默認(rèn)參數(shù)

有時(shí)會(huì)看到有些小伙伴在python中定義函數(shù)的時(shí)候會(huì)使用一些可變參數(shù)作為函數(shù)的默認(rèn)參數(shù),最常見(jiàn)的如:list。

def test(a=[]):
    a.append(1)
    print(a)


if __name__ == '__main__':
    test()  # [1]
    test()  # [1, 1]

使用可變參數(shù)作為函數(shù)的默認(rèn)參數(shù)會(huì)讓最后的運(yùn)行結(jié)果超出預(yù)期所料。如上述例子中,第一次和第二次的結(jié)果截然不同。

如果不明白為什么會(huì)產(chǎn)生這樣的結(jié)果,看下面這個(gè)例子就會(huì)明白了

def test(a=[]):
    a.append(1)
    print(a)


def test2(a=print("test2")):
    pass


if __name__ == '__main__':
    test()  # [1]
    test()  # [1, 1]

運(yùn)行上述例子,你會(huì)發(fā)現(xiàn)控制臺(tái)會(huì)去打印"test2"。通過(guò)對(duì)比你會(huì)發(fā)現(xiàn),函數(shù)的參數(shù)在函數(shù)被定義的時(shí)候就已經(jīng)確定了,如果參數(shù)是個(gè)表達(dá)式,則取表達(dá)式的結(jié)果。所以在test函數(shù)中, 無(wú)論運(yùn)行多少次,在函數(shù)里面都是在對(duì)函數(shù)被定義時(shí)的那個(gè)list進(jìn)行操作。

最開(kāi)始的那個(gè)例子就等同于下面的代碼

a = []


def test():
    a.append(1)
    print(a)


if __name__ == '__main__':
    test()  # [1]
    test()  # [1, 1]

避免此類(lèi)事故的發(fā)生的最好的方法就是不使用可變參數(shù),將默認(rèn)參數(shù)的行為放到函數(shù)內(nèi)部去定義。下面是改進(jìn)后的版本。

def test(a=None):
    if a is None:
        a = []
    a.append(1)
    print(a)


if __name__ == '__main__':
    test()  # [1]
    test()  # [1]

tuple的隱式變換

a = 1,  # 1

b = [1],  # ([1],)

c = (1)  # 1

d = (1,)  # (1,)

e = True if 10 / 2 > 2 else False, 1, 2, 3  # (True, 1, 2, 3)

print(a, b, c, d, e)  # (1,) ([1],) 1 (1,) (True, 1, 2, 3)

python中,tuple存在著一些隱式轉(zhuǎn)換的問(wèn)題。觀(guān)察上面例子,如果你是個(gè)python新手你會(huì)發(fā)現(xiàn),除了d的值符合你的預(yù)期,別的結(jié)果都似乎不是你想的那樣(注釋的部分即為運(yùn)行結(jié)果)。

符合一下幾種條件的都會(huì)被隱式轉(zhuǎn)換。

1、當(dāng)一個(gè)表達(dá)式以逗號(hào)結(jié)尾的時(shí)候,那么這個(gè)表達(dá)式的結(jié)果會(huì)被轉(zhuǎn)換為tuple。如上述a,b。

2、當(dāng)一個(gè)tuple里面只有一個(gè)元素,第一個(gè)元素后面沒(méi)有使用逗號(hào)隔開(kāi)的時(shí)候,那么這個(gè)tuple就會(huì)被轉(zhuǎn)換成僅有的那個(gè)元素。如上述c和d。

3、當(dāng)一個(gè)表達(dá)式有多個(gè)值,但表達(dá)式的接受者只有一個(gè)時(shí),那么接受者會(huì)被轉(zhuǎn)成tuple類(lèi)型。如上述e。

神奇的列表

item = [[]] * 3

print(item)  # [[], [], []]

item[0].append(1)

print(item)  # [[1], [1], [1]]

在上面例子中,明明只對(duì)0號(hào)索引的list進(jìn)行了append操作,為什么最后所有索引位置的list都添加進(jìn)了值。

注意看第一個(gè)表達(dá)式 item = [[]] * 3, * 3 的操作是操作的外層的列表,而里面的list沒(méi)有發(fā)生變化。因?yàn)閘ist是可變對(duì)象,每個(gè)list里面的list其實(shí)指向的都是同一個(gè)list。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1python介紹 Python是著名的“龜叔”Guido van Rossum在1989年圣誕節(jié)期間,為了打發(fā)無(wú)...
    jbb_43b0閱讀 404評(píng)論 0 0
  • 最近在慕課網(wǎng)學(xué)習(xí)廖雪峰老師的Python進(jìn)階課程,做筆記總結(jié)一下重點(diǎn)。 基本變量及其類(lèi)型 變量 在Python中,...
    victorsungo閱讀 1,950評(píng)論 0 5
  • 一、Python中數(shù)據(jù)類(lèi)型 計(jì)算機(jī)顧名思義就是可以做數(shù)學(xué)計(jì)算的機(jī)器,因此,計(jì)算機(jī)程序理所當(dāng)然地可以處理各種數(shù)值。但...
    大嘴蝸牛閱讀 1,145評(píng)論 0 5
  • 一、python 變量和數(shù)據(jù)類(lèi)型 1.整數(shù) Python可以處理任意大小的整數(shù),當(dāng)然包括負(fù)整數(shù),在Python程序...
    績(jī)重KF閱讀 2,019評(píng)論 0 1
  • 教程總綱:http://www.runoob.com/python/python-tutorial.html 進(jìn)階...
    健康哥哥閱讀 2,191評(píng)論 1 3

友情鏈接更多精彩內(nèi)容