我首先把所有跟python參數(shù)有關(guān)的構(gòu)成方法羅列出來作為printdif的參數(shù),這種構(gòu)成方法可以看成是混合參數(shù)構(gòu)造,是參數(shù)構(gòu)造中最為復(fù)雜的一種方式,作為對講解參數(shù)*args與**kwargs的一個非常棒的方法。代碼如下,仔細(xì)看:
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
"""
Created on Sat May 20 18:43:07 2017
This demo shows the diffrent arguments between *args and **kwargs
@author: zhangll
"""
class argdemo:
def __init__(self,name):
self.name=name
def printdif(self,name,key=None,*args,**kwargs):
self.name=name
print self.name
print key
print "args=======%s"%str(args)
count=0
for value in args:
count+=1
print "args's No.%s value:%s"%(count,value)
print "kwargs=======%s"%str(kwargs)
for key in kwargs:
print "**kwargs's key=%s,value=%s"%(key,kwargs[key])
if __name__=='__main__':
arg=argdemo("name1")
print arg.name
arg.printdif("name2","B",["C","D"],{"key1":"E"},key1="hello",key2="world")
最后得到結(jié)果
name2
B
args=======(['C', 'D'], {'key1': 'E'})
args's No.1 value:['C', 'D']
args's No.2 value:{'key1': 'E'}
kwargs======={'key2': 'world', 'key1': 'hello'}
**kwargs's key=key2,value=world
**kwargs's key=key1,value=hello
這個代碼通過調(diào)用arg對象的printdif方法傳遞了共六個參數(shù)
- "name2" 字符串
- "B" 字符串
- ["C","D"] 列表
- {"key1":"E"} 字典
- key1="hello"
- key2="world"
python參數(shù)相關(guān)知識
以上的定義printdif所使用的參數(shù)基本上涵蓋了python的主流參數(shù),根據(jù)主調(diào)函數(shù)**是否必要**傳參的特點上大致把python參數(shù)分為:**必選參數(shù)**與**可選參數(shù)**。關(guān)于這兩種類型的參數(shù)需要做如下語法規(guī)則的補(bǔ)充:
函數(shù)定義與主調(diào)函數(shù)調(diào)用的參數(shù)排序規(guī)則:在必選參數(shù)與可選參數(shù)同時存在的情況下,必須要先定義必選參數(shù),然后再能定義可選參數(shù)------畢竟可選的太多,而必選的參數(shù)是反映函數(shù)功能的主體,當(dāng)然是讓能夠反映函數(shù)主體的元素排在前頭咯。
上面的[name]參數(shù)為**必選參數(shù)**,特點是在函數(shù)定義上,不需要指定內(nèi)容,只需要關(guān)鍵字【name】就行了,但是**主調(diào)函數(shù)**必須要傳入該關(guān)鍵字相關(guān)的內(nèi)容(對象),可以不需要顯式關(guān)鍵字聲明參數(shù),比如可以定義
非顯式關(guān)鍵字:printdif(“abc”)
顯式關(guān)鍵字:printdif(name=“abc”)調(diào)用函數(shù)結(jié)果
abc
None
args=======()
kwargs======={}
[key=None,\*args,\*\*kwargs]這三個參數(shù)為**可選參數(shù)**,也就是說在主調(diào)函數(shù)中可以不用傳參,上面的必選參數(shù)例子就說明只需要必選參數(shù)的函數(shù)調(diào)用是可以執(zhí)行的。如下,我們關(guān)注的是**可選參數(shù)**的內(nèi)容
1.默認(rèn)參數(shù)又稱關(guān)鍵字參數(shù)(keyword argument):【key=None】在函數(shù)定義的時候已經(jīng)事先定義好了內(nèi)容,key關(guān)鍵字對應(yīng)的是None(相當(dāng)于什么都沒有)內(nèi)容:可以如下調(diào)用主調(diào)函數(shù)
非顯式關(guān)鍵字:printdif(“abc”,“B”)
顯式關(guān)鍵字:printdif(name=“abc”,key=“B”)調(diào)用函數(shù)結(jié)果:
abc
B
args=======()
kwargs======={}
問題1:printdif(key=“B”,“abc”)這樣的寫法正確嗎?
答案當(dāng)然是錯誤的,因為我們在上面的定義語法要求上說過了,key=“B”其實質(zhì)是一種可選參數(shù)的傳遞,而“abc”為無關(guān)鍵字的必選參數(shù)的傳遞,必選參數(shù)需要放在可選參數(shù)之前,否則會出現(xiàn)
SyntaxError: non-keyword arg after keyword arg
問題2:printdif(“abc”,name=“B”)這樣的寫法正確嗎?
答案當(dāng)然還是錯誤的,這種寫法在直觀上看有重復(fù)調(diào)用參數(shù)的行為,因為我們不僅在定義參數(shù)的語法上有“必選參數(shù)優(yōu)先放在可選參數(shù)之前”的說法,而且在函數(shù)執(zhí)行過程中也有“必選參數(shù)優(yōu)先選擇權(quán)”,也就是說,在執(zhí)行printdif(“abc”,name=“B”)語句的時候,python先執(zhí)行了,“abc”并傳值于name形參,之后又執(zhí)行一遍name=“ B”,也就是又一次重新傳值,就會出現(xiàn)
TypeError: printdif() got multiple values for keyword argument 'name'
因此python拒絕這種多此一舉的行為
2.*args參數(shù) **kwargs參數(shù)
那么為什么我要在最后講解這兩個參數(shù)的區(qū)別呢?這個兩個難道優(yōu)先級最低我才最后講解嗎?其實這兩個參數(shù)還真是在函數(shù)定義優(yōu)先級方面最低(*args參數(shù)優(yōu)先于**kwargs參數(shù)),看printdif的參數(shù)順序就行了,并且這種定義次序不可改變亂了順序,否則會報“語法錯誤”。雖然級別較低,不過這兩種參數(shù)的運(yùn)用確實比較常見的,或者說這種參數(shù)的出現(xiàn),重復(fù)發(fā)揚(yáng)了python參數(shù)傳遞的靈活性,我們拿numpy中的函數(shù)來查看下:
>>>p.fromfunction?
Signature: np.fromfunction(function, shape, **kwargs)
...
大家有沒有發(fā)現(xiàn),在第一個printdif主調(diào)函數(shù)中序列1和2實參分別傳入必選行參與關(guān)鍵字形參,而在分配之后還剩余的實參將會被默認(rèn)分配給*args形參與**kwargs形參。序列3、4參數(shù)作為*args的參數(shù)依次傳遞,而第5、6個做為**kwargs的參數(shù)以字典的形式傳入。從以上這個特點可以發(fā)現(xiàn),*args傳入的參數(shù)不需要賦值命名,并且構(gòu)成元組類型的結(jié)構(gòu),我們稱這種參數(shù)為元組參數(shù)【元組形式:args=(['C', 'D'], {'key1': 'E'})】;而**kwargs需要以命名關(guān)鍵字的實參作為傳入,且構(gòu)成字典類型的結(jié)構(gòu),并且可用key關(guān)鍵字值找到對應(yīng)的參數(shù)內(nèi)容,我們稱這種參數(shù)為字典參數(shù)【字典形式kwargs={'key2': 'world', 'key1': 'hello'}】。
這里有個最后的問題:
如果我調(diào)用printdif(“abc”,“2”,“3”,“4”,key=“B”,key1=“C”),會得到什么結(jié)果?