装饰器
装饰器是python里比较重要的语法,虽然用的不算太多。但基本每个面python的都会问到。
首先一句话解释 装饰器是一个参数为函数的函数。
现在业务场景是要实现一个为每一个函数打印日志的工呢
来看具体实现
不正确的写法
def print_log(func):
print("print log")
return func()
def my_function():
# 具体业务逻辑
print("my_function")
pass
执行
>>> print_log(my_function)
print log
my_function
>>>
这种写法功能上能实现 但是每个业务逻辑都要再包一层print函数 太麻烦
简单装饰器
def print_log(func):
def wrapper(*args, **kwargs): # 1
print("print log") # 2
return func(*args, **kwargs) # 3
return wrapper # 4
可以这样执行
my_function = print_log(my_function) # 5
my_function() # 6
python有个专门的语法糖来处理my_function = print_log(my_function)
这段代码 在定义my_function时候这样写
@print_log
def my_function():
# 具体业务逻辑
print("my_function")
pass
这样之后直接调用my_function()
都是经过装饰器装饰的
我们来看一下装饰器里面是什么意思
装饰器print_log接受的是一个函数的指针 返回的是wrapper函数的指针(#4)所以 在(#5)的时候 my_function 其实就已经被赋值为wrapper函数了 已经不是以前的my_function函数了
再看wrapper函数里 接受任何参数(#1),打印日志(#2 装饰器本身应该干的活儿)返回一个func函数的执行结果(#3
所以(#6)的时候,相当于执行了函数warpper 也就是走了(#2,#3)这两个步骤,完成了装饰器的功能(#2),还执行了被装饰的函数(#3)
带参数装饰器
def print_log(msg):
def decorator(func):
def wrapper(*args, **kwargs):
print("print log")
return func(*args, **kwargs)
return wrapper
return decorator
调用
my_function = print_log(msg="my_message")(my_function)
my_function()
或者
@print_log(msg="my_message")
def my_function():
# 具体业务逻辑
print("my_function")
pass
更详细的可以参考
https://zhuanlan.zhihu.com/p/53837833
迭代器
先说迭代器的优点,举个例子来说 a=[1,2,3,4]
中,如果用 for ... in 语句,就不用直接访问a的下标,把容器(a) 的操作和底层彻底分开了
迭代器要明白两个概念 可迭代对象和迭代器
笼统的讲,可以用for ... in 遍历的都是可迭代对象 比如 list, tupe等
准确的讲,内置有__iter__
方法的 就叫可迭代对象
内置有next
方法的,就叫迭代器
>>> dir([])
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
>>> dir({})
['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values', 'viewitems', 'viewkeys', 'viewvalues']
>>> dir(())
['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getslice__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'index']
>>>
可以看到 list tupe dict都有__iter__
方法
我们可以用可迭代对象来生成迭代器 用iter
函数
a = [1,2,3,4,5]
因为a有__iter__
方法 所以a就是个可迭代对象
b = iter(a)
b就是个迭代器 下面用next访问b
>>> next(b)
1
>>> next(b)
2
>>> next(b)
3
>>> next(b)
4
>>> next(b)
5
>>> next(b)
Traceback (most recent call last):
File "<console>", line 1, in <module>
StopIteration
所有的这一切,都被封装在了 for ... in 里
也就是说,执行for ... in 的时候 会先用可迭代对象创建为一个迭代器, 然后用next一直访问 直到抛出StopIteration异常
在python里 iter
和 next
源码基本是这样
def iter(obj):
return obj.__iter__()
#Python 2.X
def next(obj):
return obj.next()
#Python 3.X
def next(obj):
return obj.__next__()
下面是自己实现一个迭代器和迭代对象的代码
import random
class demo_iterator(object):
def __next__(self):
return self.next()
def next(self):
v = random.randint(0,10)
if v < 5:
raise StopIteration()
else:
return v
class demo_iterable(object):
def __iter__(self):
return demo_iterator()
for v in demo_iterable():
print(v)
这个迭代器有随机的长度。测试它的方法就用for...in...
网友评论