gpt4 book ai didi

python - 在上下文管理器中装饰任何 python 函数

转载 作者:太空宇宙 更新时间:2023-11-03 15:47:39 25 4
gpt4 key购买 nike

我想创建一个 python 上下文管理器,它将允许以下操作(使用 reverse_decorator 应用装饰函数,如果它是字符串,则第一个参数反转):

print('hi')
with MyFunctionDecorator('print', reverse_decorator):
print('hello')
print('bye')

导致:

hi
olleh
bye

重点不是打印函数本身,而是编写这种上下文管理器,它可以装饰任何函数——本地的、全局的、内置的,来自任何模块。这在 python 中甚至可能吗?我应该怎么做?

编辑:澄清一点,重点是不必更改 with 上下文中的代码。

最佳答案

这是我的方法:

from contextlib import contextmanager
from importlib import import_module

@contextmanager
def MyFunctionDecorator(func, decorator):
if hasattr(func, '__self__'):
owner = func.__self__
elif hasattr(func, '__objclass__'):
owner = func.__objclass__
else:
owner = import_module(func.__module__)
qname = func.__qualname__
while '.' in qname:
parent, qname = qname.split('.', 1)
owner = getattr(owner, parent)
setattr(owner, func.__name__, decorator(func))
yield
setattr(owner, func.__name__, func)

# Example decorator, reverse all str arguments
def reverse_decorator(f):
def wrapper(*args, **kwargs):
newargs = []
for arg in args:
newargs.append(arg[::-1] if isinstance(arg, str) else arg)
newkwargs = {}
for karg, varg in kwargs.values():
newkwargs[karg] = varg[::-1] if isinstance(varg, str) else varg
return f(*newargs, **newkwargs)
return wrapper

# Free functions
print('hi')
with MyFunctionDecorator(print, reverse_decorator):
print('hello')
print('bye')

# Class for testing methods (does not work with builtins)
class MyClass(object):
def __init__(self, objId):
self.objId = objId
def print(self, arg):
print('Printing from object', self.objId, arg)

# Class level (only affects instances created within managed context)
# Note for decorator: first argument of decorated function is self here
with MyFunctionDecorator(MyClass.print, reverse_decorator):
myObj = MyClass(1)
myObj.print('hello')

# Instance level (only affects one instance)
myObj = MyClass(2)
myObj.print('hi')
with MyFunctionDecorator(myObj.print, reverse_decorator):
myObj.print('hello')
myObj.print('bye')

输出:

hi
olleh
bye
Printing from object 1 olleh
Printing from object 2 hi
Printing from object 2 olleh
Printing from object 2 bye

这应该跨函数和其他模块等工作,因为它修改了模块或类的属性。类方法很复杂,因为一旦你创建了一个类的实例,它的属性就指向类中定义的函数在创建对象时,所以你必须在修改类的行为之间做出选择特定实例或修改托管上下文中新实例的行为,如示例中所示。此外,尝试修饰 listdict 等内置类的方法也不起作用。

关于python - 在上下文管理器中装饰任何 python 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49034642/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com