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

詳細(xì)介紹Python函數(shù)中的默認(rèn)參數(shù)

 更新時(shí)間:2015年03月30日 11:43:16   作者:Leonardo Giordani  
這篇文章主要介紹了詳細(xì)介紹Python函數(shù)中的默認(rèn)參數(shù),包括默認(rèn)參數(shù)的傳遞和求值等內(nèi)容,需要的朋友可以參考下
import datetime as dt
 
def log_time(message, time=None):
  if time is None:
    time=dt.datetime.now()
  print("{0}: {1}".format(time.isoformat(), message))

最近我在一段Python代碼中發(fā)現(xiàn)了一個(gè)因?yàn)殄e(cuò)誤的使用默認(rèn)參數(shù)而產(chǎn)生的非常惡心的bug。如果您已經(jīng)知道關(guān)于默認(rèn)參數(shù)的全部?jī)?nèi)容了,只是想嘲笑一下我這可笑的錯(cuò)誤,請(qǐng)直接跳到本文末尾。哎,這段代碼是我寫的,但是我非常確定那天我被惡魔附體了。你懂的,有時(shí)候就是這樣。

本文僅僅是總結(jié)一下關(guān)于Python函數(shù)的標(biāo)準(zhǔn)參數(shù)和默認(rèn)參數(shù)的一些基本內(nèi)容。提醒你注意你的代碼中可能存在的陷阱。如果你剛開始接觸Python,開始寫一些函數(shù),我真心推薦你看一下Python官方手冊(cè)中關(guān)于函數(shù)的內(nèi)容,鏈接如下:Defining Functions 以及 More on Defining Functions
簡(jiǎn)單復(fù)習(xí)一下函數(shù)

Python是一個(gè)強(qiáng)大的面向?qū)ο笳Z(yǔ)言,它把這種編程范式推向了頂峰。但是,面向?qū)ο缶幊倘匀恍枰揽亢瘮?shù)這一概念,你可以用它來處理數(shù)據(jù)。Python對(duì)于可調(diào)用對(duì)象有一個(gè)更寬泛的概念,即任何對(duì)象都可以被調(diào)用,調(diào)用的意思是對(duì)其應(yīng)用數(shù)據(jù)。

函數(shù)在Python中是可調(diào)用對(duì)象,并且乍一看,它和其他語(yǔ)言中的函數(shù)有著類似的行為。它們獲取一些數(shù)據(jù),這些數(shù)據(jù)被稱為參數(shù),然后處理它們,接著返回結(jié)果(如果沒有return語(yǔ)句則是None)

參數(shù)被聲明為占位符(在定義函數(shù)的時(shí)候),用以代表那些當(dāng)函數(shù)調(diào)用時(shí)被實(shí)際傳入的對(duì)象。在Python中你不需要聲明參數(shù)的類型(例如,像你在C或Java中做的那樣)因?yàn)镻ython哲學(xué)依賴于多態(tài)。

記住,Python的變量是引用,即實(shí)際變量的內(nèi)存地址。這意味著Python的函數(shù)永遠(yuǎn)以“傳址”的方式工作(這里使用了一個(gè)C/C++術(shù)語(yǔ)),當(dāng)你調(diào)用一個(gè)函數(shù)的時(shí)候,并不是復(fù)制了一份參數(shù)的值來替換占位符,而是把占位符指向了變量本身。這導(dǎo)致了一個(gè)非常重要的結(jié)果:你可以在函數(shù)內(nèi)部改變這個(gè)變量的值。這里有一個(gè)很好可視化講解,關(guān)于引用機(jī)制。

引用在Python扮演著非常重要的角色,它是Python完全多態(tài)方式的骨干。關(guān)于這個(gè)非常重要的主題,請(qǐng)點(diǎn)擊這個(gè)鏈接 查看更好的解釋。

為了檢查你是否理解了這門語(yǔ)言的這一基本特性,請(qǐng)跟隨這段簡(jiǎn)單的代碼(變量ph代表的是“占位符(placeholder)”)
 

>>> def print_id(ph):
... print(hex(id(ph)))
...
>>> a = 5
>>> print(hex(id(a)))
0x84ab460
>>> print_id(a)
0x84ab460
>>>
>>> def alter_value(ph):
... ph = ph + 1
... return ph
...
>>> b = alter_value(a)
>>> b
6
>>> a
5
>>> hex(id(a))
'0x84ab460'
>>> hex(id(b))
'0x84ab470'
>>>
>>> def alter_value(ph):
... ph.append(1)
... return ph
...
>>> a = [1,2,3]
>>> b = alter_value(a)
>>> a
[1, 2, 3, 1]
>>> b
[1, 2, 3, 1]
>>> hex(id(a))
'0xb701f72c'
>>> hex(id(b))
'0xb701f72c'
>>>

如果你對(duì)這里發(fā)生的事情并不感到吃驚,那說明你已經(jīng)掌握了Python中最為重要的部分之一,你可以放心的跳過下面的解釋了。

print_id()函數(shù)顯示,函數(shù)內(nèi)部的占位符同運(yùn)行時(shí)傳入的變量完全一樣(它們的內(nèi)存地址一致)。

兩個(gè)版本的alter_value()意在改變傳入?yún)?shù)的值。正如你所看到的,第一個(gè)alter_value() 并沒有像第二個(gè)alter_value()一樣成功的改變變量a的值。這是為什么呢?實(shí)際上兩者的行為是一樣的,都是嘗試修改傳入的原始變量的值,但是在Python中,有些變量是不可變的(immutable),整數(shù)就在此列。另一方面,列表并不是不可變的,所以函數(shù)得以完成它的名字所保證的工作。 在這里,你可以找到關(guān)于不可變類型的更加詳細(xì)的介紹 。

關(guān)于Python中的函數(shù),還有一些要說的,但是這些是關(guān)于標(biāo)準(zhǔn)的參數(shù)的基本知識(shí)。
默認(rèn)參數(shù)值

有時(shí)候你需要定義一個(gè)函數(shù),讓它接受一個(gè)參數(shù),而且在這個(gè)參數(shù)出現(xiàn)或不出現(xiàn)時(shí),函數(shù)有不同的行為。如果一門語(yǔ)言不支持這種情況,你就只有兩個(gè)選擇:第一種是定義兩個(gè)不同的函數(shù),決定每次調(diào)用應(yīng)該選擇調(diào)用哪個(gè),第二種是 兩種方法都是可行的,但是都不是最佳的。

Python和其他語(yǔ)言一樣,支持默認(rèn)參數(shù)值,即函數(shù)參數(shù)可以是調(diào)用時(shí)指定的,也可以留空,自動(dòng)接受一個(gè)預(yù)定義的值。

一個(gè)關(guān)于默認(rèn)值的非常簡(jiǎn)單(也很沒用)的例子如下:
 

def log(message=None):
  if message:
    print("LOG: {0}".format(message))

這個(gè)函數(shù)可以帶一個(gè)參數(shù)運(yùn)行(可以是None)

 
>>> log("File closed")
LOG: File closed
>>> log(None)
>>>

但是同樣也可以不帶參數(shù)運(yùn)行,這種情況下它會(huì)接受一個(gè)函數(shù)原型中設(shè)置的默認(rèn)值(本例中是None)
 

>>> log()
>>>

你可以在標(biāo)準(zhǔn)庫(kù)中找到更多有趣的例子,比如在open()函數(shù)中(請(qǐng)查看官方文檔
 

open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)

函數(shù)原型可以證明,例如 f = open('/etc/hosts')這樣的調(diào)用,通過傳入默認(rèn)值隱藏了很多參數(shù) (mode, buffering, encoding, 等),并且使這個(gè)函數(shù)的典型應(yīng)用案例變得非常簡(jiǎn)單易用。

正如你在內(nèi)建的open()函數(shù)中看到的那樣,我們可以在函數(shù)中使用標(biāo)準(zhǔn)或者默認(rèn)參數(shù),但是兩者在函數(shù)中出現(xiàn)的次序是固定的:首先調(diào)用標(biāo)準(zhǔn)參數(shù),然后調(diào)用默認(rèn)參數(shù)。
 

def a_rich_function(a, b, c, d=None, e=0):
  pass

原因是顯而易見的:如果我們可以在標(biāo)準(zhǔn)參數(shù)前面放置一個(gè)默認(rèn)參數(shù),語(yǔ)言就無(wú)法理解,默認(rèn)參數(shù)是否已經(jīng)被初始化。例如,考慮下面這個(gè)函數(shù)定義
 

def a_rich_function(a, b, d=None, c, e=0):
  pass

當(dāng)調(diào)用函數(shù)a_rich_function(1, 2, 4, 5)時(shí),我們傳入了什么參數(shù)? 是d=4, c=5 還是c=4, e=5?因?yàn)閐有一個(gè)默認(rèn)的值。因此這種順序的定義是被禁止的,如果你這樣做,Python會(huì)拋出一個(gè)SyntaxError
 

>>> def a_rich_function(a, b, d=None, c, e=0):
... pass
...
 File "<stdin>", line 1
SyntaxError: non-default argument follows default argument
>>>

默認(rèn)參數(shù)求值

默認(rèn)參數(shù)可以通過普通值或是函數(shù)調(diào)用結(jié)果來提高,但是后者這種技術(shù)需要一個(gè)特別的警示

一個(gè)普通的值是硬編碼的,因此除了編譯時(shí),其他時(shí)候是不需要求值的,但是函數(shù)調(diào)用期望在運(yùn)行時(shí)執(zhí)行求值。所以我們可以這樣寫
 

import datetime as dt
 
def log_time(message, time=dt.datetime.now()):
  print("{0}: {1}".format(time.isoformat(), message))

每次我們調(diào)用log_time()時(shí)都期望它能夠正確提供當(dāng)前時(shí)間。悲劇的是并沒有成功:默認(rèn)參數(shù)在定義時(shí)求值(比如說當(dāng)你首次導(dǎo)入模塊時(shí)),調(diào)用的結(jié)果如下
 

