1. 程式人生 > >【python學習筆記】python函式定義和傳參方法說明

【python學習筆記】python函式定義和傳參方法說明

一、函式定義方式

函式定義用關鍵字def,其引數傳遞不用設定型別,也不用定義返回,然後在函式名稱後加上:號,這點和java很不一樣,相對來說更加簡單了;另外包含關係上用四個空格來標識,而非java的;號;
如下為一個範例,定義了一個函式用來生成任意上界的菲波那契數列:

# -*- coding: UTF-8 -*-
def fib(n):
    a,b = 0,1
    while a<n:
        print a,
        a,b = b, a+b

if __name__ == '__main__':
    a = fib(2000)

結果:

0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597

二、高階用法

除了最簡單的傳參方法後還有特別的傳參方法,有三種可用方式,下面一一做說明;
大體來說,引數傳遞分為必選引數和可選引數(注意必選引數必須在前面),可選引數在呼叫函式的時候可傳可不傳,這點比java要好用(用java得多寫好幾個函式);

1、預設引數值

預設引數值即在函式定義的時候為一個或者多個引數定義一個預設值,如果呼叫引數的時候不傳入該引數則自動使用預設引數值,下面是一個範例:

def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
    while True:
        ok =
raw_input(prompt) if ok in ('y', 'ye', 'yes'): return True if ok in ('n', 'no', 'nop', 'nope'): return False retries = retries - 1 if retries < 0: raise IOError('refusenik user') print complaint

在這個例子中引數retriescomplaint

這兩個引數即為可選引數,其=號後邊的即為預設引數值;
那麼呼叫的時候我們就可以這樣:

  • 只傳入預設引數prompt
ask_ok('Do you really want to quit?')
  • 給出一個可選的引數:
ask_ok('OK to overwrite the file?', 2)
  • 或者給出所有的引數:
ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')

注意:這裡注意引數順序不要錯誤,另外預設引數值只會被賦值一次,但也有例外情況,譬如預設值是個列表、字典或者大多數類的例項。例如,下面的函式在後續呼叫過程中會累積(前面)傳給它的引數:

>>> def f(a,L=[0]):
	    L.append(a)
	    return L

>>> print f(1)
[0, 1]
>>> print f(2)
[0, 1, 2]
>>> print f(3)
[0, 1, 2, 3]

為什麼會這樣呢,解釋如下:
Python函式在定義的時候,預設引數L的值就被計算出來了,即[],因為預設引數L也是一個變數,它指向物件[],每次呼叫該函式,如果改變了L的內容,則下次呼叫時,預設引數的內容就變了,不再是函式定義時的[]了。
定義預設引數要牢記一點:預設引數必須指向不變物件!

可以像如下這樣修改就不會有這個問題了:

>>> def ff(a, L=None):
	    if L is None:
		    L=[]
	    L.append(a)
	    return L

>>> print ff(1)
[1]
>>> print ff(2)
[2]
>>> print ff(3)
[3]

如上所示,結果就不會再出現前次傳入的值會加入後邊的情況了;

函式呼叫的時候可選引數如果採用前面那種方式則必然得注意順序,譬如我有三個可選引數,但是我第一個可選引數不想傳咋辦呢,用前面那種方式顯然不可行,那麼就可以用關鍵字引數了,執行key=value方式可以忽略順序,也可以自定義傳入的可選引數值,範例如下:

def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
    print "-- This parrot wouldn't", action,
    print "if you put", voltage, "volts through it."
    print "-- Lovely plumage, the", type
    print "-- It's", state, "!"

接受一個必選引數( voltage)以及三個可選引數( state, action, 和 type )。可以用以下的任一方法呼叫:

parrot(1000)                                          # 1 positional argument
parrot(voltage=1000)                                  # 1 keyword argument
parrot(voltage=1000000, action='VOOOOOM')             # 2 keyword arguments
parrot(action='VOOOOOM', voltage=1000000)             # 2 keyword arguments
parrot('a million', 'bereft of life', 'jump')         # 3 positional arguments
parrot('a thousand', state='pushing up the daisies')  # 1 positional, 1 keyword

不過以下幾種呼叫是無效的:

parrot()                     # required argument missing
parrot(voltage=5.0, 'dead')  # non-keyword argument after a keyword argument
parrot(110, voltage=220)     # duplicate value for the same argument
parrot(actor='John Cleese')  # unknown keyword argument

注意:這種關鍵字引數的傳參方法適用於所有的引數,即包括必選引數和可選引數;

2、可變引數

python對於定義函式的時候的引數還提供了一種方法,即可變引數,可變引數的意思就是傳入的引數的個數是可變的,可以是0個,1個或者無數個;
譬如我們需要定義一個函式,入參為一個元組或者列表,可以這樣寫:

>>> def c(numbers):
	    sum=0
	    for n in numbers:
		    sum=sum+n*n
	    return sum

呼叫的時候就需要先定義一個元組或者列表,如下:

>>> c([1,2,3])
14
>>> c((1,3,5,7))
84

其實是比較麻煩的,那麼又沒簡單的方法呢,有的,那就是在numbers前面加一個*號即可,這樣呼叫的時候就不用再初始化了,如下:

>>> def calc(*numbers):
	sum=0
	for n in numbers:
		sum=sum+n*n
	return sum

呼叫時就可以這樣:

>>> calc(1,2,3)
14
>>> calc()
0

這樣確實比前面那個例子要方便很多;
注意:可選引數不要加兩個*argu,這樣程式會分不清的;

3、關鍵字引數

那麼如果我引數是需要傳入字典呢?可以使用**kw的方式,請看如下範例:
定義一個函式:

>>> def cheeseshop(kind,*arguments,**keywords):
	    print "-- Do you have any", kind, "?"
	    print "-- I'm sorry, we're all out of",kind
	    for arg in arguments:
		    print arg
	    print "-"*40
	    keys=sorted(keywords.keys())
	    for kw in keys:
		    print kw, ":", keywords[kw]

這個函式除了一個必選引數kind,第二個引數需要傳入的是一個tuple或者list,第三個引數呢需要傳入一個字典;
如前所說這種引數寫法是不需要先定義元組或者列表或者序列的,可以直接當引數傳入,如下即為呼叫方法:

>>> cheeseshop("Limburger","It's very runny,sir.","It's really very, VERY runny, sir.",shopkeeper='Michael Palin',client="John cleese",sketch='Cheese Shop Sketch')
-- Do you have any Limburger ?
-- I'm sorry, we're all out of Limburger
It's very runny,sir.
It's really very, VERY runny, sir.
----------------------------------------
client : John cleese
shopkeeper : Michael Palin
sketch : Cheese Shop Sketch

如上所示,傳入的第一個引數值Limburger是必選引數kind,第二個引數到第三個引數為元組,後邊幾個明顯是鍵值對模式的即為字典了。

注意:在列印關鍵字引數之前,通過對關鍵字字典keys()方法的結果進行排序,生成了關鍵字引數名的列表;如果不這樣做,打印出來的引數的順序是未定義的。

4、命名關鍵字引數

這個和**kw有點類似,區別在於,前面那種方式呼叫的時候傳入的字典很自由,但是如果我們想控制呼叫的時候傳入的字典的key呢?可以新增一個特殊分隔符**後面的引數被視為命名關鍵字引數,範例如下:

>>> def person(name, age, *, city, job):
...     print (name, age, city,job)
...

上面的程式碼中傳入的dict只能包含cityjob這兩個key
呼叫的時候可以這樣呼叫:

>>> person('jack',24,city='beijing',job='engineer')
jack 24 beijing engineer

那麼我們多傳或者少傳引數呢?就會報錯,如下:

>>> person('sun',33, city="beijing",job="actor",alive="yes")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: person() got an unexpected keyword argument 'alive'
>>> person('jack',24,city='beijing')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: person() missing 1 required keyword-only argument: 'job'

注意:這個方法只有python3.0以上的才支援,python2.x是不支援的,下面這個就是在python2.7中驗證,結果報錯了:

>>> def person(name, age,*,city,job):
	
SyntaxError: invalid syntax

如果函式定義中已經有了一個可變引數,後面跟著的命名關鍵字引數就不再需要一個特殊分隔符*了:

def person(name, age, *args, city, job):
    print(name, age, args, city, job)

命名關鍵字引數可以有預設值,從而簡化呼叫:

def person(name, age, *, city='Beijing', job):
    print(name, age, city, job)

這樣也可以不用傳入city,如:

>>> person('Jack', 24, job='Engineer')
Jack 24 Beijing Engineer

5、引數組合

在Python中定義函式,可以用必選引數、預設引數、可變引數、關鍵字引數和命名關鍵字引數,這5種引數都可以組合使用。但是請注意,引數定義的順序必須是:必選引數、預設引數、可選引數、命名關鍵字引數(python2.x無)和關鍵字引數。
比如定義一個函式,包含上述若干種引數:

def f1(a, b, c=0, *args, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)

def f2(a, b, c=0, *, d, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)

在函式呼叫的時候,Python直譯器自動按照引數位置和引數名把對應的引數傳進去。

>>> f1(1, 2)
a = 1 b = 2 c = 0 args = () kw = {}
>>> f1(1, 2, c=3)
a = 1 b = 2 c = 3 args = () kw = {}
>>> f1(1, 2, 3, 'a', 'b')
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {}
>>> f1(1, 2, 3, 'a', 'b', x=99)
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
>>> f2(1, 2, d=99, ext=None)
a = 1 b = 2 c = 0 d = 99 kw = {'ext': None}

最神奇的是通過一個tuple和dict,你也可以呼叫上述函式:

>>> args = (1, 2, 3, 4)
>>> kw = {'d': 99, 'x': '#'}
>>> f1(*args, **kw)
a = 1 b = 2 c = 3 args = (4,) kw = {'d': 99, 'x': '#'}
>>> args = (1, 2, 3)
>>> kw = {'d': 88, 'x': '#'}
>>> f2(*args, **kw)
a = 1 b = 2 c = 3 d = 88 kw = {'x': '#'}

參考文件:http://www.runoob.com/manual/pythontutorial/docs/html/controlflow.html#tut-if
https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431752945034eb82ac80a3e64b9bb4929b16eeed1eb9000