Python Tricks - Effective Functions(3)

Fun With *args and **kwargs

I once pair-programmed with a smart Pythonista who would exclaim “argh!” and “kwargh!” every time he typed out a function definition with optional or keyword parameters. We got along great otherwise. I guess that’s what programming in academia does to people eventually.

Now, while easily mocked, *args and **kwargs parameters are nevertheless a highly useful feature in Python. And understanding their potency will make you a more effective developer.

單星和雙星雖然被大家嘲笑,但是是python里面很有用的語言特性。理解它們的效力會使工作更有效率鹃祖。

So what are *args and **kwargs parameters used for? They allow a function to accept optional arguments, so you can create flexible APIs in your modules and classes:

def foo(required, *args, **kwargs):
  print(required)
  if args:
    print(args)
  if kwargs:
    print(kwargs)

單星和雙星語法可以使得函數(shù)可以接受更加可選的參數(shù),所以我們可以在類或者魔魁阿忠創(chuàng)造更加靈活地API响驴。

The above function requires at least one argument called “required,” but it can accept extra positional and keyword arguments as well.

上面的函數(shù)至少要接受一個叫required的參數(shù),但是它也可以接受其他的位置參數(shù)或者關(guān)鍵字參數(shù)。

If we call the function with additional arguments, args will collect extra positional arguments as a tuple because the parameter name has a * prefix.

如果我們用更多的參數(shù)來調(diào)用這個函數(shù),函數(shù)可以以元組的形式采集其余的位置參數(shù)苔悦,因為參數(shù)名前面有單星前綴。

Likewise, kwargs will collect extra keyword arguments as a dictionary because the parameter name has a ** prefix.

相似得映砖,因為有雙星號前綴存在间坐,函數(shù)會以字典的形式手機其他的關(guān)鍵字參數(shù)。

Both args and kwargs can be empty if no extra arguments are passed to the function.

如果沒有其他的值傳入邑退,args和kwargs可以為空。

As we call the function with various combinations of arguments, you’ll see how Python collects them inside the args and kwargs parameters according to whether they’re positional or keyword arguments:

>>> foo()
TypeError:
"foo() missing 1 required positional arg: 'required'"

>>> foo('hello')
hello

>>> foo('hello', 1, 2, 3)
hello
(1, 2, 3)

>>> foo('hello', 1, 2, 3, key1='value', key2=999)
hello
(1, 2, 3)
{'key1': 'value', 'key2': 999}

python會根據(jù)是否是關(guān)鍵字參數(shù)還是位置參數(shù)來進行收集劳澄。

I want to make it clear that calling the parameters args and kwargs is simply a naming convention. The previous example would work just as well if you called them parms and argv. The actual syntax is just the asterisk () or double asterisk (), respectively.

這種語法表達里面最重要的是雙星號和單星號地技,而不是星號之后的命名。

However, I recommend that you stick with the accepted naming convention to avoid confusion. (And to get a chance to yell “argh!” and “kwargh!” every once in a while.)

作者還是在這里推薦我們按照慣例走秒拔。

Forwarding Optional or Keyword Arguments

It’s possible to pass optional or keyword parameters from one function to another. You can do so by using the argument-unpacking operators * and ** when calling the function you want to forward arguments to.

This also gives you an opportunity to modify the arguments before you pass them along. Here’s an example:

def foo(x, *args, **kwargs):
  kwargs['name'] = 'Alice'
  new_args = args + ('extra', )
  bar(x, *new_args, **kwargs)

我們擁有著在傳遞雙星和單星參數(shù)之前對參數(shù)進行修改的機會莫矗。

This technique can be useful for subclassing and writing wrapper functions. For example, you can use it to extend the behavior of a parent class without having to replicate the full signature of its constructor in the child class. This can be quite convenient if you’re working with an API that might change outside of your control:

class Car:
  def __init__(self, color, mileage):
    self.color = color
    self.mileage = mileage

class AlwaysBlueCar(Car):
  def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.color = 'blue'

>>> AlwaysBlueCar('green', 48392).color
'blue'

利用這個性能我們就可以向上面那個例子中的一樣,我們不用太在意父類中初始化的參數(shù)有什么砂缩,直接一股腦扔個子類就好了作谚。但是我們也可以用過對子類的初始化設(shè)定對一些參數(shù)進行調(diào)整,而改變子類的屬性或者行為庵芭。

The AlwaysBlueCar constructor simply passes on all arguments to its parent class and then overrides an internal attribute. This means if the parent class constructor changes, there’s a good chance that AlwaysBlueCar would still function as intended.

父類發(fā)生變化妹懒,子類不變。

The downside here is that the AlwaysBlueCar constructor now has a rather unhelpful signature—we don’t know what arguments it expects without looking up the parent class.

