鍍金池/ 教程/ Python/ 函數(shù)(3)
標(biāo)準(zhǔn)庫(kù) (4)
如何成為 Python 高手
標(biāo)準(zhǔn)庫(kù) (6)
標(biāo)準(zhǔn)庫(kù) (3)
類(2)
Pandas 使用 (2)
xml
用 tornado 做網(wǎng)站 (5)
文件(1)
練習(xí)
列表(3)
從小工到專家
除法
錯(cuò)誤和異常 (2)
函數(shù)(1)
用 tornado 做網(wǎng)站 (7)
為做網(wǎng)站而準(zhǔn)備
函數(shù)練習(xí)
標(biāo)準(zhǔn)庫(kù) (8)
Pandas 使用 (1)
回顧 list 和 str
字典(1)
用 tornado 做網(wǎng)站 (3)
字符串(1)
函數(shù)(2)
寫一個(gè)簡(jiǎn)單的程序
將數(shù)據(jù)存入文件
語(yǔ)句(5)
SQLite 數(shù)據(jù)庫(kù)
集成開發(fā)環(huán)境(IDE)
集合(1)
類(1)
用 tornado 做網(wǎng)站 (6)
用 tornado 做網(wǎng)站 (2)
自省
語(yǔ)句(4)
錯(cuò)誤和異常 (1)
用 tornado 做網(wǎng)站 (4)
集合(2)
列表(1)
標(biāo)準(zhǔn)庫(kù) (1)
生成器
mysql 數(shù)據(jù)庫(kù) (1)
第三方庫(kù)
實(shí)戰(zhàn)
運(yùn)算符
類(3)
字典(2)
語(yǔ)句(1)
數(shù)和四則運(yùn)算
語(yǔ)句(2)
文件(2)
MySQL 數(shù)據(jù)庫(kù) (2)
電子表格
迭代器
mongodb 數(shù)據(jù)庫(kù) (1)
特殊方法 (2)
特殊方法 (1)
字符編碼
編寫模塊
用 tornado 做網(wǎng)站 (1)
標(biāo)準(zhǔn)庫(kù) (5)
函數(shù)(4)
類(5)
字符串(2)
關(guān)于 Python 的故事
函數(shù)(3)
字符串(4)
處理股票數(shù)據(jù)
常用數(shù)學(xué)函數(shù)和運(yùn)算優(yōu)先級(jí)
字符串(3)
為計(jì)算做準(zhǔn)備
多態(tài)和封裝
類(4)
迭代
語(yǔ)句(3)
錯(cuò)誤和異常 (3)
分析 Hello
Python 安裝
標(biāo)準(zhǔn)庫(kù) (2)
列表(2)
元組

函數(shù)(3)

在設(shè)計(jì)函數(shù)的時(shí)候,有時(shí)候我們能夠確認(rèn)參數(shù)的個(gè)數(shù),比如一個(gè)用來計(jì)算圓面積的函數(shù),它所需要的參數(shù)就是半徑(πr^2),這個(gè)函數(shù)的參數(shù)是確定的。

你能不能寫一個(gè)能夠計(jì)算圓面積的函數(shù)呢?

然而,這個(gè)世界不總是這么簡(jiǎn)單的,也不總是這么確定的,反而不確定性是這個(gè)世界常常存在的。如果看官了解量子力學(xué)——好多人聽都沒有聽過的東西——就更理解真正的不確定性了。當(dāng)然,不用研究量子力學(xué)也一樣能夠體會(huì)到,世界充滿里了不確定性。不是嗎?塞翁失馬焉知非福,這不就是不確定性嗎?

參數(shù)收集

既然有很多不確定性,那么函數(shù)的參數(shù)的個(gè)數(shù),也當(dāng)然有不確定性,函數(shù)怎么解決這個(gè)問題呢?Python 用這樣的方式解決參數(shù)個(gè)數(shù)的不確定性:

def func(x,*arg):
    print x         #輸出參數(shù) x 的值
    result = x
    print arg       #輸出通過 *arg 方式得到的值
    for i in arg:
        result +=i
    return result

