>>> from env_helper import info; info()
页面更新时间: 2023-12-27 09:27:37
运行环境:
    Linux发行版本: Debian GNU/Linux 12 (bookworm)
    操作系统内核: Linux-6.1.0-16-amd64-x86_64-with-glibc2.36
    Python版本: 3.11.2

3.15. 慎用变长参数

Python支持可变长度的参数列表,可以通过在函数定义的吋候使用 *args**kwargs 这两个特殊语法来实现 ( argskwargs 可以替换成任意你喜欢的变量名)。 先来看两个可变长 参数使用的例子。

3.15.1. 变长参数实例

使用 *args 来实现可变参数列表

*args 用于接受一个包装为元组形式的参数列表来 传递非关键字参数,参数个数可以任意,如下例所示。

>>> def SumFun(*args):
>>>     result = 0
>>>     for x in args[0:]:
>>>         result +=x
>>>     return result
>>> print( SumFun(2,4))
>>> print (SumFun(1,2,3,4,5))
>>> print (SumFun())
6
15
0

使用 kwargs 接受字典形式的关键字参数列表

其中字典的键值对分别表示不可变 参数的参数名和值。 如下例中 apple 表示参数名 tfruit 为其对应的 value , 可以是一个或者 多个键值对。

>>> def category_table (**kwargs) :
>>>     for name ,value in kwargs.items ():
>>>         print ('{0} is a kind of {1}'.format(name, value))
>>> category_table (apple = "fruit", carrot = 'vegetable',Python = 'programming language')
>>> category_table(BMW = 'Car')
apple is a kind of fruit
carrot is a kind of vegetable
Python is a kind of programming language
BMW is a kind of Car

如果一个函数中同时定义了普通参数、默认参数,以及上述两种形式的可变参数,那么 使用情况又是怎样的呢?来看一个简单的问题。

>>> def setaxis(x,y, xlabel="x", ylabel="y",*args, **kwargs):
>>>     pass

对于上面的函数下面几种调用方式哪些是不正确的呢?

>>>
>>> setaxis (2,3, "testl", "test2nr","test3", my_kwarg="test3")
>>> setaxis (2,3, "testl", my_kwarg="tGst3H" )
>>> setaxis ("testl","test2 ", xlabel="new_x", ylabel = "new_y", my_kwarg="test3f")
>>> setaxis (2,'test2f',fylabel = 'new_y',my_kwarg="test3M")

答案是:上面的所有调用方式都是合法的!实际上在4种不同形式的参数间时存在的情 况下.会首先满足普通参数1然后是默认参数,如果剩余的参数个数能够渑盖所有的默认参 数,则默认参数会使用传递时候的值,如标注①处的函数在调用的时候xlabel和ylabd的值 分别为“test1”和“test2”;如杲剩余参数个数不够,则尽最大可能满足默认参数的值,标 注②中xkbel值为而ylabd则使用默认参数y。除此之外其余的参数除了键值对以 外所有的参数都将作为args的可变参数,kwargs则与键值对对应。

3.15.2. 为什么慎用可变长度参数

那么,为什么要慎用可变长度参数呢?原因如下:

  1. 使用过于灵活。上面的示例 set_axis() 随随便便就能写出好几种不同形式的调用方 式。在混合普通参数或者默认参数的情况下,变长参数意味着这个函数的签名不够清晰,存 在多种调用方式。如果调用者需要花费过多的时间来研究你的方法该如何调用,显然这并不 是一种值得提倡的方式,即使你认为它很炫,很高端大气上档次,但在团队合作开发的项目 中,千万不要有这种想法,团队开发不是你的个人竞技场,代码编写从某种程度上说也是一 种沟通,清晰准确是一个很重要的指标。另外变长参数可能会破坏程序的健壮性。

  2. 如果一个函数的参数列表很长,虽然可以通过使用 argSMkwargs 来简化函数 的定义,但通常这意味着这个函数可以有更好的实现方式,应该被重构。前面的例子中 SumFun(*args) 如果改为 def Sum(seq) , 在3数调用之前将需要传递的参数保存在一个序列 中,如 seq = (l,2,3,4,5,6J) ,再将序列 seq 作为参数传人 Sum 中也是一个不错的选择。同样 如果使用 -kwargs 的目的仅仅是为了传人一个字典,这将是一个非常糟糕的选择。

3.15.3. 可变长参数适用情况

可变长参数适合在下列情况下使用(不仅限于以下场景):

为函数添加一个装饰器。

>>> def mydecorator (fun):
>>>     def new(*args,**kwarge):
>>>         return fun(*args,**kwarge)
>>>     return new

如果参数的数目不确定,可以考虑使用变长参数。如配置文件test.xfg内容如下:

(Defaults]

name = test version = 1.0 platform = windows

fun(**kcwargs)用于读取一些配罝文件中的值并进行全局变量初始化。

from ConfigParser import ConiigParser conf = ConfigParser() conf.read('test.cfg') ccmf_dict = diet(conf.items(•Defaults r)) def func(* *kwargs):

kwargs.update <c〇nf_dict) global name name =kwargs.get(* name ) global version version = kwargs.get ('version r) global platform platform = Jcwargs .get ( platform)

用来实现函数的多态或者在继承情况下子类需要调用父类的某些方法的时候。

>>>
>>> class A(object):
>>>      def somefun(self,pl,p2):
>>>            pass
>>> class B(A):
>>>     def myfun (self,*arg,**kwargs):
>>>         super(B,self) .somefun(*args,**kwargs)