最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python中的默認(rèn)參數(shù)詳解

 更新時間:2015年06月24日 12:16:32   投稿:junjie  
這篇文章主要介紹了Python中的默認(rèn)參數(shù)詳解,本文講解了默認(rèn)參數(shù)的基本原理、如何正確地使用可變參數(shù)等內(nèi)容,需要的朋友可以參考下

文章的主題

不要使用可變對象作為函數(shù)的默認(rèn)參數(shù)例如 list,dict,因為def是一個可執(zhí)行語句,只有def執(zhí)行的時候才會計算默認(rèn)默認(rèn)參數(shù)的值,所以使用默認(rèn)參數(shù)會造成函數(shù)執(zhí)行的時候一直在使用同一個對象,引起bug。

基本原理

在 Python 源碼中,我們使用def來定義函數(shù)或者方法。在其他語言中,類似的東西往往只是一一個語法聲明關(guān)鍵字,但def卻是一個可執(zhí)行的指令。Python代碼執(zhí)行的時候先會使用 compile 將其編譯成 PyCodeObject.

PyCodeObject 本質(zhì)上依然是一種靜態(tài)源代碼,只不過以字節(jié)碼方式存儲,因為它面向虛擬機(jī)。因此 Code 關(guān)注的是如何執(zhí)行這些字節(jié)碼,比如??臻g大小,各種常量變量符號列表,以及字節(jié)碼與源碼行號的對應(yīng)關(guān)系等等。

PyFunctionObject 是運行期產(chǎn)生的。它提供一個動態(tài)環(huán)境,讓 PyCodeObject 與運行環(huán)境關(guān)聯(lián)起來。同時為函數(shù)調(diào)用提供一系列的上下文屬性,諸如所在模塊、全局名字空間、參數(shù)默認(rèn)值等等。這是def語句執(zhí)行的時候干的活。

PyFunctionObject 讓函數(shù)面向邏輯,而不僅僅是虛擬機(jī)。PyFunctionObject 和 PyCodeObject 組合起來才是一個完整的函數(shù)。

下文翻譯了一篇文章,有一些很好的例子。但是由于水平有限,有些不會翻譯或者有些翻譯有誤,敬請諒解。如果有任何問題請發(fā)郵件到 acmerfight圈gmail.com,感激不盡

主要參考資料 書籍:《深入Python編程》 大牛:shell 和 Topsky

Python對于函數(shù)中默認(rèn)參數(shù)的處理往往會給新手造成困擾(但是通常只有一次)。

當(dāng)你使用“可變”的對象作為函數(shù)中作為默認(rèn)參數(shù)時會往往引起問題。因為在這種情況下參數(shù)可以在不創(chuàng)建新對象的情況下進(jìn)行修改,例如 list dict。

復(fù)制代碼 代碼如下:

>>> def function(data=[]):
...     data.append(1)
...     return data
...
>>> function()
[1]
>>> function()
[1, 1]
>>> function()
[1, 1, 1]

像你所看到的那樣,list變得越來越長。如果你仔細(xì)地查看這個list。你會發(fā)現(xiàn)list一直是同一個對象。
復(fù)制代碼 代碼如下:

>>> id(function())
12516768
>>> id(function())
12516768
>>> id(function())
12516768

原因很簡單: 在每次函數(shù)調(diào)用的時候,函數(shù)一直再使用同一個list對象。這么使用引起的變化,非?!皊ticky”。

為什么會發(fā)生這種情況?

當(dāng)且僅當(dāng)默認(rèn)參數(shù)所在的“def”語句執(zhí)行的時候,默認(rèn)參數(shù)才會進(jìn)行計算。請看文檔描述

https://docs.python.org/2/reference/compound_stmts.html#function-definitions
其中有下面一段

"Default parameter values are evaluated when the function definition is executed. This means that the expression is evaluated once, when the function is defined, and that the same “pre-computed” value is used for each call. This is especially important to understand when a default parameter is a mutable object, such as a list or a dictionary: if the function modifies the object (e.g. by appending an item to a list), the default value is in effect modified. This is generally not what was intended. A way around this is to use None as the default, and explicitly test for it in the body of the function,e.g.:

復(fù)制代碼 代碼如下:

def whats_on_the_telly(penguin=None):
    if penguin is None:
        penguin = []
    penguin.append("property of the zoo")
    return penguin
"

