python wrapper_简述python中`functools.wrapper()

简述python中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

综上:调用该函数创建了另一个名字一样的函数,但是内部构造可能会不相同。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值