美文网首页
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模块介绍

    functools.partial functools.partial 通过包装手法,允许我们 "重新定义" 函数...

  • python itertools

    PYTHON-进阶-ITERTOOLS模块小结

  • PYTHON-进阶-ITERTOOLS模块小结

    PYTHON-进阶-ITERTOOLS模块小结转自wklken:http://wklken.me/posts/20...

  • functools模块

    一.update_wrapper 该函数用于更新包装函数(wrapper),使它看起来像被包装的原函数一样。该函数...

  • functools模块

    1 functools函数 functools模块用于高阶函数:作用与或者返回其它函数的函数。一般来说,对于该模块...

  • functools

    functools模块里存放的是一些工具函数,在使用前需要导入functools模块,在python3.X中,可以...

  • Python @cache 简化无限缓存

    Python 内置模块 functools 提供的高阶函数 @functools.cache 是简单轻量级无长度限...

  • 那些Python方法---reduce()

    python3中reduce被放到了functools模块,所以用之前需要导入 from functools im...

  • Python 模块简介 -- functools

    Python 的 functools 模块可以说主要是为函数式编程而设计,用于增强函数功能。 functools....

  • functools 模块详解

    functool.reduce 方法是迭代的应用传入的方法用前面得到的值来作为输入,所以方法最好有两个以上的变量,...

网友评论

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

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