Python断言在某个"with"语句的上下文中调用函数



在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_modelmlflow.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只是一个局部函数,它可能会更受欢迎。

最新更新