【问题标题】:Enter object namespace in Python在 Python 中输入对象命名空间
【发布时间】:2020-11-22 19:55:08
【问题描述】:

有没有办法进入对象的命名空间,以便我可以像使用全局方法一样使用它的方法?我正在考虑使用 with 语句。

class Bar():
    
    def methodA(self):
        # do stuff

    def methodB(self):
        # do more stuff

    def __enter__(self):
        # somehow enter object namespace / transfer methods into global namespace

    def __exit__(self, *args):
        # exit object namespace / get rid of globalized methods

foo = Bar()

with foo:
    methodA() # all works fine
    methodB()

methodA() # throws an error

这只是一个想法,可能根本行不通。或者也许有一个没有 with 语句的解决方案。

【问题讨论】:

  • 你能解释一下为什么要这样做吗?
  • 我看到了请求的来源(with 构造用于其他语言)。我过去使用过它。我不认为这是一个可取的 Python 模式。这与必须在方法内部编写 self 有点相关。
  • 决定你应该这样做。
  • @MaximilianPeters 最近我一直在玩 Cairo 图形框架,它涉及在同一个对象上连续调用不同的方法。我有一个“如果......不是很好”的时刻。我想写一个包装类来减少 Cairo 样板并管理不同的图像层以最终将它们组合成一个。

标签: python python-3.x with-statement


【解决方案1】:

这回答了最初的问题,但我建议不要使用它


类似于wKavey的建议方式。

但我不确定我为什么要这样做。 我需要确保全局命名空间中没有变量 methodA

class Bar():
    
    def __init__(self, value=5):
        self.value = value
        
    def methodA(self):
        return self.value

    def methodB(self):
        return -self.value

    def __enter__(self):
        global methodA
        global methodB
        methodA = self.methodA
        methodB = self.methodB

    def __exit__(self, *args):
        global methodA
        del methodA
        global methodB
        del methodB
        pass

foo = Bar()

with foo:
    print(methodA()) # all works fine
    print(methodB())

methodA() # throws an error

【讨论】:

  • 可能值得检查预先存在的全局methodA,以便您可以缓存它(如果存在)并在退出时恢复它。否则,这可能会破坏进入上下文管理器之前存在的名称。
  • 问题是其他地方是否依赖原始全局值才能正常工作。 @80KiloMett,虽然这看起来不错,但我认为不应该使用它,不是因为每次看到的技术,而是因为影响全局。甚至不需要想象并发性。您甚至可能在 with 块内调用受影响的代码(在某些函数调用中),而不会注意到。
  • @progmatico 是的,它看起来不太好。尤其是当您想要提供两种以上的方法时。然后你开始循环遍历类 dict 并在全局空间中找到一个对象的 init 方法。我什至不知道这意味着什么。也许通过对更改进行一些簿记,可以将其拉到一半干净。但这可能不值得付出努力。
  • @80KiloMett 也许PEP 555 也有帮助。相反,将值添加到本地上下文(或本地范围)会不那么危险。本地上下文也是线程安全的。
  • 猜猜我要把它标记为已解决。由于没有其他方法可以做到这一点,建议不要使用这个,我想它可以作为一种解决方案。
【解决方案2】:

您可能可以使用此处描述的技术:Insert variable into global namespace from within a function?

我想它需要在 __enter____exit__ 函数中进行一些记账,以便自行清理。这不是真正的标准,所以我忽略了其他一些脚枪。

【讨论】:

    【解决方案3】:

    (哦。Maximilian Peters' answer 也在做同样的事情,但语法略有不同,并且首先出现在这里......)

    我不建议您这样做,但您可以这样做(如果全局命名空间中已经存在 methodA,您当然会遇到麻烦):

    class Bar():
    
        def methodA(self):
            print("methodA called")
    
        def methodB(self):
            print("methodB called")
    
        def __enter__(self):
            g = globals()
            g["methodA"] = self.methodA
            g["methodB"] = self.methodB
    
        def __exit__(self, *args):
            g = globals()
            del g["methodA"]
            del g["methodB"]
    
    foo = Bar()
    
    with foo:
        methodA()  # all works fine
        methodB()
    

    【讨论】:

      猜你喜欢
      • 2010-12-11
      • 1970-01-01
      • 2010-10-31
      • 2015-01-23
      • 2021-10-03
      • 2017-01-25
      • 1970-01-01
      • 2021-12-14
      • 1970-01-01
      相关资源
      最近更新 更多