函數(shù)(5)--可變參數(shù)

第 18 條:用數(shù)量可變的位置參數(shù)減少視覺雜訊

先看這樣一個函數(shù):

def log(message, values):
    if not values:
        print(message)
    else:
        values_str = ''.join(str(x) for x in values)
        print('%s: %s' % (message, values_str))

log('My number are', [1, 2])
log('No number', [])
>>>
My number are: 12
No number

這個函數(shù)接受一個字符串和一個列表闽巩,用于打印丰包,只是如果列表沒有值時爆价,就像第二個傳值垦巴,仍然要去傳一個空列表媳搪。這是因為 log 函數(shù)的參數(shù)是固定的,只能按照固定的參數(shù)來傳值骤宣。

在使用的時候秦爆,當(dāng)然希望如果第二個參數(shù)是空值,最好不需要傳空列表進去憔披,函數(shù)也能正常運行等限。在 Python 中,如果把后面的位置參數(shù)加一個 * 芬膝,就可以實現(xiàn)望门。

def log(message, *values):  # 這里加了個 *
    if not values:
        print(message)
    else:
        values_str = ''.join(str(x) for x in values)
        print('%s: %s' % (message, values_str))

log('My number are', [1, 2])
log('No number')  # 這時不需要再傳入空列表
>>>
My number are: 12
No number

在使用帶有變長參數(shù)的函數(shù)時,總是先轉(zhuǎn)換成元組锰霜。所以怒允,變長參數(shù)對應(yīng)的參數(shù)個數(shù)應(yīng)該足夠少,否則就會消耗大量內(nèi)存锈遥,尤其是當(dāng)傳入的可變參數(shù)是帶有 * 號的生成器。還有一個問題就是在可變參數(shù)前添加新的參數(shù)時勘畔,函數(shù)就必須要修改所灸,否則就是發(fā)生混亂。

第 19 條:用關(guān)鍵字參數(shù)來表達(dá)可選的行為

Python 函數(shù)在傳參時炫七,可以使用關(guān)鍵字來指定參數(shù)進行傳值爬立。

def remainer(number, divisor):
    return number % divisor
assert remainer(20, 7) == 6

remainer(20, divisor=7)
remainer(number=20, divisor=7)
remainer(divisor=7, number=20)

直接傳值和指定關(guān)鍵字來傳值都是可以的。但是不能把位置參數(shù)放在關(guān)鍵字參數(shù)的前面万哪,

remainer(number=20, 7)
>>>
SyntaxError: positional argument follows keyword argument

每個參數(shù)只能指定一次侠驯,

remainer(20, number=7)
>>>
TypeError: remainer() got multiple values for argument 'number'
第 20 條:動態(tài)默認(rèn)值參數(shù)

有時候如果一個函數(shù)的參數(shù)需要動態(tài)的默認(rèn)值,那么就想當(dāng)然會在參數(shù)中指定一個默認(rèn)值奕巍,

def log(message, when=datetime.now()):
    print('%s: %s' % (message, when))

log('first time')
sleep(1)
log('second time')

>>>
first time: 2018-05-21 07:54:09.361192
second time: 2018-05-21 07:54:09.361192

可以看到吟策,運行結(jié)果和我們認(rèn)為的有出入,時間并沒有相差一秒的止,而是完全相同檩坚!

這里涉及到 Python 代碼的執(zhí)行, 在 Python 中诅福,參數(shù)的默認(rèn)值是在每個模塊加載的時候就求出的匾委,而模塊又是在程序啟動時加載的,所以也就是說參數(shù)的默認(rèn)值是在模塊加載時就已經(jīng)固定不變了氓润。

def log(message, when=None):
    when=datetime.now() if when is None else when
    print('%s: %s' % (message, when))

log('first time')
sleep(1)
log('second time')

>>>
first time: 2018-05-21 08:00:44.378427
second time: 2018-05-21 08:00:45.378766

如上赂乐, Python 中如果想要實現(xiàn)參數(shù)的動態(tài)默認(rèn)值,只能在函數(shù)中實現(xiàn)咖气“ご耄可以把 參數(shù)默認(rèn)為 None挖滤,然后在函數(shù)中根據(jù)參數(shù)的值來判斷是否為 None,再進行求值运嗜。而如果參數(shù)是可變類型壶辜,如列表,字典等担租,一定要使用 None 傳入砸民,否則使用的一直是同一個可變類型對象。

