參數類型
Python函數的參數類型一共有五種,分別是:
- POSITIONAL_OR_KEYWORD(位置參數或關鍵字參數)
- VAR_POSITIONAL(可變參數)
- KEYWORD_ONLY(關鍵字參數)
- VAR_KEYWORD(可變關鍵字參數)
- POSITIONAL_ONLY(位置參數)
下面用舉幾個例子解釋一下這5個參數類型的含義:
POSITIONAL_OR_KEYWORD如其名所見,既可以用位置傳參,也可以用關鍵字傳參,並且他沒有任何*的聲明
>>> def foo(name): ... print(name) ... >>> foo("hello") hello >>> foo(name="hello") hello
VAR_POSITIONAL是可變參數,通過*來聲明,它會把接收到的值存入一個元組
>>> def foo(*args): ... print(args) ... >>> foo(1, 2, 3, 4, 5) (1, 2, 3, 4, 5)
KEYWORD_ONLY只能通過關鍵字傳參,這種參數會在VAR_POSITIONAL參數類型的后面,而且不帶**前綴,如同語義,只能通過指定關鍵字來傳參,不可以用位置傳參
>>> def foo(n1, *, n2): ... print(n1, n2) ... >>> foo("hello", n2="world") hello world
VAR_KEYWORD是可變關鍵字參數,通過前綴**來聲明,這種參數類型可以接收0個或多個參數,並存入一個字典
>>> def foo(**kwargs): ... for key, value in kwargs.items(): ... print("%s=%s" % (key, value)) ... >>> foo(a=1, b=2, c=3) a=1 b=2 c=3
POSITIONAL_ONLY是第五個參數類型,但是它已經不重要了,因為高版本的Python無法創建一個POSITIONAL_ONLY類型的參數,但是有些使用C語言實現且不接收關鍵字參數的函數(如divmod)支持
從下面的例子,我們可以看到,新定義的foo函數,每個參數都對應到上面的一個類型
>>> def foo(name, *args, middle=None, **kwargs): ... print("name:", name) ... print("args:", args) ... print("middle:", middle) ... print("kwargs:", kwargs) ... >>> foo("hello", 1, 2, 3, middle="world", a=1, b=2, c=3) name: hello args: (1, 2, 3) middle: world kwargs: {'a': 1, 'b': 2, 'c': 3} >>> my_foo = {"name": "hello", "middle": "world", "a": "1", "b": "2", "c": "3"} >>> foo(**my_foo) name: hello args: () middle: world kwargs: {'a': '1', 'b': '2', 'c': '3'} >>> from inspect import signature >>> sig = signature(foo) >>> for name, param in sig.parameters.items(): ... print(param.kind, ":", name, '=', param.default) ... POSITIONAL_OR_KEYWORD : name = <class 'inspect._empty'> VAR_POSITIONAL : args = <class 'inspect._empty'> KEYWORD_ONLY : middle = None VAR_KEYWORD : kwargs = <class 'inspect._empty'>
參數綁定
將函數的參數綁定到一個字典上
>>> def foo(name, *args, middle=None, **kwargs): ... print("name:", name) ... print("args:", args) ... print("middle:", middle) ... print("kwargs:", kwargs) ... >>> my_foo = {"name": "hello", "middle": "world", "a": "1", "b": "2", "c": "3"} >>> from inspect import signature >>> sig = signature(foo) >>> bound_args = sig.bind(**my_foo) >>> for name, value in bound_args.arguments.items(): ... print(name, '=', value) ... name = hello middle = world kwargs = {'a': '1', 'b': '2', 'c': '3'} >>> del my_foo["name"] >>> bound_args = sig.bind(**my_foo) Traceback (most recent call last): ... TypeError: missing a required argument: 'name'
在inspect模塊的幫助下,展示了Python數據模型把實參綁定給函數調用的形參的機制,這與解釋器使用的機制相同,當我們刪除字典中的name,執行時會報錯缺少name參數。
再者,我們使用operator模塊進行參數綁定
>>> from operator import methodcaller >>> s = "The time has come" >>> upcase = methodcaller("upper") >>> upcase(s) 'THE TIME HAS COME' >>> hiphenate = methodcaller("replace", " ", "-") >>> hiphenate(s) 'The-time-has-come'
如上,methodcaller創建的函數會在對象上調用參數指定的方法,我們可以自己建立一個對象並生成自己的方法,再用methodcaller調用
class Person: def __init__(self, name): self.name = name def say(self, text): print(self.name, 'say:', text) p = Person("John") person_say = methodcaller("say", "hello") person_say(p)
最后會打印:
John say: hello
使用function.partial凍結參數
function.partial這個高階函數用於部分應用函數,部分應用是指,基於一個函數創建一個新的可調用對象,把原函數的某些參數固定
>>> from operator import mul >>> from functools import partial >>> triple = partial(mul, 3) >>> triple(7) 21 >>> list(map(triple, range(1, 10))) [3, 6, 9, 12, 15, 18, 21, 24, 27]
如上,我們使用mul創建了triple函數,把第一個參數固定為3,然后返回一個可調用的對象,再傳入不同的參數