Python 3.6學習--基礎3:函式的定義
>>> def fib(n): # write Fibonacci series up to n ... """Print a Fibonacci series up to n.""" ... a, b = 0, 1 ... while a < n: ... print(a, end=' ') ... a, b = b, a+b ... print() ... >>> # Now call the function we just defined: ... fib(2000) 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
該關鍵字def
引入了一個函式定義。它必須後跟函式名稱和帶括號的形式引數列表。構成函式體的語句從下一行開始,並且必須縮排。
呼叫函式呼叫的實際引數(引數)在被呼叫函式的本地符號表中引入; 因此,使用call by value傳遞引數(其中值始終是物件引用,而不是物件的值)。當函式呼叫另一個函式時,將為該呼叫建立一個新的本地符號表。
函式定義在當前符號表中引入函式名稱。函式名稱的值具有直譯器將其識別為使用者定義函式的型別。此值可以分配給另一個名稱,該名稱也可以用作函式。這是一般的重新命名機制:
>>> fib <function fib at 10042ed0> >>> f = fib >>> f(100) 0 1 1 2 3 5 8 13 21 34 55 89
實際上,即使是沒有return
語句的函式也會 返回一個值,儘管它是一個相當無聊的值。呼叫此值None
(它是內建名稱)。None
如果它是唯一寫入的值,則直譯器通常會禁止寫入值。如果你真的想使用它,你可以看到它print()
:
>>> fib(0)
>>> print(fib(0))
None
編寫一個函式可以很簡單地返回Fibonacci系列的數字列表,而不是列印它:
>>> def fib2(n): # return Fibonacci series up to n ... """Return a list containing the Fibonacci series up to n.""" ... result = [] ... a, b = 0, 1 ... while a < n: ... result.append(a) # see below ... a, b = b, a+b ... return result ... >>> f100 = fib2(100) # call it >>> f100 # write the result [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
像往常一樣,此示例演示了一些新的Python功能:
- 該
return
語句返回一個函式的值。return
沒有表示式引數返回None
。從函式的末尾掉落也會返回None
。 - 該語句
result.append(a)
呼叫list物件 的方法result
。方法是“屬於”物件並被命名的函式obj.methodname
,其中obj
是某個物件(可能是表示式),並且methodname
是由物件的型別定義的方法的名稱。不同型別定義不同的方法。不同型別的方法可以具有相同的名稱而不會引起歧義。(可以使用類定義自己的物件型別和方法,請參閱類)append()
示例中顯示的方法是為列表物件定義的; 它在列表的末尾添加了一個新元素。在這個例子中它相當於 ,但效率更高。result = result + [a]
更多關於定義函式的資訊
也可以使用可變數量的引數定義函式。有三種形式可以組合。
預設引數值
最有用的形式是為一個或多個引數指定預設值。這建立了一個函式,可以使用比定義允許的引數更少的引數呼叫。例如:
def ask_ok(prompt, retries=4, reminder='Please try again!'):
while True:
ok = 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 ValueError('invalid user response')
print(reminder)
可以通過多種方式呼叫此函式:
- 只給出強制性引數:
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!')
此示例還介紹了in
關鍵字。這測試序列是否包含某個值。
預設值在定義範圍內的函式定義點進行計算 ,以便進行
i = 5
def f(arg=i):
print(arg)
i = 6
f()
將列印5
。
重要警告: 預設值僅評估一次。當預設值是可變物件(例如列表,字典或大多數類的例項)時,這會產生差異。例如,以下函式會累積在後續呼叫中傳遞給它的引數:
def f(a, L=[]):
L.append(a)
return L
print(f(1))
print(f(2))
print(f(3))
這將打印出來
[1]
[1, 2]
[1, 2, 3]
如果您不希望在後續呼叫之間共享預設值,則可以編寫如下函式:
def f(a, L=None):
if L is None:
L = []
L.append(a)
return L
關鍵字引數
也可以使用 表單的關鍵字引數呼叫函式kwarg=value
。例如,以下功能:
def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
print("-- This parrot wouldn't", action, end=' ')
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
在函式呼叫中,關鍵字引數必須遵循位置引數。傳遞的所有關鍵字引數必須與函式接受的引數之一匹配(例如actor
,不是函式的有效引數 parrot
),並且它們的順序並不重要。這還包括非可選引數(例如parrot(voltage=1000)
也是有效的)。沒有引數可能會多次獲得一個值。以下是由於此限制而失敗的示例:
>>> def function(a):
... pass
...
>>> function(0, a=0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: function() got multiple values for keyword argument 'a'
當**name
存在表單的最終形式引數時,它接收包含除了與形式引數相對應的所有關鍵字引數的字典(參見對映型別 - 字典)。這可以與形式的形式引數*name
(在下一小節中描述)組合,該引數接收包含超出形式引數列表的位置引數的元組。(*name
必須在之前發生**name
。)例如,如果我們定義一個這樣的函式:
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)
for kw in keywords:
print(kw, ":", keywords[kw])
它可以像這樣呼叫:
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.
----------------------------------------
shopkeeper : Michael Palin
client : John Cleese
sketch : Cheese Shop Sketch
請注意,列印關鍵字引數的順序保證與函式呼叫中提供它們的順序相匹配。
任意引數列表
def write_multiple_items(file, separator, *args):
file.write(separator.join(args))
通常,這些variadic
引數將在形式引數列表中排在最後,因為它們會挖掘傳遞給函式的所有剩餘輸入引數。在*args
引數之後出現的任何形式引數都是“僅關鍵字”引數,這意味著它們只能用作關鍵字而不是位置引數
>>> def concat(*args, sep="/"):
... return sep.join(args)
...
>>> concat("earth", "mars", "venus")
'earth/mars/venus'
>>> concat("earth", "mars", "venus", sep=".")
'earth.mars.venus'
解壓縮引數列表
當引數已經在列表或元組中但需要為需要單獨位置引數的函式呼叫解包時,會發生相反的情況。例如,內建range()
函式需要單獨的 start和stop引數。如果它們不是單獨可用的,請使用*
-operator 編寫函式呼叫以 從列表或元組中解壓縮引數:
>>> list(range(3, 6)) # normal call with separate arguments
[3, 4, 5]
>>> args = [3, 6]
>>> list(range(*args)) # call with arguments unpacked from a list
[3, 4, 5]
以相同的方式,字典可以使用**
-operator 提供關鍵字引數:
>>> def parrot(voltage, state='a stiff', action='voom'):
... print("-- This parrot wouldn't", action, end=' ')
... print("if you put", voltage, "volts through it.", end=' ')
... print("E's", state, "!")
...
>>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}
>>> parrot(**d)
-- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !