接受任意数量参数的函数在Python中定义一个函数非常简单,例如一个计算2的幂的函数:defpower(x):returnx*x如果我们想要一个函数可以acceptanynumber如何定义函数的参数?例如,您想要一个接受一组数字并计算它们的平方值之和的函数。当然,你可以直接传递一个列表或元组作为函数参数:defsum_power(x):sum=0foriinx:sum+=i*ireturnsum但是如果你这样做,如果你想使用这个函数,你必须先创建一个列表或元组,这样调用它:sum_power([1,2,3,4])使用这个方法要简单得多:defsum_power(*x):sum=0foriinx:sum+=i*ireturnsum使用*开头的参数,那么这之后的位置参数会被当作一个序列。但是如果有一个列表arr=[1,2,3,4,5]呢?可以这样调用这个函数:sum_power(*arr)在调用函数的时候给list等参数加上一个*,相当于把list拆掉,把所有的元素都作为函数的参数传入。如果要使用任意数量的关键字参数,可以使用以**开头的参数。>>>defa(**attrs):...print(attrs)...>>>a(name="张三",age="18"){'name':'张三','age':'18'}>>>可以发现,**开头的参数被打包成字典进行处理。defa(*args,**kwargs):pass这样的函数可以接受任意数量的位置参数和关键字参数。定义关键字参数时,以*开头的参数必须是最后一个位置参数,以**开头的参数必须是最后一个参数。想想这是为什么?但是以*开头的参数后,仍然可以接收参数。如果在以*开头的函数后面加上一个关键字参数或者单独的*,这个参数就会变成一个关键字参数,只能使用word形式使用的key。例如:defperson(name,*,age):passperson("ZhangSan",12)#Error:TypeError:person()takes1positionalargumentbut2weregivenperson("ZhangSan",age=12)#True这时候用第一种方式调用函数会报错,必须使用关键字age=12。使用仅关键字参数可以提高代码的可读性。闭包(closure)有时候对于一些只有一个方法的类(__init__()除外),我们想用一个函数来代替它来简化代码。fromurllib.requestimporturlopenclassUrlTemplate:def__init__(self,template):self.template=templatedefopen(self,**kwargs):returnurlopen(self.template.format_map(kwargs))#Usageexampleyahoo=UrlTemplate('http://finance.yahoo.com/d/quotes.csv?s={names}&f={fields}')forlineinyahoo.open(names='IBM,AAPL,FB',fields='sllclv'):print(line.decode('utf-8'))这里的UrlTemplate类可以用一个函数代替:defurltemplate(template):defopener(**kwargs):returnurlopen(template.format_map(kwargs))returnopener#Useexampleyahoo=urltemplate('http://finance.yahoo.com/d/quotes.csv?s={names}&f={fields}')forlineinyahoo(names='IBM,AAPL,FB',fields='sllclv'):print(line.decode('utf-8'))闭包是嵌套函数,外层函数直接返回内层函数作为返回值。顾名思义,闭包就像一个包,它会记住定义闭包的环境。如示例中所示,opener()函数可以记住urltemplate()参数模板的值,并在后续调用中使用它。装饰器有时候我们想扩展函数的功能,但又不想修改函数的代码,这时就可以使用装饰器。装饰器本质上是一个函数(或类),它将一个函数作为输入并返回一个新函数作为输出。例如,我们现在需要在我们的函数中添加一个日志函数来打印出函数执行时间:“调用:{}”.format(func.__name__))start=time.time()result=func(*args,**kwargs)end=time.time()print(func.__name__,end-start)returnresultreturnwrapper#Usageexample@logdeff(x):whilex<1000000:x+=1Callingresult:>>>f(1)calling:ff0.11393427848815918>>>如果我们不使用装饰器,我们需要在f()函数中写代码的时候,不仅原来的函数变得面目全非,而且如果我们想在其他函数中加入录音功能,还得把代码复制过去,还不如使用装饰器方便。上面使用装饰器的部分本质上等同于:deff(x):...f=log(f)装饰器函数接受装饰后的函数作为参数,将原函数名的变量重新赋值给return后新功能。扫码关注公众号:
