在我的示例中,如果调用函数(此处为f1
或decorated
)具有特定的修饰符(在代码not_decorated
中),是否可以检查函数@out
内的任何方法?这样的信息是否传递给函数?
def out(fun):
def inner(*args, **kwargs):
fun(*args, **kwargs)
return inner
@out
def decorated():
f1()
def not_decorated():
f1()
def f1():
if is_decorated_by_out: # here I want to check it
print('I am')
else:
print('I am not')
decorated()
not_decorated()
预期输出:
I am
I am not
答案 0 :(得分:2)
要清楚,这是骇人听闻的骇客,所以我不推荐这样做,但是由于您已经排除了其他参数,并且f1
还是相同,无论是否包装,您都留下了骇客作为您唯一的选择。解决方案是将唯一变量添加到包装函数,以仅通过堆栈检查来找到它:
import inspect
def out(fun):
def inner(*args, **kwargs):
__wrapped_by__ = out
fun(*args, **kwargs)
return inner
def is_wrapped_by(func):
try:
return inspect.currentframe().f_back.f_back.f_back.f_locals.get('__wrapped_by__') is func
except AttributeError:
return False
@out
def decorated():
f1()
def not_decorated():
f1()
def f1():
if is_wrapped_by(out):
print('I am')
else:
print('I am not')
decorated()
not_decorated()
这假定了特定的嵌套程度(通过f_back
进行手动回溯以说明is_wrapped_by
本身,f1
,decorated
,最后是{{1} }(来自inner
)。如果要确定out
是否在调用堆栈的任何地方都涉及到,请进行out
循环直到堆栈用尽: / p>
is_wrapped_by
答案 1 :(得分:0)
如果您愿意在f1
中创建其他参数(也可以使用默认参数),则可以使用functools.wraps
并检查是否存在__wrapped__
属性。为此,请将包装函数传递给f
:
import functools
def out(fun):
@functools.wraps(fun)
def inner(*args, **kwargs):
fun(*args, **kwargs)
return inner
@out
def decorated():
f1(decorated)
def not_decorated():
f1(not_decorated)
def f1(_func):
if getattr(_func, '__wrapped__', False):
print('I am')
else:
print('I am not')
decorated()
not_decorated()
输出:
I am
I am not
答案 2 :(得分:0)
假设您具有这样的功能修饰
def double_arg(fun):
def inner(x):
return fun(x*2)
return inner
但是您无法访问它(它在第3方库中或其他内容中)。在这种情况下,您可以将其包装到另一个将装饰名称添加到结果函数中的函数中
def keep_decoration(decoration):
def f(g):
h = decoration(g)
h.decorated_by = decoration.__name__
return h
return f
并用包装纸代替旧装饰。
double_arg = keep_decoration(double_arg)
您甚至可以编写一个辅助函数来检查该函数是否被修饰。
def is_decorated_by(f, decoration_name):
try:
return f.decorated_by == decoration_name
except AttributeError:
return False
使用示例...
@double_arg
def inc_v1(x):
return x + 1
def inc_v2(x):
return x + 1
print(inc_v1(5))
print(inc_v2(5))
print(is_decorated_by(inc_v1, 'double_arg'))
print(is_decorated_by(inc_v2, 'double_arg'))
输出
11
6
True
False