但是有一個壞處就是我們?nèi)绻豢锤割愑质裁磪?shù)的話双吆,不知道子類都被傳遞了什么眨唬。

Typically you wouldn’t use this technique with your own class hierarchies. The more likely scenario would be that you’ll want to modify or override behavior in some external class which you don’t control.

一般情況下,我們不會用這個(就是雙星和單星)在我們自己的類的繼承上好乐。更可能的情景是你想去修改或者改寫一些你不控制的外部類的行為

But this is always dangerous territory, so best be careful (or you might soon have yet another reason to scream “argh!”).

在使用雙星或者單星語法的時候我們需要加以注意匾竿。

One more scenario where this technique is potentially helpful is writing wrapper functions such as decorators. There you typically also want to accept arbitrary arguments to be passed through to the wrapped function.

這個技術(shù)有用的一個場景是寫如裝飾器這樣的封裝函數(shù)的時候。我們可能會需要將接受任意的參數(shù)傳遞到被封裝的函數(shù)中蔚万。

And, if we can do it without having to copy and paste the original function’s signature, that might be more maintainable:

def trace(f):
  @functools.wraps(f)
  def decorated_function(*args, **kwargs):
    print(f, args, kwargs)
    result = f(*args, **kwargs)
    print(result)
  return decorated_function

@trace
def greet(greeting, name):
  return '{}, {}!'.format(greeting, name)

>>> greet('Hello', 'Bob')
<function greet at 0x1031c9158> ('Hello', 'Bob') {}
'Hello, Bob!'

我們不用復(fù)制和粘貼原始函數(shù)的簽名就可以做到這一點岭妖,這樣更可維護。

With techniques like this one, it’s sometimes difficult to balance the idea of making your code explicit enough and yet adhere to the Don’t Repeat Yourself (DRY) principle. This will always be a tough choice to make. If you can get a second opinion from a colleague, I’d encourage you to ask for one.

需要平衡在使得代碼足夠清晰和不要自己重復(fù)自己(應(yīng)該是大量重復(fù)的代碼)。

Key Takeaways

  • *args and **kwargs let you write functions with a variable number of arguments in Python.
  • *args collects extra positional arguments as a tuple **kwargs collects the extra keyword arguments as a dictionary.
  • The actual syntax is * and **. Calling them args and kwargs is just a convention (and one you should stick to).
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末昵慌,一起剝皮案震驚了整個濱河市假夺,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌废离,老刑警劉巖侄泽,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蜻韭,居然都是意外死亡悼尾,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進店門肖方,熙熙樓的掌柜王于貴愁眉苦臉地迎上來闺魏,“玉大人,你說我怎么就攤上這事俯画∥銮牛” “怎么了?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵艰垂,是天一觀的道長泡仗。 經(jīng)常有香客問我,道長猜憎,這世上最難降的妖魔是什么娩怎? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮胰柑,結(jié)果婚禮上截亦,老公的妹妹穿的比我還像新娘。我一直安慰自己柬讨,他們只是感情好崩瓤,可當(dāng)我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著踩官,像睡著了一般却桶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上卖鲤,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天肾扰,我揣著相機與錄音,去河邊找鬼蛋逾。 笑死集晚,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的区匣。 我是一名探鬼主播偷拔,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蒋院,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了莲绰?” 一聲冷哼從身側(cè)響起欺旧,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蛤签,沒想到半個月后辞友,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡震肮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年称龙,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片戳晌。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡鲫尊,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出沦偎,到底是詐尸還是另有隱情疫向,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布豪嚎,位于F島的核電站搔驼,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏侈询。R本人自食惡果不足惜匙奴,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望妄荔。 院中可真熱鬧,春花似錦谍肤、人聲如沸啦租。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽篷角。三九已至,卻和暖如春系任,著一層夾襖步出監(jiān)牢的瞬間恳蹲,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工俩滥, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留嘉蕾,地道東北人。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓霜旧,卻偏偏與公主長得像错忱,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,884評論 2 354

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

  • rljs by sennchi Timeline of History Part One The Cognitiv...
    sennchi閱讀 7,331評論 0 10
  • pyspark.sql模塊 模塊上下文 Spark SQL和DataFrames的重要類: pyspark.sql...
    mpro閱讀 9,453評論 0 13
  • mean to add the formatted="false" attribute?.[ 46% 47325/...
    ProZoom閱讀 2,696評論 0 3
  • 秋天 是來了嗎以清? 好像吧 吹了一個晚上的風(fēng) 就把秋天給吹來了 那么 秋天別來可以嗎 或者 可以晚一點來嗎 讓我再感...
    多摩呸呸呸_ian閱讀 228評論 0 1
  • 最近在更新ButterKnife時發(fā)現(xiàn)出了點問題,到官網(wǎng)看了一下,原來ButterKnife使用apt.配置也要進...
    口袋易佰閱讀 355評論 0 0