print func(1,2,3,4,5,6,7,8,9)    #賦給函數(shù)的參數(shù)個(gè)數(shù)不僅僅是  2個(gè)

運(yùn)行此代碼后,得到如下結(jié)果:

1                       #這是函數(shù)體內(nèi)的第一個(gè) print,參數(shù)x得到的值是 1
(2, 3, 4, 5, 6, 7, 8, 9) #這是函數(shù)內(nèi)的第二個(gè) print,參數(shù) arg 得到的是一個(gè)元組
45                      #最后的計(jì)算結(jié)果

從上面例子可以看出,如果輸入的參數(shù)個(gè)數(shù)不確定,其它參數(shù)全部通過 *arg,以元組的形式由 arg 收集起來。對(duì)照上面的例子不難發(fā)現(xiàn):

  • 值 1 傳給了參數(shù) x
  • 值 2,3,4,5,6.7.8.9 被塞入一個(gè) tuple 里面,傳給了 arg

為了能夠更明顯地看出 args(名稱可以不一樣,但是 符號(hào)必須要有),可以用下面的一個(gè)簡(jiǎn)單函數(shù)來演示:

>>> def foo(*args):
...     print args      #打印通過這個(gè)參數(shù)得到的對(duì)象
... 

下面演示分別傳入不同的值,通過參數(shù) *args 得到的結(jié)果:

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

>>> foo("qiwsir","qiwsir.github.io","python")
('qiwsir', 'qiwsir.github.io', 'python')

>>> foo("qiwsir",307,["qiwsir",2],{"name":"qiwsir","lang":"python"})
('qiwsir', 307, ['qiwsir', 2], {'lang': 'python', 'name': 'qiwsir'})

不管是什么,都一股腦地塞進(jìn)了 tuple 中。

>>> foo("python")
('python',)

即使只有一個(gè)值,也是用 tuple 收集它。特別注意,在 tuple 中,如果只有一個(gè)元素,后面要有一個(gè)逗號(hào)。

還有一種可能,就是不給那個(gè) *args 傳值,也是許可的。例如:

>>> def foo(x, *args):
...     print "x:",x
...     print "tuple:",args
... 
>>> foo(7)
x: 7
tuple: ()

這時(shí)候 *args 收集到的是一個(gè)空的 tuple。

在各類編程語(yǔ)言中,常常會(huì)遇到以 foo,bar,foobar 等之類的命名,不管是對(duì)變量、函數(shù)還是后面要講到的類。這是什么意思呢?下面是來自維基百科的解釋。

在計(jì)算機(jī)程序設(shè)計(jì)與計(jì)算機(jī)技術(shù)的相關(guān)文檔中,術(shù)語(yǔ) foobar 是一個(gè)常見的無(wú)名氏化名,常被作為“偽變量”使用。

從技術(shù)上講,“foobar”很可能在 1960 年代至 1970 年代初通過迪吉多的系統(tǒng)手冊(cè)傳播開來。另一種說法是,“foobar”可能來源于電子學(xué)中反轉(zhuǎn)的 foo 信號(hào);這是因?yàn)槿绻粋€(gè)數(shù)字信號(hào)是低電平有效(即負(fù)壓或零電壓代表“1”),那么在信號(hào)標(biāo)記上方一般會(huì)標(biāo)有一根水平橫線,而橫線的英文即為“bar”。在《新黑客辭典》中,還提到“foo”可能早于“FUBAR”出現(xiàn)。

單詞“foobar”或分離的“foo”與“bar”常出現(xiàn)于程序設(shè)計(jì)的案例中,如同 Hello World 程序一樣,它們常被用于向?qū)W習(xí)者介紹某種程序語(yǔ)言?!癴oo”常被作為函數(shù)/方法的名稱,而“bar”則常被用作變量名。

除了用 *args 這種形式的參數(shù)接收多個(gè)值之外,還可以用 **kargs 的形式接收數(shù)值,不過這次有點(diǎn)不一樣:

>>> def foo(**kargs):
...     print kargs
...
>>> foo(a=1,b=2,c=3)    #注意觀察這次賦值的方式和打印的結(jié)果
{'a': 1, 'c': 3, 'b': 2}