"def"是Python中的可執(zhí)行語句,默認(rèn)參數(shù)在"def"的語句環(huán)境里被計算。如果你執(zhí)行了"def"語句多次,每次它都將會創(chuàng)建一個新的函數(shù)對象。接下來我們將看到例子。

用什么來代替?

像其他人所提到的那樣,用一個占位符來替代可以修改的默認(rèn)值。None

復(fù)制代碼 代碼如下:

def myfunc(value=None):
    if value is None:
        value = []
    # modify value here

如果你想要處理任意類型的對象,可以使用sentinel
復(fù)制代碼 代碼如下:

sentinel = object()

def myfunc(value=sentinel):
    if value is sentinel:
        value = expression
    # use/modify value here


在比較老的代碼中,written before “object” was introduced,你有時會看到
復(fù)制代碼 代碼如下:

sentinel = ['placeholder']

譯者注:太水,真的不知道怎么翻譯了。我說下我的理解 有時邏輯上可能需要傳遞一個None,而你的默認(rèn)值可能又不是None,而且還剛好是個列表,列表不
可以寫在默認(rèn)值位置,所以你需要占位符,但是用None,你又不知道是不是調(diào)用者傳遞過來的那個

正確地使用可變參數(shù)

最后需要注意的是一些高深的Python代碼經(jīng)常會利用這個機(jī)制的優(yōu)勢;舉個例子,如果在一個循環(huán)里創(chuàng)建一些UI上的按鈕,你可能會嘗試這樣去做:

復(fù)制代碼 代碼如下:

for i in range(10):
    def callback():
        print "clicked button", i
    UI.Button("button %s" % i, callback)

但是你卻發(fā)現(xiàn)callback打印出相同的數(shù)字(在這個情況下很可能是9)。原因是Python的嵌套作用域只是綁定變量,而不是綁定數(shù)值的,所以callback只看到了變量i綁定的最后一個數(shù)值。為了避免這種情況,使用顯示綁定。
復(fù)制代碼 代碼如下:

for i in range(10):
    def callback(i=i):
        print "clicked button", i
    UI.Button("button %s" % i, callback)

