在Python中输入对象命名空间

4
有没有一种方法可以进入一个对象的命名空间,以便我可以像使用全局函数一样使用它的方法? 我在考虑使用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 语句。


你读过例如 https://stackoverflow.com/q/24920220/3001761 吗? - jonrsharpe
你能解释一下为什么要这样做吗? - Maximilian Peters
我知道请求的来源(with结构在其他语言中也被使用)。我过去也用过它。但我认为这不是一个建议遵循的Python模式。这与在方法内部编写self有些相关。 - progmatico
决定你应该拥有。 - progmatico
1
@MaximilianPeters 最近我一直在玩Cairo图形框架,这涉及到在同一个对象上连续调用不同的方法。然后我有了一个“如果能……就好了”的想法。我考虑编写一个包装类,以减少Cairo样板代码并管理不同的图像层以将它们合并为一个最终图像。 - 80KiloMett
3个回答

2

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


类似于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

2
最好检查是否存在预先存在的全局 methodA,以便在存在时缓存它并在退出时恢复它。否则,这可能会覆盖进入上下文管理器之前存在的名称。 - Mark
1
问题在于如果其他地方依赖于原始全局值才能正常工作。@80KiloMett,虽然这看起来不错,但我认为不应该使用它,不是因为技术本身,而是因为会影响全局变量。甚至不需要考虑并发。你甚至可能在with块内调用受影响的代码(在某个函数调用中),而没有注意到这一点。 - progmatico
@progmatico 是的,看起来不太好。特别是当你要提供两个以上的方法时,就会开始遍历类字典,并在全局空间中找到一个对象的 init 方法。我甚至不知道那会有什么影响。也许通过一些修改的记录,可以做到半干净的代码。但这可能不值得这样做。 - 80KiloMett
@80KiloMett 或许 PEP 555 也会有所帮助。将值添加到本地上下文(或本地作用域)中会更加安全。本地上下文也是线程安全的。 - progmatico
我猜我要把这个标记为已解决。由于没有其他方法来执行此建议,我猜它可以作为一个解决方案。 - 80KiloMett

0

您可以尝试使用这里描述的技术:如何在函数内将变量插入全局命名空间?

我想这可能需要在__enter____exit__函数中进行一些簿记,以便在完成后进行清理。这不是标准的操作,因此可能会有其他问题,我可能会忽略。


0

(哦,Maximilian Peters的回答使用略有不同的语法做了同样的事情,并且他先到这里了...)

我不建议这样做,但你可以这样做(当然,如果全局命名空间中已经有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()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接