我们如何才能将Python上下文管理器“关联”到其块中出现的变量?

时间:2018-08-14 20:35:27

标签: python pymc3 contextmanager

据我了解,上下文管理器在Python中用于定义对象的代码段(__enter____exit__)的初始化和终结。

但是,在tutorial for PyMC3中,它们显示了以下上下文管理器示例:

basic_model = pm.Model()

with basic_model:

    # Priors for unknown model parameters
    alpha = pm.Normal('alpha', mu=0, sd=10)
    beta = pm.Normal('beta', mu=0, sd=10, shape=2)
    sigma = pm.HalfNormal('sigma', sd=1)

    # Expected value of outcome
    mu = alpha + beta[0]*X1 + beta[1]*X2

    # Likelihood (sampling distribution) of observations
    Y_obs = pm.Normal('Y_obs', mu=mu, sd=sigma, observed=Y)

并提到这样做的目的是将变量alphabetasigmamuY_obs与模型basic_model相关联。

我想了解这种机制是如何工作的。在我发现的explanations of上下文管理器中,我没有看到任何建议暗示如何在上下文块中定义的变量或对象以某种方式“关联”到上下文管理器。似乎该库(PyMC3)以某种方式可以访问“当前”上下文管理器,因此它可以在幕后将每个新创建的语句与其关联。但是图书馆如何获得对上下文管理器的访问权限?

2 个答案:

答案 0 :(得分:2)

在这种特定情况下,我不知道它是如何工作的,但通常您会使用一些“幕后魔术”:

class Parent:
    def __init__(self):
        self.active_child = None

    def ContextManager(self):
        return Child(self)

    def Attribute(self):
        return self.active_child.Attribute()

class Child:
    def __init__(self,parent):
        self.parent = parent

    def __enter__(self):
        self.parent.active_child = self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.parent.active_child = None

    def Attribute(self):
        print("Called Attribute of child")

使用此代码:

p = Parent()
with p.ContextManager():
    attr = p.Attribute()

将产生以下输出:

Called Attribute of child

答案 1 :(得分:1)

PyMC3通过在Context类内将thread local variable保留为 class变量来实现。 Model继承自Context

每次在模型上调用with时,当前模型都会被推送到特定于线程的上下文堆栈中。因此,堆栈的顶部始终引用用作上下文管理器的最内部(最新)的模型。

Context s(因此还有Model s)具有.get_context() 类方法,以获取上下文堆栈的顶部。

Distribution在创建Model.get_context()并将其与最内部的模型相关联时会调用它们。

简而言之:

  1. with modelmodel推送到上下文堆栈。这意味着在with块中,type(model).contextsModel.contextsContext.contexts现在包含model作为其最后一个(最顶部)元素。
  2. Distribution.__init__()调用Model.get_context()(注意大写字母M),该返回上下文堆栈的顶部。在我们的情况下,这是model。上下文堆栈是线程本地的(每个线程一个),但是它不是特定于实例的。如果只有一个线程,那么无论模型数量如何,也只有一个上下文堆栈。
  3. 退出上下文管理器时。 model从上下文堆栈中弹出。