函数中的可变参数列表 当函数调用可变个数的参数时,这些可变参数被包装进一个元组,在可变参数前,可以有0到多个普通的参数,多个参数用*作为前缀.
1 2 3 4 5 6 7 8 9 10 def write_multiple_items (file, separator, *args) : file.write(separator.join(args)) def concat (*args, sep="/" ) : return sep.join(args) concat("earth" , "mars" , "venus" ) 'earth/mars/venus' concat("earth" , "mars" , "venus" , sep="." ) 'earth.mars.venus'
相反的情况
要传递的参数已经是一个列表,但是调用的函数却接手分开一个个的参数值,这时候就要把已有的列表拆开,,可以在调用函数时加一个*
操作符来自动把参数列表拆开
1 2 3 4 5 list(range(3 , 6 )) [3 , 4 , 5 ] args = [3 ,6 ] list(range(*args)) [3 ,4 ,5 ]
以同样的方式,可以用**操作符拆关键字参数为字典
1 2 3 4 5 6 7 8 def parrot (voltage, state='a stiff' , action='voom' ) : print("-- This parrot wouldn't" , action, end=' ' ) print("if you put" , voltage, "volts through it." , end=' ' ) print("E's" , state, "!" ) d = {"voltage" : "four million" , "state" : "bleedin' demised" , "action" : "VOOM" } parrot(**d) --This parrot wouldn't VOOM if you put four million volts through it. E' s bleedin' demised !
迭代器 大部分容器对象都可以用for循环
1 2 3 4 5 6 7 8 9 10 for element in [1 , 2 , 3 ]: print(element) for element in (1 , 2 , 3 ): print(element) for key in {'one' :1 , 'two' :2 }: print(key) for char in "123" : print(char) for line in open("myfile.txt" ): print(line, end='' )
这种形式的访问清晰、简洁、方便。迭代器的用法在 Python 中普遍而且统一。在后台, for语句在容器对象中调用 iter() 。该函数返回一个定义了 __next__()
方法的迭代器对象,它在容器中逐一访问元素。没有后续的元素时, __next__()
抛出一个 StopIteration
异常通知 for
语句循环结束。你可以是用内建的 next()
函数调用 __next__()
方法;以下是其工作原理的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 s = 'abc' it = iter(s) it <iterator object at 0x00A1DB50 > next(it) 'a' next(it) 'b' next(it) 'c' next(it) Traceback (most recent call last): File "<stdin>", line 1, in ? next(it) StopIteration
了解了迭代器协议的后台机制,就可以给自己的类添加迭代器行为,定义一个__iter__()
方法,使其返回一个带有__next__()
方法的对象,如果这个类已经定义了__next__()
,那么__iter__()
只需要返回self.
1 2 3 4 5 6 7 8 9 10 11 12 13 class Reverse : """Iterator for looping over a sequence backwards.""" def __init__ (self, data) : self.data = data self.index = len(data) def __iter__ (self) : return self def __next__ (self) : if self.index == 0 : raise StopIteration self.index = self.index - 1 return self.data[self.index]
测试上面的类
1 2 3 4 5 6 7 8 9 10 rev = Reverse('spam' ) iter(rev) <__main__.Reverse object at 0x00A1DB50 > for char in rev: print(char) m a p s
生成器 在Python中,这种一边循环一边计算的机制,称为生成器:generator。
创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]
改成()
,就创建了一个generator.
第二种:如果一个函数定义中包含yield
关键字,那么这个函数就不再是一个普通函数,而是一个generator.
在执行过程中,遇到yield
就中断,下次又继续执行。
生成器Generator是创建迭代器简单而强大的工具,需要返回数据的时候使用yield语句,每次next()被调用时,生成器回复它脱离的位置.
1 2 3 def reverse (data) : for index in range(len(data)-1 , -1 , -1 ): yield data[index]
1 2 3 4 5 6 for char in reverse('golf' ): print(char) f l o g
前一节中描述了基于类的迭代器,它能作的每一件事生成器也能作到。因为自动创建了 iter () 和 next () 方法,生成器显得如此简洁。
*args 和 ** kw 补充 *args 代表多个参数,但是没有key值,**kw代表有多个参数的key值.
*args 1 2 3 4 5 def fun (f1, *args) : print "arg:" , f1 for value in args: print "another arg:" , value fun(1 , "two" , 3 )
1 2 3 arg: 1 another arg: two another arg: 3
**kw 1 2 3 4 5 6 def fun (*args,**kwargs) : for a1 in args: print(a1) for k1 in kwargs: print(k1,kwargs[k1]) fun(3 , 4 , 5 ,d=1 ,ff=2 ,v=34 )
装饰器 由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数。
1 2 3 4 5 def now () : print("2018" ) >>> f = now>>>f() 2018
函数对象有一个__name__
属性,可以拿到函数的名字
假设我们要增强now()
函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()
函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。
本质上,decorator就是一个返回函数的高阶函数。所以,我们要定义一个能打印日志的decorator,可以定义如下.
1 2 3 4 5 6 7 8 9 10 11 12 13 def use_logging (func) : def wrapper (*args, **kw) : print('call %s():' % func.__name__) func(*args, **kw) print("after" ) return return wrapper def bar () : print('i am bar' ) bar = use_logging(bar) bar()
函数use_logging就是装饰器,wrapper是组装的最终函数
1 2 3 call bar(): i am bar after
@符号是装饰器的语法糖,在定义函数的时候使用,避免再一次赋值操作
1 2 3 4 5 6 7 8 9 10 11 12 13 def use_logging (func) : def wrapper (*args, **kw) : print('call %s():' % func.__name__) func(*args, **kw) print("after" ) return return wrapper @use_logging def foo () : print('i am foo' ) @use_logging def bar () : print('i am bar' )
带参数的装饰器 装饰器语法允许在调用时,提供其他参数,可以在装饰器的外面再封装一层
1 2 3 4 5 6 7 8 9 10 def gaoceng_fengzhuang (参数) def use_logging (func) : def wrapper (*args, **kw) : print('call %s():' % func.__name__) func(*args, **kw) print("after" ) return return wrapper return use_logging
类装饰器 使用类装饰器还可以依靠内部的__call__
方法,当使用@形式将装饰器附加到函数上时,就会调用此方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Foo (Object) : def __init__ (self,func) : self.func =func def __call__ (self) : print('before' ) self.func() print('after' ) @Foo def bar () : print('bar' ) bar()