如果這次還用 foo(1,2,3)的方式,會(huì)有什么結(jié)果呢?

>>> foo(1,2,3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() takes exactly 0 arguments (3 given)

如果用 **kargs 的形式收集值,會(huì)得到 dict 類型的數(shù)據(jù),但是,需要在傳值的時(shí)候說明“鍵”和“值”,因?yàn)樵谧值渲惺且枣I值對(duì)形式出現(xiàn)的。

看官到這里可能想了,不是不確定性嗎?我也不知道參數(shù)到底會(huì)可能用什么樣的方式傳值呀,這好辦,把上面的都綜合起來。

>>> def foo(x,y,z,*args,**kargs):
...     print x   
...     print y
...     print z
...     print args
...     print kargs        
... 
>>> foo('qiwsir',2,"python")
qiwsir
2
python
()
{}
>>> foo(1,2,3,4,5)
1
2
3
(4, 5)
{}
>>> foo(1,2,3,4,5,name="qiwsir")
1
2
3
(4, 5)
{'name': 'qiwsir'}

很 good 了,這樣就能夠足以應(yīng)付各種各樣的參數(shù)要求了。

另外一種傳值方式

>>> def add(x,y):
...     return x + y
... 
>>> add(2,3)
5

這是通常的函數(shù)調(diào)用方法,在前面已經(jīng)屢次用到。這種方法簡(jiǎn)單明快,很容易理解。但是,世界總是多樣性的,有時(shí)候你秀出下面的方式,甚至在某種情況用下面的方法可能更優(yōu)雅。

>>> bars = (2,3)
>>> add(*bars)
5

先把要傳的值放到元組中,賦值給一個(gè)變量 bars,然后用 add(*bars) 的方式,把值傳到函數(shù)內(nèi)。這有點(diǎn)像前面收集參數(shù)的逆過程。注意的是,元組中元素的個(gè)數(shù),要跟函數(shù)所要求的變量個(gè)數(shù)一致。如果這樣:

>>> bars = (2,3,4)
>>> add(*bars)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: add() takes exactly 2 arguments (3 given)

就報(bào)錯(cuò)了。

這是使用一個(gè)星號(hào) *,是以元組形式傳值,如果用 ** 的方式,是不是應(yīng)該以字典的形式呢?理當(dāng)如此。

>>> def book(author,name):
...     print "%s is writing %s" % (author,name)
... 
>>> bars = {"name":"Starter learning Python","author":"Kivi"}
>>> book(**bars)
Kivi is writing Starter learning Python

這種調(diào)用函數(shù)傳值的方式,至少在我的編程實(shí)踐中,用的不多。不過,不代表讀者不用。這或許是習(xí)慣問題。

復(fù)習(xí)

python 中函數(shù)的參數(shù)通過賦值的方式來傳遞引用對(duì)象。下面總結(jié)通過總結(jié)常見的函數(shù)參數(shù)定義方式,來理解參數(shù)傳遞的流程。

def foo(p1,p2,p3,...)

這種方式最常見了,列出有限個(gè)數(shù)的參數(shù),并且彼此之間用逗號(hào)隔開。在調(diào)用函數(shù)的時(shí)候,按照順序以此對(duì)參數(shù)進(jìn)行賦值,特備注意的是,參數(shù)的名字不重要,重要的是位置。而且,必須數(shù)量一致,一一對(duì)應(yīng)。第一個(gè)對(duì)象(可能是數(shù)值、字符串等等)對(duì)應(yīng)第一個(gè)參數(shù),第二個(gè)對(duì)應(yīng)第二個(gè)參數(shù),如此對(duì)應(yīng),不得偏左也不得偏右。

>>> def foo(p1,p2,p3):
...     print "p1==>",p1
...     print "p2==>",p2
...     print "p3==>",p3
... 
>>> foo("python",1,["qiwsir","github","io"])    #一一對(duì)應(yīng)地賦值
p1==> python
p2==> 1
p3==> ['qiwsir', 'github', 'io']

