在python中,我想检查给定函数是否在给定类型的with
语句中被调用
class Bar:
def __init__(self, x):
self.x = x
def __enter__(self):
return self
def __exit__(self, *a, **k):
pass
def foo(x):
# assert that the enclosing context is an instance of bar
# assert isinstance('enclosed context', Bar)
print(x*2)
with Bar(1) as bar:
foo(bar.x)
我可以做一些事情,比如强制执行传递到foo
的arg,并在装饰器(即(中包装函数
class Bar:
def __init__(self, x):
self.x = x
def __enter__(self):
return self
def __exit__(self, *a, **k):
pass
def assert_bar(func):
def inner(bar, *a, **k):
assert isinstance(bar, Bar)
return func(*a, **k)
return inner
@assert_bar
def foo(x):
print(x*2)
with Bar(1) as bar:
foo(bar, bar.x)
但那时我将不得不绕过CCD_ 3。
因此,我正在尝试查看是否有方法访问with
上下文
注意:这在现实世界中的应用是确保mlflow.pyfunc.log_model
在mlflow.ActiveRun
上下文中被调用,或者它使ActiveRun
保持打开状态,从而在上稍后出现问题
这里有一种丑陋的方法:全局状态。
class Bar:
active = 0
def __init__(self, x):
self.x = x
def __enter__(self):
Bar.active += 1
return self
def __exit__(self, *a, **k):
Bar.active -= 1
from functools import wraps
def assert_bar(func):
@wraps(func)
def wrapped(*vargs, **kwargs):
if Bar.active <= 0:
# raises even if asserts are disabled
raise AssertionError()
return func(*vargs, **kwargs)
return wrapped
不幸的是,我不认为有任何非丑陋的方法可以做到这一点。如果你不打算自己传递Bar
实例,那么你必须依靠其他地方存在的某种状态来告诉你Bar
实例存在,并且目前正在用作上下文管理器。
避免全局状态的唯一方法是将状态存储在实例中,这意味着装饰器需要是一个实例方法,并且在声明函数之前实例需要存在:
from functools import wraps
class Bar:
def __init__(self, x):
self.x = x
self.active = 0
def __enter__(self):
self.active += 1
return self
def __exit__(self, *a, **k):
self.active -= 1
def assert_this(self, func):
@wraps(func)
def wrapped(*vargs, **kwargs):
if self.active <= 0:
raise AssertionError()
return func(*vargs, **kwargs)
return wrapped
bar = Bar(1)
@bar.assert_this
def foo(x):
print(x + 1)
with bar:
foo(1)
这仍然是";全局状态";在函数CCD_ 10现在保持对保持状态的CCD_。但是,如果foo
只是一个局部函数,它可能会更受欢迎。