美文网首页
Python-进阶-functools模块介绍

Python-进阶-functools模块介绍

作者: 笨手笨脚越 | 来源:发表于2017-07-19 14:09 被阅读64次

    functools.partial

    functools.partial 通过包装手法,允许我们 "重新定义" 函数签名
    用一些默认参数包装一个可调用对象,返回结果是可调用对象,并且可以像原始对象一样对待
    冻结部分函数位置函数或关键字参数,简化函数,更少更灵活的函数参数调用
    应用:
    典型的,函数在执行时,要带上所有必要的参数进行调用。
    然后,有时参数可以在函数被调用之前提前获知。
    这种情况下,一个函数有一个或多个参数预先就能用上,以便函数能用更少的参数进行调用。

    import functools
    
    def add(a, b):
        return a + b
    
    if __name__ == '__main__':
        print add(3, 4)
        plus9 = functools.partial(add, 9)
        print plus9(11)
        plus7 = functools.partial(add, 5)
        print plus7(4)
        
    C:\Python27\python.exe D:/wangyueWorkspace/mytest/functiontools/test1.py
    7
    20
    9
    

    functool.update_wrapper

    默认partial对象没有namedoc

    def wrap(func):
        def call_it(*args, **kwargs):
            """wrap func: call it"""
            print 'before call'
            return func(*args, **kwargs)
        return call_it
    
    @wrap
    def hello():
        """hello"""
        print 'hello world!'
        
    if __name__ == '__main__':
        hello()
        print hello.__name__
        print hello.__doc__
        
    C:\Python27\python.exe D:/wangyueWorkspace/mytest/functiontools/test2.py
    before call
    hello world!
    call_it
    wrap func: call it
    

    使用update_wrapper可以把被封装函数的name、module、docdict都复制到封装函数去(模块级别常量WRAPPER_ASSIGNMENTS, WRAPPER_UPDATES)

    
    from functools import update_wrapper
    
    def wrap2(func):
        def call_it(*args, **kwargs):
            """wrap2 func: call it"""
            print 'before call2'
            return func(*args, **kwargs)
        return update_wrapper(call_it, func)
    
    @wrap2
    def hello2():
        """hello2 test
        aaaaaaaaaaaaa
        asdfasdfad
        """
        print 'hello world2!'
    
    
    if __name__ == '__main__':
        hello2()
        print hello2.__name__
        print hello2.__doc__
        
    C:\Python27\python.exe D:/wangyueWorkspace/mytest/functiontools/test2.py  
    before call2
    hello world2!
    hello2
    hello2 test
    aaaaaaaaaaaaa
    asdfasdfad
    

    这个函数主要用在装饰器函数中,装饰器返回函数反射得到的是包装函数的函数定义而不是原始函数定义

    functool.wraps

    调用函数装饰器partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated)的简写。

    from functools import wraps, update_wrapper
    
    def mywrap(func):
        @wraps(func)
        def call_it(*args, **kwargs):
            """wrap func: call_it2"""
            print 'before call'
            return func(*args, **kwargs)
    
        update_wrapper(call_it, func)
        return call_it
    
    
    @mywrap
    def hello():
        """test hello"""
        print 'hello'
    
    
    if __name__ == '__main__':
        hello()
        print hello.__name__
        print hello.__doc__
    
    

    运行效果可知,functool.wraps装饰器和update_wrapper函数其实效果是一样的,都是把被封装函数的__name__、module、__doc__和 __dict__都复制到封装函数去。

    问题:

    ==但是很奇怪,在cinder的代码里,同时用了这两个东西,不懂事为什么???==

    def _retry_on_deadlock(f):
        """Decorator to retry a DB API call if Deadlock was received."""
    
        @functools.wraps(f)
        def wrapped(*args, **kwargs):
            while True:
                try:
                    return f(*args, **kwargs)
                except db_exc.DBDeadlock:
                    LOG.warning(_LW("Deadlock detected when running "
                                    "'%(func_name)s': Retrying..."),
                                dict(func_name=f.__name__))
                    # Retry!
                    time.sleep(0.5)
                    continue
    
        functools.update_wrapper(wrapped, f)
        return wrapped
    

    这里补充下:
    __name__、__doc__和 __dict__的作用:

    1. 在python中,当一个module作为整体被执行时,moduel.__name__`的值将是"__ main__";而当一个 module被其它module引用时,module.__name__将是module自己的名字
    >>> print dir.__name__
    dir
    >>> print __name__
    __main__
    
    1. 每个函数都是一个对象,每个函数对象都是有一个__doc__的属性,函数语句中,如果第一个表达式是一个string,这个函数的__doc__就是这个string,否则__doc__是None。其实就是函数注释~~
    >>> def hello():
    ...     """hello function lalalal"""
    ...     print 'hello world'
    ...
    >>>
    >>> print hello.__doc__
    hello function lalalal
    
    1. __dict__是一个字典,键是属性名,值为属性值。Python的实例有自己的__dict__,它对应的类也有自己的__dict__
    >>> print file.__dict__
    {'softspace': <attribute 'softspace' of 'file' objects>, 'encoding': <member 'encoding' of 'file' objects>, 'xreadlines': <method 'xreadlines' of 'file' objects>, 'readlines': <method 'readlines' of 'file' objects>, 'flush': <method 'flush' of 'file' objects>, 'close': <method 'close' of 'file' objects>, 'seek': <method 'seek' of 'file' objects>, '__init__': <slot wrapper '__init__' of 'file' objects>, 'newlines': <attribute 'newlines' of 'file' objects>, '__setattr__': <slot wrapper '__setattr__' of 'file' objects>, 'errors': <member 'errors' of 'file' objects>, '__new__': <built-in method __new__ of type object at 0x7f220ba9cd20>, 'readinto': <method 'readinto' of 'file' objects>, '__enter__': <method '__enter__' of 'file' objects>, 'next': <slot wrapper 'next' of 'file' objects>, 'write': <method 'write' of 'file' objects>, 'closed': <attribute 'closed' of 'file' objects>, 'tell': <method 'tell' of 'file' objects>, 'mode': <member 'mode' of 'file' objects>, '__exit__': <method '__exit__' of 'file' objects>, 'isatty': <method 'isatty' of 'file' objects>, 'truncate': <method 'truncate' of 'file' objects>, 'read': <method 'read' of 'file' objects>, '__getattribute__': <slot wrapper '__getattribute__' of 'file' objects>, '__iter__': <slot wrapper '__iter__' of 'file' objects>, 'readline': <method 'readline' of 'file' objects>, 'fileno': <method 'fileno' of 'file' objects>, 'writelines': <method 'writelines' of 'file' objects>, 'name': <member 'name' of 'file' objects>, '__doc__': "file(name[, mode[, buffering]]) -> file object\n\nOpen a file.  The mode can be 'r', 'w' or 'a' for reading (default),\nwriting or appending.  The file will be created if it doesn't exist\nwhen opened for writing or appending; it will be truncated when\nopened for writing.  Add a 'b' to the mode for binary files.\nAdd a '+' to the mode to allow simultaneous reading and writing.\nIf the buffering argument is given, 0 means unbuffered, 1 means line\nbuffered, and larger numbers specify the buffer size.  The preferred way\nto open a file is with the builtin open() function.\nAdd a 'U' to mode to open the file for input with universal newline\nsupport.  Any line ending in the input file will be seen as a '\\n'\nin Python.  Also, a file so opened gains the attribute 'newlines';\nthe value for this attribute is one of None (no newline read yet),\n'\\r', '\\n', '\\r\\n' or a tuple containing all the newline types seen.\n\n'U' cannot be combined with 'w' or '+' mode.\n", '__delattr__': <slot wrapper '__delattr__' of 'file' objects>, '__repr__': <slot wrapper '__repr__' of 'file' objects>}
    
    

    参考:

    Python-进阶-functools模块小结

    相关文章

      网友评论

          本文标题:Python-进阶-functools模块介绍

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