标签:tools xxx original ext elf apply use wrap key
functools.wrapper()首先对于最简单的函数:
def a():
	pass
if __name__ == ‘__main__‘:
	print(a.__name__)
输出结果:
a
然后稍微复杂点:
def a(func):
	def wrapper()
		return func
@a
def b():
	pass
if __name__ == ‘__main__‘
	print(b.__name__)
输出结果:
a
当加上functools.wrapper时:
def a(func):
	@functools.wrapper(func)
	def wrapper()
		return func
@a
def b():
	pass
if __name__ == ‘__main__‘
	print(b.__name__)
输出结果:
b
很明显,通过调用functools.wrapper()使得返回值发生了改变,这其实与它的函数定义有关,代码如下:
def wraps(wrapped,
          assigned = WRAPPER_ASSIGNMENTS,
          updated = WRAPPER_UPDATES):
    """Decorator factory to apply update_wrapper() to a wrapper function
       Returns a decorator that invokes update_wrapper() with the decorated
       function as the wrapper argument and the arguments to wraps() as the
       remaining arguments. Default arguments are as for update_wrapper().
       This is a convenience function to simplify applying partial() to
       update_wrapper().
    """
    return partial(update_wrapper, wrapped=wrapped,
                   assigned=assigned, updated=updated)
def update_wrapper(wrapper,
                   wrapped,
                   assigned = WRAPPER_ASSIGNMENTS,
                   updated = WRAPPER_UPDATES):
    """Update a wrapper function to look like the wrapped function
       wrapper is the function to be updated
       wrapped is the original function
       assigned is a tuple naming the attributes assigned directly
       from the wrapped function to the wrapper function (defaults to
       functools.WRAPPER_ASSIGNMENTS)
       updated is a tuple naming the attributes of the wrapper that
       are updated with the corresponding attribute from the wrapped
       function (defaults to functools.WRAPPER_UPDATES)
    """
    for attr in assigned:
        try:
            value = getattr(wrapped, attr)
        except AttributeError:
            pass
        else:
            setattr(wrapper, attr, value)
    for attr in updated:
        getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
        # Issue #17482: set __wrapped__ last so we don‘t inadvertently copy it
    # from the wrapped function when updating __dict__
    wrapper.__wrapped__ = wrapped
    # Return the wrapper so this can be used as a decorator via partial()
    return wrapper
class partial:
    """New function with partial application of the given arguments
    and keywords.
    """
    __slots__ = "func", "args", "keywords", "__dict__", "__weakref__"
    def __new__(cls, func, /, *args, **keywords):
        if not callable(func):
            raise TypeError("the first argument must be callable")
        if hasattr(func, "func"):
            args = func.args + args
            keywords = {**func.keywords, **keywords}
            func = func.func
        self = super(partial, cls).__new__(cls)
        self.func = func
        self.args = args
        self.keywords = keywords
        return self
    def __call__(self, /, *args, **keywords):
        keywords = {**self.keywords, **keywords}
        return self.func(*self.args, *args, **keywords)
    @recursive_repr()
    def __repr__(self):
        qualname = type(self).__qualname__
        args = [repr(self.func)]
        args.extend(repr(x) for x in self.args)
        args.extend(f"{k}={v!r}" for (k, v) in self.keywords.items())
        if type(self).__module__ == "functools":
            return f"functools.{qualname}({‘, ‘.join(args)})"
        return f"{qualname}({‘, ‘.join(args)})"
    def __reduce__(self):
        return type(self), (self.func,), (self.func, self.args,
               self.keywords or None, self.__dict__ or None)
    def __setstate__(self, state):
        if not isinstance(state, tuple):
            raise TypeError("argument to __setstate__ must be a tuple")
        if len(state) != 4:
            raise TypeError(f"expected 4 items in state, got {len(state)}")
        func, args, kwds, namespace = state
        if (not callable(func) or not isinstance(args, tuple) or
           (kwds is not None and not isinstance(kwds, dict)) or
           (namespace is not None and not isinstance(namespace, dict))):
            raise TypeError("invalid partial state")
        args = tuple(args) # just in case it‘s a subclass
        if kwds is None:
            kwds = {}
        elif type(kwds) is not dict: # XXX does it need to be *exactly* dict?
            kwds = dict(kwds)
        if namespace is None:
            namespace = {}
        self.__dict__ = namespace
        self.func = func
        self.args = args
        self.keywords = kwds
try:
    from _functools import partial
except ImportError:
    pass
 
上面大致讲的呢,就是通过调用functools.wrappers()来创建了不一样的函数,但是名字却是一样的,且id不一样,功能也可能会有所改变。代码如下:
import functools
def m(func):
    print(func.__name__)
    print(id(func))
    @functools.wraps(func)
    def wrapper():
        print(wrapper.__name__)
        print(id(wrapper))
    return wrapper
def method1():
    pass
@m
def method2():
    print(id(method2))
if __name__ == ‘__main__‘:
    print(method2())
输出:
method2
1868266070224
method2
1868266070368
None
综上:掉用该函数创建了另一个名字一样的函数,但是内部构造可能会不相同。
标签:tools xxx original ext elf apply use wrap key
原文地址:https://www.cnblogs.com/JonnyJiang-zh/p/13215415.html