目录
Python参数种类
Python参数定义
不定参数接收
限定传入参数方式
具体示例
位置参数示例
关键词参数示例
两种方法都支持的形式
参数默认值(可选参数)
参数默认值定义
引用类型默认值异常行为
参数类型声明
参数类型定义申明
函数返回值类型声明
参数与装饰器
Python参数种类
总体来看,Python支持两种类型的方法参数,其类型分别为:
- 位置参数(Positional Parameters)
- 关键词参数(Keyword Parameters)
然后我们看下参数的传递形式,假如有如下函数定义:
def f(a,b,c):...
如果我们通过如下方式调用,则称为位置参数:
f(1,2,3)
# 这里的 1,2,3 分别对应位置 a,b,c ,故这里是位置参数 args=[1,2,3]
f(*args)
如果我们通过如下方式调用,则称为关键词参数。这种方式下,我们不用关心参数位置,而是使用显示指定的方式指定每个参数的值,相比之下,这种方式更明确每个参数的值。
f(b=2,c=3,a=1)
# 或者
kwargs = {"b":2,"c":3,"a":1}
f(**kwargs)
⚠️当我们在给定参数时候,关键词参数后,不可跟位置参数,即如下调用方式是错误的
>>> f(2,b=3,1)
SyntaxError: positional argument follows keyword argument
Python参数定义
不定参数接收
最常见的形式:
def f(*args,**kwargs):...
其中,args
用于接收位置参数,即args
类型是列表;kwargs
用于接收keyword参数,即kwargs
是一个字典。
限定传入参数方式
从官方给的这个示例说起
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):----------- ---------- ----------| | || 位置参数/关键词参数 || - 只能关键词参数-- 只能是位置参数
根据上述示例,不难看出,在方法定义的时候,我们可以通过特定的两个符号/
和*
将参数分开。即/
前面的只能是未知参数,/
与*
之间的参数即可使位置参数,也可以是关键词参数,*
后面的参数必须是关键词参数。
考虑到不定参数同时存在的情况,支持如下定义形式
def f(a,/,b,c,*args,**kwargs):...
# 或
def f(a,/,b,c,*args):...
# 或
def f(a,/,b,c,**kwargs):...
# 或
ef f(a,/,b,c,*,d,**kwargs):...
具体示例
位置参数示例
方法定义:
def f(pos1,pos2,/):...
正确调用方式
f(1,2)
错误调用方式及其报错
>>> f(1,pos2=2)
TypeError: f() got some positional-only arguments passed as keyword arguments: 'pos2'
>>> f(pos1=1,pos2=2)
TypeError: f() got some positional-only arguments passed as keyword arguments: 'pos1, pos2'
关键词参数示例
方法定义
def f(*,pos1,pos2):...
正确调用方式
>>> f(pos1=1,pos2=2)
错误调用方式及其异常
>>> f(1,2)
TypeError: f() takes 0 positional arguments but 2 were given
>>> f(1,pos2=2)
TypeError: f() takes 0 positional arguments but 1 positional argument (and 1 keyword-only argument) were given
两种方法都支持的形式
方法定义
def f(a,/,pos1,pos2,*,b):...
⚠️ 如下方式定义会抛出异常
>>> def f(/,pos1,pos2,*):...
SyntaxError: invalid syntax
# / 前面必须有参数, * 后面必须有参数
正确调用方式
>>> f(1,2,3,b=4)
>>> f(1,2,pos2=3,b=4)
参数默认值(可选参数)
Python中,给定默认值的参数都是可选参数。
参数默认值定义
Python函数定义的时候,按照参数顺序,从第一个给定默认值之后的参数之后,必须提供默认值
def f(a=1,b=2,c=None):...
异常定义及其错误
>>> def f(a,b=2,c):...
def f(a,b=2,c):^
SyntaxError: non-default argument follows default argument
引用类型默认值异常行为
有的时候,你可能需传入一个默认的列表,如
def f(a:list=[]):a.append(1)return a
当我们如下操作,会发现第二次的输出并不是我们希望的
f() # 输出 [1]
f() # 输出 [1, 1]
正确应该采用如下方式定义
def f(a: list = None):if a is None:a = []a.append(1)return a# 字典参数的情况
def f(a: dict = None):if a is None:a = {}
参数类型声明
Python是动态类型语言,其变量的类型在运行时才确定。虽然这种灵活性为开发者带来了方便,但也可能导致代码在运行时发生类型错误。为了提高代码的可维护性和可读性,Python 3.5及以上版本引入了类型提示(Type Hints)。
参数类型定义申明
在函数定义时,可以使用冒号**:
**来指定参数的类型
def greet(name: str):return "Hello, " + name
函数返回值类型声明
我们可以使用**->
**符号来指定函数的返回值类型。例如
def add(x: int, y: int) -> int:return x + y
其他类型参数声明参考typing
库。
参数与装饰器
首先,我们定义了一系列实用的装饰器,用于测量函数的执行时间。接着,我们定义了几个简单的函数,其中包括不同类型的参数和使用了不同装饰器的函数。
import inspect
from functools import wrapsdef timeit(func):import time@wraps(func)def wrapper(*args, **kwargs):start = time.time()func(*args, **kwargs)print(f"cost time: {time.time() - start}")return wrapperdef timeit1(name):def _timeit(func):import time@wraps(func)def wrapper(*args, **kwargs):start = time.time()func(*args, **kwargs)print(f"{name} cost time: {time.time() - start}")return wrapperreturn _timeitdef timeit2(name):def _timeit(func):import time@wraps(func)def wrapper(param1, param2, param3):start = time.time()func(param1, param2, param3)print(f"{name} cost time: {time.time() - start}")return wrapperreturn _timeitdef func1(param1, param2, param3):print(param1, param2, param3)@timeit
def func2(param1, param2, param3):print(param1, param2, param3)@timeit1("func3")
def func3(param1, param2, param3):print(param1, param2, param3)@timeit2("func4")
def func4(param1, param2, param3):print(param1, param2, param3)def call_func(func):arg_spect = inspect.getfullargspec(func)print(f"arg_spect: {arg_spect}")...>>> call_func(func1)
arg_spect: FullArgSpec(args=['param1', 'param2', 'param3'], varargs=None, varkw=None, defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={})
-------------------->>> call_func(func2)
arg_spect: FullArgSpec(args=[], varargs='args', varkw='kwargs', defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={})
-------------------->>> call_func(func3)
arg_spect: FullArgSpec(args=[], varargs='args', varkw='kwargs', defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={})
-------------------->>> call_func(func4)
arg_spect: FullArgSpec(args=['param1', 'param2', 'param3'], varargs=None, varkw=None, defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={})
--------------------
通过上述结果,我们可以看到不同类型的函数具有不同的参数信息。对于普通的函数,我们可以通过 inspect.getfullargspec
来获取其参数信息。而对于使用了装饰器的函数,装饰器的实现方式会影响inspect.getfullargspec
方法获取实际的参数信息。