學習python: 函數參數

大體上python中的參數可以根據其表現形式分爲以下四種:

  1. 位置參數
  2. 默認參數
  3. 關鍵字參數
  4. 可變參數

其中前兩種是比較常用的方式,其形式也c,c++等語言形式上比較相似,因此比較好理解。

關鍵字參數也是非常常用的方式,使用關鍵字參數不需要使傳入的參數順序和函數定義的參數順序一致,因此更加靈活,尤其是參數過多的時候。

可變參數的形式用處也十分廣泛,其表現形式有兩種,分別是使用一個*和兩個**來表示,且星號所處位置不同(分定義函數時和調用函數),其功能也有所差異。雖然這樣,這種方式也不難理解,只需要多加練習即可。

在實際應用過程中,前三種方式最爲常用,但是往往也會看到很多人使用後可變參數的方式進行程序的編寫,因此學會並且掌握所有的參數的使用方法是十分必要的。

位置參數

位置參數和我們使用的c,c++等語言中定義和調用方法一致。且在調用函數的時候傳入的參數順序要和定義時候的順序一致,其主要表現形式如下:

def f(num1, num2):
    print(num1)
    print(num2)

f(1, 2)

---
#Output:
1
2

由於位置參數比較簡單,因此這裏不在過多介紹。

默認參數

默認參數是指在我們定義函數的過程中,如果有一些參數大多數情況下都可以使用一個值,那麼就可以給它一個默認的值,或者是給它一個初始的值。

這樣的話當我再調用一個這個函數的時候,如果我給它傳遞一個值,那麼函數就會收到我給它傳遞的值;否則,如果我沒有給它傳遞值,那麼函數也不會報錯,而是使用默認的值作爲參數。

舉個例子:

def f(num, power=True):
    if power:
        print(num ** 2) 
    else:
        print(num)

f(2)                # 第一個參數由於是位置參數,因此必須傳入值
                    # 但是第二個參數由於有了默認值,因此可以不給它傳值,此時使用默認的值
f(2, True)          # 當然也可以給它附上一個值,注意此時沒給它關鍵字信息,它會自動把`True`這個值匹配給函數中的power
f(2, False)         # 同上
f(2, power=False)   # 當然還可以使用`power=xxx`的方式去給這個參數傳值
---
#Output
4
4
2
2 

關鍵字參數

上一節默認參數的最後,實際上已經用到了關鍵字參數的形式,f(2, power=False)power=False這樣以一個key=value的形式來傳遞參數的方式即爲關鍵字參數。和位置參數不同,關鍵字參數不需要使傳入的參數順序和定義的順序相同,因爲它是通過關鍵字去匹配的,如下面的例子:

def f(a, b, c):
    print('a = %d'%a)
    print('b = %d'%b)
    print('c = %d'%c)

f(1, 2, 3)		# 使用位置參數,1, 2, 3分別對應a, b, c
f(a=1, b=2, c=3)	# 使用關鍵字參數,也可以讓傳入參數順序和定義順序相同
f(b=2, c=3, a=1)	# 使用關鍵字參數,還可以使傳入參數順序和定義順序不同
f(c=3, a=1, b=2)	# 同上

#Output
a = 1
b = 2
c = 3

a = 1
b = 2
c = 3

a = 1
b = 2
c = 3

a = 1
b = 2
c = 3

可變參數

一個*的表現形式(包裹位置參數)

所謂的包裹(packing)位置參數,就是在函數執行過程中,將傳入的多餘的位置參數打包爲一個tuple傳入包裹位置參數中。

一個經典的例子就是:如何將傳遞到函數裏的參數全部相加,而且傳入函數中的參數數量不確定。比如如果我傳入1,2,那麼就要輸出3,如果輸入1, 2, 3, 4,就是要輸出10.

這時我們就可以使用可變參數來解決這個問題,其函數定義方式爲f(*args)。注意,其中的args參數名字可以換爲其它的名字,但是爲了方便閱讀和協作開發,我們通常使用args來表示一個可變參數。

這種形式當放在函數的定義中時,會把調用時多餘的位置參數傳遞給args,並且封裝爲一個tuple。

我們可以通過如下的方式實現:

def f(*args):
    print(args)
    sum = 0
    for i in args:
        sum += i
    print(sum)

def f1(num, *args):
    print(args)
    sum = 0
    sum += num 
    for i in args:
        sum += i
    print(sum)

