參數類型
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,然后返回一個可調用的對象,再傳入不同的參數