i=i把callback的參數(shù)i(一個局部變量)綁定到了當(dāng)前外部的i變量的數(shù)值上。(譯者注:如果不理解這個例子,請看http://stackoverflow.com/questions/233673/lexical-closures-in-python)

另外的兩個用途local caches/memoization

復(fù)制代碼 代碼如下:

def calculate(a, b, c, memo={}):
    try:
        value = memo[a, b, c] # return already calculated value
    except KeyError:
        value = heavy_calculation(a, b, c)
        memo[a, b, c] = value # update the memo dictionary
    return value

(對一些遞歸算法非常好用)

對高度優(yōu)化的代碼而言, 會使用局部變量綁全局的變量:

復(fù)制代碼 代碼如下:

import math

def this_one_must_be_fast(x, sin=math.sin, cos=math.cos):
    ...


這是如何工作的?

當(dāng)Python執(zhí)行一條def語句時, 它會使用已經(jīng)準(zhǔn)備好的東西(包括函數(shù)的代碼對象和函數(shù)的上下文屬性),創(chuàng)建了一個新的函數(shù)對象。同時,計算了函數(shù)的默認(rèn)參數(shù)值。

不同的組件像函數(shù)對象的屬性一樣可以使用。上文用到的'function'

復(fù)制代碼 代碼如下:

>>> function.func_name
'function'
>>> function.func_code
<code object function at 00BEC770, file "<stdin>", line 1>
>>> function.func_defaults
([1, 1, 1],)
>>> function.func_globals
{'function': <function function at 0x00BF1C30>,
'__builtins__': <module '__builtin__' (built-in)>,
'__name__': '__main__', '__doc__': None}

這樣你可以訪問默認(rèn)參數(shù),你甚至可以修改它。

復(fù)制代碼 代碼如下:

>>> function.func_defaults[0][:] = []
>>> function()
[1]
>>> function.func_defaults
([1],)

然而我不推薦你平時這么使用。

另一個重置默認(rèn)參數(shù)的方法是重新執(zhí)行相同的def語句,Python將會和代碼對象創(chuàng)建一個新的函數(shù)對象,并計算默認(rèn)參數(shù),并且把新創(chuàng)建的函數(shù)對象賦值給了和上次相同的變量。但是再次強(qiáng)調(diào),只有你清晰地知道在做什么的情況下你才能這么做。

And yes, if you happen to have the pieces but not the function, you can use the function class in the new module to create your own function object.

相關(guān)文章

  • 10種檢測Python程序運行時間、CPU和內(nèi)存占用的方法

    10種檢測Python程序運行時間、CPU和內(nèi)存占用的方法

    這篇文章主要介紹了10種檢測Python程序運行時間、CPU和內(nèi)存占用的方法,包括利用Python裝飾器或是外部的Unix Shell命令等,需要的朋友可以參考下
    2015-04-04
  • Python使用pdfplumber庫高效解析PDF文件

    Python使用pdfplumber庫高效解析PDF文件

    PDF 文件是日常辦公和數(shù)據(jù)處理中常見的文件格式,而 pdfplumber 是一個專為 PDF 文件解析設(shè)計的 Python 庫,可以輕松提取文本、表格、圖像等內(nèi)容,本文將介紹 pdfplumber 的基本功能、使用方法,以及在實際場景中的應(yīng)用,需要的朋友可以參考下
    2024-11-11
  • python列表的常用操作方法小結(jié)

    python列表的常用操作方法小結(jié)

    這篇文章主要為大家詳細(xì)介紹了python字典的常用操作方法,主要內(nèi)容包含Python中列表(List)的詳解操作方法,包含創(chuàng)建、訪問、更新、刪除、其它操作等,需要的朋友可以參考下
    2016-05-05
  • Pearson相關(guān)系數(shù)和Spearman相關(guān)系數(shù)的區(qū)別及說明

    Pearson相關(guān)系數(shù)和Spearman相關(guān)系數(shù)的區(qū)別及說明

    這篇文章主要介紹了Pearson相關(guān)系數(shù)和Spearman相關(guān)系數(shù)的區(qū)別及說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • Python基礎(chǔ)之變量基本用法與進(jìn)階詳解

    Python基礎(chǔ)之變量基本用法與進(jìn)階詳解

    這篇文章主要介紹了Python基礎(chǔ)之變量基本用法與進(jìn)階,結(jié)合實例形式詳細(xì)分析了Python變量引用、可變和不可變類型、局部變量和全局變量等相關(guān)原理與使用技巧,需要的朋友可以參考下
    2020-01-01
  • 對Python中class和instance以及self的用法詳解

    對Python中class和instance以及self的用法詳解

    今天小編就為大家分享一篇對Python中class和instance以及self的用法詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-06-06
  • python中字符串?dāng)?shù)組逆序排列方法總結(jié)

    python中字符串?dāng)?shù)組逆序排列方法總結(jié)

    在本篇文章里小編給大家整理了關(guān)于python中字符串?dāng)?shù)組如何逆序排列的相關(guān)知識點,需要的朋友們學(xué)習(xí)下。
    2019-06-06
  • Python實現(xiàn)將Unicode轉(zhuǎn)換為ASCII

    Python實現(xiàn)將Unicode轉(zhuǎn)換為ASCII

    這篇文章主要為大家詳細(xì)介紹了系統(tǒng)編碼的不同方法以及如何利用Python實現(xiàn)將Unicode轉(zhuǎn)換為?ASCII,文中的示例代碼講解詳細(xì),有需要的小伙伴可以學(xué)習(xí)一下
    2023-10-10
  • Python遍歷字典方式就實例詳解

    Python遍歷字典方式就實例詳解

    這篇文章主要介紹了Python遍歷字典方式就實例詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-12-12
  • 詳解python使用canvas實現(xiàn)移動并綁定鍵盤

    詳解python使用canvas實現(xiàn)移動并綁定鍵盤

    這篇文章主要為大家介紹了python使用canvas實現(xiàn)移動并綁定鍵盤,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2021-12-12

最新評論

新安县| 丁青县| 香港| 北票市| 清流县| 瑞昌市| 福建省| 松原市| 松原市| 志丹县| 石景山区| 龙口市| 淳化县| 安新县| 剑河县| 嘉荫县| 湄潭县| 六盘水市| 左云县| 武义县| 三台县| 称多县| 莱阳市| 屏东市| 盐池县| 错那县| 栾城县| 鄂伦春自治旗| 三原县| 新平| 清水县| 舞钢市| 阿拉善盟| 金华市| 车致| 石楼县| 前郭尔| 察哈| 盐津县| 汝州市| 黔南|