f()             # 可以看到,當可變參數什麼都傳遞時,程序不會掛掉,而是在’args‘中收到一個空的tuple
f(1, 2)         # 當傳入1,2時,函數接收到了兩個參數到args中,並且形式爲一個tuple
f(1, 2, 3, 4)   # 同上,只不過tuple中的元素個數變爲了4個,即args = (1, 2, 3, 4)
print('---')
f1(1)           # 這個例子中,由於只傳遞了一個參數,而函數中又有位置參數,因此args中爲空
f1(1, 2)        # 這個例子中, 由於有兩個參數,因此把多餘的2傳遞到args中,即args = (2)
f1(1, 2, 3, 4)  # 這個例子中, 由於多了三個參數,因此把多餘的
                # 3個參數都給到args中,即args = (2, 3, 4)
---
#Output
()
0
(1, 2)
3
(1, 2, 3, 4)
10
---
()
1
(2,)
3
(2, 3, 4)
10

兩個**的表現形式(包裹關鍵字參數)

所謂的包裹關鍵字參數,就是函數執行時將傳入的多餘關鍵字參數打包成一個dict,然後傳遞給一個固定的參數。

其函數定義的方式爲f(**kwargs)。注意,其中參數kwargs的名字也是可以替換成任意名字的,只不過還是爲了協作開發以及閱讀的方便,我們約定俗成使用kwargs

舉個例子:

def f(**kwargs):
    print(kwargs)

f(name = 'laowang', age = 30)	# 函數中沒有位置參數,因此直接將關鍵字參數打包爲一個字典傳給kwargs,注意,我們在使用時不加兩個`**`,直接使用`print(kwargs)`即可。

#Output 
{'age': 30, 'name': 'laowang'}
def f(name, age, **kwargs):
    print('name = %s' % name)
    print('age = %d' % age)
    print(kwargs)

f(name = 'laowang', age = 30)					# 當程序中有了位置參數時候,首先把傳入的值給到位置參數
								# 如果沒有多餘的值,kwargs爲空 
f(name = 'laoli', age = 30, name1 = 'huluwa', age1 = 80)        # 當程序中有了多餘的關鍵字參數,纔將多餘的部分傳遞給kwargs

#Output
name = laowang
age = 30
{}

name = laoli
age = 30
{'age1': 80, 'name1': 'huluwa'}

解包

前面說道,***在函數中和調用時的使用方式是不一樣的,我們已經知道在函數中他們起到打包(packing)的作用;自然可以推理一下在函數調用過程中它們應該是起到解包(unpacking)的作用。

首先看一個例子:

def f(*args, **kwargs):
    print(args)
    print(kwargs)
    print('\n')

a = (1, 2, 3)
b = {'name':'laowang', 'age':30}

f(1, 2, 3, name='laowang', age=30)	# 直接按照上兩節講的內容,將1,2,3打包成位置參數,將name和age打包成關鍵字參數
f(a, b)					# 這裏由於a和b雖然其內容一個是tuple一個是dict,但是放在參數裏都被當做了位置參數處理,而kwargs裏面爲空

# Output 
(1, 2, 3)
{'age': 30, 'name': 'laowang'}


((1, 2, 3), {'age': 30, 'name': 'laowang'})
{}

從上面的例子我們可以看出,我們希望讓f(a, b)的調用方式能夠和f(1, 2, 3, name='laowang', age=30)的調用方式得到相同的結果,但是卻失敗了。

原因是**kwargs只接受key=value形式的調用,而我們直接調用f(a, b), 雖然b={'name':'laowang', 'age':30}是一個字典,但是放在傳入參數中時候b就變成了一個元素,因此沒有達到我們想要的效果;變量a同理。

解決上述問題就是在調用時候增加一個解包(unpacking)的標識符即對應的***號。如將上述調用方式改爲f(*a, **b),這樣其效果就等同於調用f(1, 2, 3, name='laowang', age=30),也就是說,***號把對應的tuple或者dict中的元素一個一個解包出來了。

demo如下:

def f(*args, **kwargs):
    print(args)
    print(kwargs)
    print('\n')

a = (1, 2, 3)
b = {'name':'laowang', 'age':30}

f(1, 2, 3, name='laowang', age=30)
f(*a, **b)

# Output 
(1, 2, 3)
{'age': 30, 'name': 'laowang'}


(1, 2, 3)
{'age': 30, 'name': 'laowang'}

python 中參數的注意事項

一個需要注意的問題就是順序問題,一個合法的順序是位置參數->默認參數->包裹位置參數(*)->包裹關鍵字參數(**)。見下面的demo:

def f(a, b, c=10, *args, **kwargs):
    print(a)
    print(b)
    print(c)
    print(args)
    print(kwargs)

num = (1, 2, 3, 4)
info = {'name':'huluwa', 'grade':2}

f(100, 10, 20, *num, **info)

# Output 
100
10
20
(1, 2, 3, 4)
{'grade': 2, 'name': 'huluwa'}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章