美文网首页
python(二)装饰器,迭代器,生成器

python(二)装饰器,迭代器,生成器

作者: 王大吉 | 来源:发表于2019-01-30 00:56 被阅读0次

    装饰器

    装饰器是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里 iternext源码基本是这样

    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...

    生成器

    相关文章

      网友评论

          本文标题:python(二)装饰器,迭代器,生成器

          本文链接:https://www.haomeiwen.com/subject/rjabxqtx.html