亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Python函數(shù)的默認(rèn)參數(shù)設(shè)計(jì)示例詳解

 更新時(shí)間:2019年12月01日 08:18:04   作者:Mr-chen  
這篇文章主要給大家介紹了關(guān)于Python函數(shù)的默認(rèn)參數(shù)設(shè)計(jì)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Python具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

在Python教程里,針對(duì)默認(rèn)參數(shù),給了一個(gè)“重要警告”的例子:

def f(a, L=[]):
  L.append(a)
  return L

print(f(1))
print(f(2))
print(f(3))

默認(rèn)值只會(huì)執(zhí)行一次,也沒(méi)說(shuō)原因。會(huì)打印出結(jié)果:

[1]
[1, 2]
[1, 2, 3]

因?yàn)閷W(xué)的第一門語(yǔ)言是Ruby,所以感覺(jué)有些奇怪。 但肯定的是方法f一定儲(chǔ)存了變量L。

準(zhǔn)備知識(shí):指針

p指向不可變對(duì)象,比如數(shù)字。則相當(dāng)于p指針指向了不同的內(nèi)存地址。

p指向的是可變對(duì)象,比如list。list自身的改變,并不會(huì)改變list對(duì)象自身所在的內(nèi)存地址。所以p指向的內(nèi)存地址不變。

>>> p = 1
>>> id(p)
>>> p = p + 1
>>> id(p)
>>> p = 11
>>> id(p)

>>> p = []
>>> id(p)
>>> p.append(11)
>>> id(p)

根本原因

Python函數(shù)的參數(shù)默認(rèn)值,是在編譯階段就綁定了。(寫(xiě)代碼時(shí)就定義了。)

下面是一段從Python Common Gotchas中摘錄的原因解釋:

Python's default arguments are evaluated once when the function is defined, not each time the function is called (like it is in say, Ruby). This means that if you use a mutable default argument and mutate it, you will and have mutated that object for all future calls to the function as well.

由此可知:

  1. 在運(yùn)行代碼時(shí),運(yùn)行到函數(shù)定義時(shí),默認(rèn)參數(shù)的表達(dá)式就被執(zhí)行了。
  2. 函數(shù)調(diào)用時(shí),不會(huì)再次運(yùn)行默認(rèn)參數(shù)的表達(dá)式。⚠️ 這點(diǎn)和Ruby完全不同。
  3. 由此可知,如果默認(rèn)參數(shù),指向一個(gè)不變對(duì)象,例如L = 1。那么在函數(shù)調(diào)用時(shí),在函數(shù)體內(nèi)對(duì)L重新賦值,L其實(shí)是一個(gè)新的指針, 指向的是一個(gè)新的內(nèi)存地址。而原來(lái)默認(rèn)參數(shù)L本身及指向的內(nèi)存地址,已經(jīng)儲(chǔ)存在最開(kāi)始編譯時(shí)的函數(shù)定義中??梢杂胈_default__查看。
  4. 如果默認(rèn)參數(shù)指向的是一個(gè)可變對(duì)象,如list, 那么L.append(a)是對(duì)可變對(duì)象自身的修改,L指向的內(nèi)存地址不變。所以每次調(diào)用函數(shù),默認(rèn)參數(shù)取出的都是這個(gè)內(nèi)存地址的對(duì)象。

第三條,修改上面的例子:

def f(a, L = 1):
  L = a
  print(id(L))
  return L

print("self",id(f.__defaults__[0]))
print(f(1))
print("self",id(f.__defaults__[0]))
print(f(33))
print("self",id(f.__defaults__[0]))

#運(yùn)行結(jié)果:
self 4353170064
1
self 4353170064
33
self 4353170064

默認(rèn)參數(shù)L,在編譯階段就綁定了,儲(chǔ)存在__default__內(nèi)。函數(shù)體內(nèi)的L = a表達(dá)式,生成的是新的變量。返回的L是新的變量,和默認(rèn)參數(shù)無(wú)關(guān)。

第四條,還是上面的例子, 改一下默認(rèn)參數(shù)的類型為可變對(duì)象list:

def f(a, L = []):
  L.append(a)
  print(id(L))
  return L
# L = f(1)
print("self",id(f.__defaults__[0]))
print(f(1))
print("self",id(f.__defaults__[0]))
print(f(33))
print("self",id(f.__defaults__[0]))
#返回結(jié)果
self 4337586048
[1]
self 4337586048
[1, 33]
self 4337586048

由id號(hào)可知,返回的是默認(rèn)參數(shù)自身。

如何避免這個(gè)陷阱帶來(lái)不必要麻煩

def f(a, L = None):
  if L is None:
    L = []
  L.append(a)
  return L

為什么Python要這么設(shè)計(jì)

 StackOverflow 上爭(zhēng)論很多。

Ruby之所以沒(méi)有這個(gè)問(wèn)題,我想是因?yàn)镽uby的def關(guān)鍵字定義了一個(gè)封閉作用域,任何數(shù)據(jù)都必須通過(guò)參數(shù)傳入到方法內(nèi),才能用。

和Ruby比,Python參數(shù)的作用被大大消弱了。Python的出現(xiàn)晚于Ruby,其創(chuàng)始人肯定參考了Ruby的設(shè)計(jì)。拋棄了這個(gè)設(shè)計(jì),選擇了類似javascript的函數(shù)方式。def定義的函數(shù),執(zhí)行時(shí)是可以接收外部作用域的變量的。

有觀點(diǎn)認(rèn)為:

出于Python編譯器的實(shí)現(xiàn)方式考慮,函數(shù)是一個(gè)內(nèi)部一級(jí)對(duì)象。而參數(shù)默認(rèn)值是這個(gè)對(duì)象的屬性。在其他任何語(yǔ)言中,對(duì)象屬性都是在對(duì)象創(chuàng)建時(shí)做綁定的。因此,函數(shù)參數(shù)默認(rèn)值在編譯時(shí)綁定也就不足為奇了。

本文參考了:http://cenalulu.github.io/python/default-mutable-arguments/#toc1 ,并加入了自己的理解。

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • PyQt實(shí)現(xiàn)異步數(shù)據(jù)庫(kù)請(qǐng)求的實(shí)戰(zhàn)記錄

    PyQt實(shí)現(xiàn)異步數(shù)據(jù)庫(kù)請(qǐng)求的實(shí)戰(zhàn)記錄

    開(kāi)發(fā)軟件的時(shí)候不可避免要和數(shù)據(jù)庫(kù)發(fā)生交互,但是有些 SQL 請(qǐng)求非常耗時(shí),如果在主線程中發(fā)送請(qǐng)求,可能會(huì)造成界面卡頓,本文將介紹一種讓數(shù)據(jù)庫(kù)請(qǐng)求變得和前端的 ajax 請(qǐng)求一樣簡(jiǎn)單,希望對(duì)大家有所幫助
    2023-12-12
  • 在Python中使用AOP實(shí)現(xiàn)Redis緩存示例

    在Python中使用AOP實(shí)現(xiàn)Redis緩存示例

    本篇文章主要介紹了在Python中使用AOP實(shí)現(xiàn)Redis緩存示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-07-07
  • Python Selenium實(shí)現(xiàn)無(wú)可視化界面過(guò)程解析

    Python Selenium實(shí)現(xiàn)無(wú)可視化界面過(guò)程解析

    這篇文章主要介紹了Python Selenium實(shí)現(xiàn)無(wú)可視化界面過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • 關(guān)于Python中compile() 函數(shù)簡(jiǎn)單實(shí)用示例詳解

    關(guān)于Python中compile() 函數(shù)簡(jiǎn)單實(shí)用示例詳解

    這篇文章主要介紹了關(guān)于compile() 函數(shù)簡(jiǎn)單實(shí)用示例,compile() 函數(shù)將一個(gè)字符串編譯為字節(jié)代碼,compile將代碼編譯為代碼對(duì)象,應(yīng)用在代碼中可以提高效率,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-05-05
  • 如何使用Django默認(rèn)的Auth權(quán)限管理系統(tǒng)

    如何使用Django默認(rèn)的Auth權(quán)限管理系統(tǒng)

    本文主要介紹了如何使用Django默認(rèn)的Auth權(quán)限管理系統(tǒng),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • 解讀Python編程中的命名空間與作用域

    解讀Python編程中的命名空間與作用域

    這篇文章主要介紹了Python編程中的命名空間與作用域,是Python入門學(xué)習(xí)中的重要知識(shí),需要的朋友可以參考下
    2015-10-10
  • PyQt5利用QPainter繪制各種圖形的實(shí)例

    PyQt5利用QPainter繪制各種圖形的實(shí)例

    下面小編就為大家?guī)?lái)一篇PyQt5利用QPainter繪制各種圖形的實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-10-10
  • Opencv中cv2.cvtColor彩色圖轉(zhuǎn)灰度圖的其他6種方法

    Opencv中cv2.cvtColor彩色圖轉(zhuǎn)灰度圖的其他6種方法

    本文主要介紹了Opencv中cv2.cvtColor彩色圖轉(zhuǎn)灰度圖的其他6種方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • python基礎(chǔ)之文件的備份以及定位

    python基礎(chǔ)之文件的備份以及定位

    這篇文章主要介紹了python文件的備份以及定位,實(shí)例分析了Python中返回一個(gè)返回值與多個(gè)返回值的方法,需要的朋友可以參考下
    2021-10-10
  • Pyhton中防止SQL注入的方法

    Pyhton中防止SQL注入的方法

    這篇文章主要介紹了Pyhton中防止SQL注入的方法,本文講解的方法簡(jiǎn)單實(shí)用,需要的朋友可以參考下
    2015-02-02

最新評(píng)論