Python基础之:函数
文章目錄
- 簡介
- 內(nèi)置函數(shù)
- 自定義函數(shù)
- 參數(shù)的默認(rèn)值
- 關(guān)鍵字參數(shù)
- 特殊參數(shù)
- 參數(shù)解包
- Lambda
- 函數(shù)標(biāo)注
簡介
函數(shù)是結(jié)構(gòu)化編程的基礎(chǔ),也是代碼復(fù)用的基石。Python中通過def來自定義函數(shù)。本文將會深入探索Python中函數(shù)的秘密。
內(nèi)置函數(shù)
除了用戶的自定義函數(shù)之外,Python內(nèi)置了一些非常有用的函數(shù):
| abs() | delattr() | hash() | memoryview() | set() |
| all() | dict() | help() | min() | setattr() |
| any() | dir() | hex() | next() | slice() |
| ascii() | divmod() | id() | object() | sorted() |
| bin() | enumerate() | input() | oct() | staticmethod() |
| bool() | eval() | int() | open() | str() |
| breakpoint() | exec() | isinstance() | ord() | sum() |
| bytearray() | filter() | issubclass() | pow() | super() |
| bytes() | float() | iter() | print() | tuple() |
| callable() | format() | len() | property() | type() |
| chr() | frozenset() | list() | range() | vars() |
| classmethod() | getattr() | locals() | repr() | zip() |
| compile() | globals() | map() | reversed() | __import__() |
| complex() | hasattr() | max() | round() |
自定義函數(shù)
Python中使用def來定義函數(shù),并使用return來返回特定的值。
看一個(gè)簡單的函數(shù)的例子:
def my_function(x, y, z):if z > 1:return z * (x + y)else:return z / (x + y)把我們之前講的斐波拉赫數(shù)列的例子重新用函數(shù)來定義,可以這樣寫:
def fib(n): a, b = 0, 1while a < n:print(a, end=' ')a, b = b, a+bprint()# 調(diào)用函數(shù) fib(1000)函數(shù)的內(nèi)容需要使用空格或者tab來進(jìn)行縮進(jìn)。
參數(shù)的默認(rèn)值
在Python中,我們可以給參數(shù)設(shè)置默認(rèn)值,這樣如果在函數(shù)調(diào)用的過程中沒有傳遞參數(shù)的時(shí)候,就會使用默認(rèn)值作為參數(shù)。
在我們之前定義的函數(shù)my_function中,我們可以給z設(shè)置一個(gè)默認(rèn)值:
def my_function(x, y, z=10):if z > 1:return z * (x + y)else:return z / (x + y)這樣我們在調(diào)用my_function可以只用傳遞兩個(gè)參數(shù),最后的z可以使用默認(rèn)的參數(shù)值。
注意,默認(rèn)值只會執(zhí)行一次,如果你傳入的參數(shù)是可變對象(列表,字典和類實(shí)例)的話,我們需要注意這個(gè)問題:
def f(a, L=[]):L.append(a)return Lprint(f(1)) print(f(2)) print(f(3))# 輸出 [1] [1, 2] [1, 2, 3]如果不想在后面的調(diào)用中共享默認(rèn)值,那么可以把默認(rèn)值的賦值放到函數(shù)體內(nèi)部:
def f(a, L=None):if L is None:L = []L.append(a)return L關(guān)鍵字參數(shù)
我們可以使用key=value的方式對函數(shù)進(jìn)行調(diào)用。
還是前面的函數(shù):
def my_function(x, y, z=10):if z > 1:return z * (x + y)else:return z / (x + y)我們可以這樣調(diào)用:
my_function(1,y=3,z=5) my_function(1,y=3)但是不能這樣用:
my_function(y=3,1)關(guān)鍵字的參數(shù)必須要放在非關(guān)鍵詞參數(shù)的后面。也不能對參數(shù)進(jìn)行多次賦值:
>>> 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'通過上面的討論我們可以看出,Python函數(shù)中的參數(shù)有兩種,一種是帶默認(rèn)值的參數(shù),一種是不帶默認(rèn)值的參數(shù)。
注意,不帶默認(rèn)值的參數(shù)一定要在帶默認(rèn)值的參數(shù)之前 。
看一個(gè)錯(cuò)誤的例子:
In [69]: def fa(a=100,b,c=200):...: passFile "<ipython-input-69-d5678b64f352>", line 1def fa(a=100,b,c=200):^ SyntaxError: non-default argument follows default argument而向函數(shù)傳遞參數(shù)也有兩種方式,一種是不帶關(guān)鍵字的傳遞,一種是帶關(guān)鍵字的傳遞。
注意,非關(guān)鍵詞參數(shù)的傳遞一定要在關(guān)鍵詞參數(shù)傳遞之前。
舉個(gè)錯(cuò)誤的例子:
In [70]: def fa(a,b=100,c=200):...: pass...:In [71]: fa(a=100,30)File "<ipython-input-71-5a229b8e420e>", line 1fa(a=100,30)^ SyntaxError: positional argument follows keyword argument那么問題來了,如果有多個(gè)關(guān)鍵詞參數(shù)和多個(gè)非關(guān)鍵詞參數(shù),有沒有簡便的方法來定義這樣的函數(shù)呢?
有的,那就是 *arguments 和 **keywords
*arguments用來接收所有多余的非關(guān)鍵詞參數(shù)。而**keywords用來接收所有額外的關(guān)鍵詞參數(shù)。
注意,*arguments一定要出現(xiàn)在 **keywords 的前面。
舉個(gè)例子:
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])我們可以這樣調(diào)用:
cheeseshop("Limburger", "It's very runny, sir.","It's really very, VERY runny, sir.",shopkeeper="Michael Palin",client="John Cleese",sketch="Cheese Shop Sketch")將會得到下面的結(jié)果:
-- 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特殊參數(shù)
函數(shù)可以按位置傳參,可以按照關(guān)鍵詞傳參,也可以混合傳參。
在某些情況下,我們可能需要限制傳參的類型,比如只接收按位置傳遞,只接收按關(guān)鍵詞傳遞,或者只接受混合傳遞。
看下特殊參數(shù)的定義:
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):----------- ---------- ----------| | || 按位置或者關(guān)鍵詞 || - 只允許按關(guān)鍵詞傳遞-- 只允許按位置傳遞注意,參數(shù)之間是以 / 和 * 來進(jìn)行區(qū)分的。
我們舉個(gè)例子:
>>> def standard_arg(arg): ... print(arg) ... >>> def pos_only_arg(arg, /): ... print(arg) ... >>> def kwd_only_arg(*, arg): ... print(arg) ... >>> def combined_example(pos_only, /, standard, *, kwd_only): ... print(pos_only, standard, kwd_only)上面定義了4種傳參方式的函數(shù)。
第一個(gè)函數(shù)就是標(biāo)準(zhǔn)形式,可以按位置傳遞,也可以按關(guān)鍵詞傳遞。
第二個(gè)函數(shù)只允許按照位置傳遞。
第三個(gè)函數(shù)只允許按照關(guān)鍵詞來傳遞。
第四個(gè)函數(shù)是混合模式。
參數(shù)解包
有時(shí)候我們需要將列表或者字典的值轉(zhuǎn)換為函數(shù)的參數(shù)。那么就需要用到參數(shù)解包的功能。
* 操作符 可以用來解包列表和元組。
>>> 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]** 操作符 可以用來解包字典。
>>> 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)Lambda
熟悉java的朋友可能知道,在JDK8中,Java引入了Lambda表達(dá)式。同樣的Python中也有Lambda。
你可以將Lambda看做是匿名函數(shù)。可以在任何需要函數(shù)的地方使用Lambda表達(dá)式。
看一個(gè)Lambda的例子:
>>> def make_incrementor(n): ... return lambda x: x + n ... >>> f = make_incrementor(42) >>> f(0) 42 >>> f(1) 43還可以將lambda的返回值作為參數(shù):
>>> pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')] >>> pairs.sort(key=lambda pair: pair[1]) >>> pairs [(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]函數(shù)標(biāo)注
之前我們討論的是簡單的自定義函數(shù)形式,我們并不知道函數(shù)的參數(shù)類型和返回值類型,其實(shí)函數(shù)可以寫得更加詳細(xì)一些,這就要用到函數(shù)標(biāo)注了。
所謂函數(shù)標(biāo)注就是用戶自定義函數(shù)中的類型的可選元數(shù)據(jù)信息。
函數(shù)標(biāo)注是以字典的形式存放在 __annotations__ 屬性中的。我們在參數(shù)的名稱后面加上冒號,后面跟一個(gè)表達(dá)式,那么這個(gè)表達(dá)式會被求值為標(biāo)注的值。對于返回值來說,返回值標(biāo)注的定義是加上一個(gè)組合符號 ->,后面跟一個(gè)表達(dá)式,該標(biāo)注位于形參列表和表示 def 語句結(jié)束的冒號之間。
舉個(gè)例子:
>>> def f(ham: str, eggs: str = 'eggs') -> str: ... print("Annotations:", f.__annotations__) ... print("Arguments:", ham, eggs) ... return ham + ' and ' + eggs ... >>> f('spam') Annotations: {'ham': <class 'str'>, 'return': <class 'str'>, 'eggs': <class 'str'>} Arguments: spam eggs 'spam and eggs'其實(shí)使用函數(shù)標(biāo)注寫出來的程序更加清晰,可讀性更高。
本文已收錄于 http://www.flydean.com/05-python-function/
最通俗的解讀,最深刻的干貨,最簡潔的教程,眾多你不知道的小技巧等你來發(fā)現(xiàn)!
歡迎關(guān)注我的公眾號:「程序那些事」,懂技術(shù),更懂你!
總結(jié)
以上是生活随笔為你收集整理的Python基础之:函数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AI数学基础之:概率和上帝视角
- 下一篇: Python基础之:Python中的模块