Python基础之:函数
文章目錄
- 簡介
- 內置函數
- 自定義函數
- 參數的默認值
- 關鍵字參數
- 特殊參數
- 參數解包
- Lambda
- 函數標注
簡介
函數是結構化編程的基礎,也是代碼復用的基石。Python中通過def來自定義函數。本文將會深入探索Python中函數的秘密。
內置函數
除了用戶的自定義函數之外,Python內置了一些非常有用的函數:
| 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() |
自定義函數
Python中使用def來定義函數,并使用return來返回特定的值。
看一個簡單的函數的例子:
def my_function(x, y, z):if z > 1:return z * (x + y)else:return z / (x + y)把我們之前講的斐波拉赫數列的例子重新用函數來定義,可以這樣寫:
def fib(n): a, b = 0, 1while a < n:print(a, end=' ')a, b = b, a+bprint()# 調用函數 fib(1000)函數的內容需要使用空格或者tab來進行縮進。
參數的默認值
在Python中,我們可以給參數設置默認值,這樣如果在函數調用的過程中沒有傳遞參數的時候,就會使用默認值作為參數。
在我們之前定義的函數my_function中,我們可以給z設置一個默認值:
def my_function(x, y, z=10):if z > 1:return z * (x + y)else:return z / (x + y)這樣我們在調用my_function可以只用傳遞兩個參數,最后的z可以使用默認的參數值。
注意,默認值只會執行一次,如果你傳入的參數是可變對象(列表,字典和類實例)的話,我們需要注意這個問題:
def f(a, L=[]):L.append(a)return Lprint(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關鍵字參數
我們可以使用key=value的方式對函數進行調用。
還是前面的函數:
def my_function(x, y, z=10):if z > 1:return z * (x + y)else:return z / (x + y)我們可以這樣調用:
my_function(1,y=3,z=5) my_function(1,y=3)但是不能這樣用:
my_function(y=3,1)關鍵字的參數必須要放在非關鍵詞參數的后面。也不能對參數進行多次賦值:
>>> 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函數中的參數有兩種,一種是帶默認值的參數,一種是不帶默認值的參數。
注意,不帶默認值的參數一定要在帶默認值的參數之前 。
看一個錯誤的例子:
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而向函數傳遞參數也有兩種方式,一種是不帶關鍵字的傳遞,一種是帶關鍵字的傳遞。
注意,非關鍵詞參數的傳遞一定要在關鍵詞參數傳遞之前。
舉個錯誤的例子:
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那么問題來了,如果有多個關鍵詞參數和多個非關鍵詞參數,有沒有簡便的方法來定義這樣的函數呢?
有的,那就是 *arguments 和 **keywords
*arguments用來接收所有多余的非關鍵詞參數。而**keywords用來接收所有額外的關鍵詞參數。
注意,*arguments一定要出現在 **keywords 的前面。
舉個例子:
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 f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):----------- ---------- ----------| | || 按位置或者關鍵詞 || - 只允許按關鍵詞傳遞-- 只允許按位置傳遞注意,參數之間是以 / 和 * 來進行區分的。
我們舉個例子:
>>> 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種傳參方式的函數。
第一個函數就是標準形式,可以按位置傳遞,也可以按關鍵詞傳遞。
第二個函數只允許按照位置傳遞。
第三個函數只允許按照關鍵詞來傳遞。
第四個函數是混合模式。
參數解包
有時候我們需要將列表或者字典的值轉換為函數的參數。那么就需要用到參數解包的功能。
* 操作符 可以用來解包列表和元組。
>>> 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表達式。同樣的Python中也有Lambda。
你可以將Lambda看做是匿名函數。可以在任何需要函數的地方使用Lambda表達式。
看一個Lambda的例子:
>>> def make_incrementor(n): ... return lambda x: x + n ... >>> f = make_incrementor(42) >>> f(0) 42 >>> f(1) 43還可以將lambda的返回值作為參數:
>>> 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')]函數標注
之前我們討論的是簡單的自定義函數形式,我們并不知道函數的參數類型和返回值類型,其實函數可以寫得更加詳細一些,這就要用到函數標注了。
所謂函數標注就是用戶自定義函數中的類型的可選元數據信息。
函數標注是以字典的形式存放在 __annotations__ 屬性中的。我們在參數的名稱后面加上冒號,后面跟一個表達式,那么這個表達式會被求值為標注的值。對于返回值來說,返回值標注的定義是加上一個組合符號 ->,后面跟一個表達式,該標注位于形參列表和表示 def 語句結束的冒號之間。
舉個例子:
>>> 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'其實使用函數標注寫出來的程序更加清晰,可讀性更高。
本文已收錄于 http://www.flydean.com/05-python-function/
最通俗的解讀,最深刻的干貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!
歡迎關注我的公眾號:「程序那些事」,懂技術,更懂你!
總結
以上是生活随笔為你收集整理的Python基础之:函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AI数学基础之:概率和上帝视角
- 下一篇: 密码学系列之:内容嗅探