>>> log_time("message 1")
2015-02-10T21:20:32.998647: message 1
>>> log_time("message 2")
2015-02-10T21:20:32.998647: message 2
>>> log_time("message 3")
2015-02-10T21:20:32.998647: message 3

如果把默認(rèn)值賦給一個(gè)類的實(shí)例,結(jié)果會(huì)更加奇怪,你可以在中讀到相關(guān)內(nèi)容。根據(jù)。。通常的解決方法是把默認(rèn)參數(shù)替換為None,并且在函數(shù)內(nèi)部檢查參數(shù)值。
 
結(jié)論

默認(rèn)參數(shù)能夠極大的簡(jiǎn)化API,你需要關(guān)注它唯一的“失敗點(diǎn)”,即求值的時(shí)機(jī)。令人驚奇的是,Python最基本的內(nèi)容之一,函數(shù)的參數(shù)和引用,是最大的錯(cuò)誤源之一,有時(shí)候?qū)τ谟薪?jīng)驗(yàn)的程序員也一樣。我建議抽時(shí)間學(xué)習(xí)一下引用和多態(tài)。
相關(guān)閱讀:

  •     OOP concepts in Python 2.x – Part 2
  •     Python 3 OOP Part 1 – Objects and types
  •     Digging up Django class-based views – 2
  •     Python Generators – From Iterators to Cooperative Multitasking – 2
  •     OOP concepts in Python 2.x – Part 1

相關(guān)文章

  • Python range、enumerate和zip函數(shù)用法詳解

    Python range、enumerate和zip函數(shù)用法詳解

    這篇文章主要介紹了Python range、enumerate和zip函數(shù)用法詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • 使用keras實(shí)現(xiàn)BiLSTM+CNN+CRF文字標(biāo)記NER

    使用keras實(shí)現(xiàn)BiLSTM+CNN+CRF文字標(biāo)記NER

    這篇文章主要介紹了使用keras實(shí)現(xiàn)BiLSTM+CNN+CRF文字標(biāo)記NER,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-06-06
  • 深入理解Python中命名空間的查找規(guī)則LEGB

    深入理解Python中命名空間的查找規(guī)則LEGB

    這篇文章主要介紹了深入理解Python中命名空間的查找規(guī)則LEGB,作者根據(jù)Python3.x版本進(jìn)行講解,需要的朋友可以參考下
    2015-08-08
  • Python Numpy 高效的運(yùn)算工具詳解

    Python Numpy 高效的運(yùn)算工具詳解

    這篇文章主要介紹了Python numpy矩陣處理運(yùn)算工具用法匯總,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2021-10-10
  • 詳解python字符串相關(guān)str

    詳解python字符串相關(guān)str

    這篇文章主要為大家介紹了python字符串相關(guān)str,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-01-01
  • pytorch中使用LSTM詳解

    pytorch中使用LSTM詳解

    這篇文章主要介紹了pytorch中使用LSTM,可以在troch.nn模塊中找到LSTM類,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下
    2022-07-07
  • 通過Python收集匯聚MySQL 表信息的實(shí)例詳解

    通過Python收集匯聚MySQL 表信息的實(shí)例詳解

    這篇文章主要介紹了通過Python收集匯聚MySQL 表信息的實(shí)例代碼,核心代碼是創(chuàng)建保存數(shù)據(jù)的腳本,收集的功能腳本,代碼簡(jiǎn)單明了,需要的朋友可以參考下
    2021-10-10
  • Django model 中設(shè)置聯(lián)合約束和聯(lián)合索引的方法

    Django model 中設(shè)置聯(lián)合約束和聯(lián)合索引的方法

    今天小編就為大家分享一篇Django model 中設(shè)置聯(lián)合約束和聯(lián)合索引的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2019-08-08
  • Python模擬脈沖星偽信號(hào)頻率實(shí)例代碼

    Python模擬脈沖星偽信號(hào)頻率實(shí)例代碼

    這篇文章主要介紹了Python模擬脈沖星偽信號(hào)頻率實(shí)例代碼,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-01-01
  • pandas中按行或列的值對(duì)數(shù)據(jù)排序的實(shí)現(xiàn)

    pandas中按行或列的值對(duì)數(shù)據(jù)排序的實(shí)現(xiàn)

    本文主要介紹了pandas中按行或列的值對(duì)數(shù)據(jù)排序的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02

最新評(píng)論

井研县| 天祝| 张家口市| 阳春市| 陆河县| 贡山| 正镶白旗| 宜川县| 四会市| 彝良县| 舒兰市| 夹江县| 富源县| 晋江市| 凤冈县| 南江县| 岑溪市| 西乌| 黄龙县| 海晏县| 四子王旗| 忻州市| 石台县| 邯郸县| 象山县| 枣庄市| 遂昌县| 乐至县| 永嘉县| 乌海市| 江达县| 靖西县| 弥勒县| 苍山县| 奉贤区| 西城区| 吉木萨尔县| 盈江县| 吉木乃县| 赤壁市| 舒城县|