>>> foo("python")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() takes exactly 3 arguments (1 given)    #注意看報(bào)錯(cuò)信息

>>> foo("python",1,2,3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() takes exactly 3 arguments (4 given)    #要求 3 個(gè)參數(shù),實(shí)際上放置了 4 個(gè),報(bào)錯(cuò)

def foo(p1=value1,p2=value2,...)

這種方式比前面一種更明確某個(gè)參數(shù)的賦值,貌似這樣就不亂子了,很明確呀。頗有一個(gè)蘿卜對(duì)著一個(gè)坑的意味。

還是上面那個(gè)函數(shù),用下面的方式賦值,就不用擔(dān)心順序問題了。

>>> foo(p3=3,p1=10,p2=222)
p1==> 10
p2==> 222
p3==> 3

也可以采用下面的方式定義參數(shù),給某些參數(shù)有默認(rèn)的值

>>> def foo(p1,p2=22,p3=33):    #設(shè)置了兩個(gè)參數(shù) p2,p3 的默認(rèn)值
...     print "p1==>",p1
...     print "p2==>",p2
...     print "p3==>",p3
... 
>>> foo(11)     #p1=11,其它的參數(shù)為默認(rèn)賦值
p1==> 11
p2==> 22
p3==> 33
>>> foo(11,222)     #按照順序,p2=222,p3 依舊維持原默認(rèn)值
p1==> 11
p2==> 222
p3==> 33
>>> foo(11,222,333)  #按順序賦值
p1==> 11
p2==> 222
p3==> 333

>>> foo(11,p2=122)
p1==> 11
p2==> 122
p3==> 33

>>> foo(p2=122)     #p1 沒有默認(rèn)值,必須要賦值的,否則報(bào)錯(cuò)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() takes at least 1 argument (1 given)

def foo(*args)

這種方式適合于不確定參數(shù)個(gè)數(shù)的時(shí)候,在參數(shù) args 前面加一個(gè) *,注意,僅一個(gè)喲。

>>> def foo(*args):         #接收不確定個(gè)數(shù)的數(shù)據(jù)對(duì)象
...     print args
... 
>>> foo("qiwsir.github.io") #以 tuple 形式接收到,哪怕是一個(gè)
('qiwsir.github.io',)
>>> foo("qiwsir.github.io","python")
('qiwsir.github.io', 'python')

def foo(**args)

這種方式跟上面的區(qū)別在于,必須接收類似 arg=val 形式的。

>>> def foo(**args):    #這種方式接收,以 dictionary 的形式接收數(shù)據(jù)對(duì)象
...     print args
... 

>>> foo(1,2,3)          #這樣就報(bào)錯(cuò)了
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() takes exactly 0 arguments (3 given)

>>> foo(a=1,b=2,c=3)    #這樣就可以了,因?yàn)橛辛随I值對(duì)
{'a': 1, 'c': 3, 'b': 2}

下面來一個(gè)綜合的,看看以上四種參數(shù)傳遞方法的執(zhí)行順序

>>> def foo(x,y=2,*targs,**dargs):
...     print "x==>",x
...     print "y==>",y
...     print "targs_tuple==>",targs
...     print "dargs_dict==>",dargs
... 

>>> foo("1x")
x==> 1x
y==> 2
targs_tuple==> ()
dargs_dict==> {}

>>> foo("1x","2y")
x==> 1x
y==> 2y
targs_tuple==> ()
dargs_dict==> {}

>>> foo("1x","2y","3t1","3t2")
x==> 1x
y==> 2y
targs_tuple==> ('3t1', '3t2')
dargs_dict==> {}

>>> foo("1x","2y","3t1","3t2",d1="4d1",d2="4d2")
x==> 1x
y==> 2y
targs_tuple==> ('3t1', '3t2')
dargs_dict==> {'d2': '4d2', 'd1': '4d1'}

總目錄   |   上節(jié):函數(shù)(2)   |   下節(jié):函數(shù)(4)

如果你認(rèn)為有必要打賞我,請(qǐng)通過支付寶:qiwsir@126.com,不勝感激。

上一篇:字典(1)下一篇:xml