第 21 條:使用只能以關(guān)鍵字形式指定的參數(shù)確保代碼清晰

Python3 中奋救,可以定義一種只能以關(guān)鍵字形式來指定的參數(shù)岭参,這些參數(shù)必須以關(guān)鍵字來提供,而不能按位置提供尝艘。

def safe_division(number, divisor, *, ignore_overflow=False, ignore_zero_division=False):
    try:
        return number / divisor
    except OverflowError:
        if ignore_overflow:
            return 0
        else:
            raise
    except ZeroDivisionError:
        if ignore_zero_division:
            return 0
        else:
            raise 
            
safe_division(5, 3, True, False)
>>>
TypeError: safe_division() takes 2 positional arguments but 4 were given

在上面的例子中演侯,在參數(shù)列表中使用*號表示位置參數(shù)已經(jīng)結(jié)束,后續(xù)參數(shù)只能以關(guān)鍵字的方式來指定背亥。如果沒有去指定關(guān)鍵字參數(shù)的話秒际,使用位置參數(shù)就會報錯。

print(safe_division(1, 10*500, ignore_overflow=True, ignore_zero_division=False))

>>>
0.0

使用指定關(guān)鍵字參數(shù)后正常運行狡汉。

在 Python2 中娄徊,沒有這個方法,但是可以使用另一種方式來實現(xiàn)只能使用指定關(guān)鍵字參數(shù)盾戴。

def safe_division_d(number, divisor, **kwargs):
    ignore_overflow = kwargs.pop('ignore_overflow', False)
    ignore_zero_division = kwargs.pop('ignore_zero_division', False)
    if kwargs:
        raise TypeError('Unexcepted **kwargs')
    try:
        return number / divisor
    except OverflowError:
        if ignore_overflow:
            return 0
        else:
            raise
    except ZeroDivisionError:
        if ignore_zero_division:
            return 0
        else:
            raise
            
print(safe_division_d(1, 10**500000, True, False))
print(safe_division_d(1, 10**500000, ignore_overflow=True, ignore_zero_division=False))
print(safe_division_d(1, 10**500000, unexpected=True))

>>>
TypeError: safe_division_d() takes 2 positional arguments but 4 were given
0.0
TypeError: Unexcepted **kwargs

使用**kwargs 這個參數(shù)寄锐,可以很方便的判斷傳參有沒有以指定的方式,并且指定的參數(shù)是不是正確尖啡。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末橄仆,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子衅斩,更是在濱河造成了極大的恐慌盆顾,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件矛渴,死亡現(xiàn)場離奇詭異椎扬,居然都是意外死亡,警方通過查閱死者的電腦和手機具温,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進店門蚕涤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人铣猩,你說我怎么就攤上這事揖铜。” “怎么了达皿?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵天吓,是天一觀的道長贿肩。 經(jīng)常有香客問我,道長龄寞,這世上最難降的妖魔是什么汰规? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮物邑,結(jié)果婚禮上溜哮,老公的妹妹穿的比我還像新娘。我一直安慰自己色解,他們只是感情好茂嗓,可當(dāng)我...
    茶點故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著科阎,像睡著了一般述吸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上锣笨,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天蝌矛,我揣著相機與錄音,去河邊找鬼错英。 笑死朴读,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的走趋。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼噪伊,長吁一口氣:“原來是場噩夢啊……” “哼簿煌!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起鉴吹,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤姨伟,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后豆励,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體夺荒,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年良蒸,在試婚紗的時候發(fā)現(xiàn)自己被綠了技扼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡嫩痰,死狀恐怖剿吻,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情串纺,我是刑警寧澤丽旅,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布椰棘,位于F島的核電站,受9級特大地震影響榄笙,放射性物質(zhì)發(fā)生泄漏邪狞。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一茅撞、第九天 我趴在偏房一處隱蔽的房頂上張望帆卓。 院中可真熱鬧,春花似錦乡翅、人聲如沸鳞疲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽尚洽。三九已至,卻和暖如春靶累,著一層夾襖步出監(jiān)牢的瞬間腺毫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工挣柬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留潮酒,地道東北人。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓邪蛔,卻偏偏與公主長得像急黎,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子侧到,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內(nèi)容