【问题标题】:Using python decorator functions from a different module使用来自不同模块的 python 装饰器函数
【发布时间】:2011-02-14 23:53:57
【问题描述】:

我想使用来自另一个模块的函数作为装饰器,但我需要它来操作当前模块的全局命名空间。

例如,我希望能够从这个:

class SomeClass:
    pass

root = SomeClass

到这里:

from othermodule import decorator

@decorator
class Someclass:
    pass

有什么想法吗?

【问题讨论】:

  • 那段代码不是已经工作了吗?
  • 我认为他希望装饰器中的代码在源类的全局范围内定义一个根变量。恐怕这对所有蟒蛇都是不利的。
  • 你可以有一个函数返回接受你的全局变量的装饰器。

标签: python decorator


【解决方案1】:

您可以使用一个函数来返回一个装饰器并接受模块的全局变量,而不是直接装饰器:

def decorator(globals):
    def dec(cls):
        globals.root = cls
        return cls
    return dec

@decorator(globals())
class SomeClass:
    ...

【讨论】:

    【解决方案2】:

    这有点hacky,但在othermodule.py试试这个:

    import sys
    def decorator(cls):
        mod = __import__(cls.__module__)
        mod.root = cls
    

    【讨论】:

    • 是的,谢谢。实际上我最终使用了 mod = sys.modules[cls.__module__] 因为 import 调用只返回顶级模块(cls.__module__)是 4 级深 - 即 mod1.mod2.mod3.mod4
    • 顺便提一下,mod = __import__(cls.__module__, {}, {}, ('*', )) 会返回 mod4 模块,而不是最外面的 mod1 包
    • 这是一个直接的答案(虽然包等容易出错),但代码非常可怕。此外,将setattr 与字符串文字一起使用有点愚蠢。 setattr(foo, 'bar', baz) 拼写为 foo.bar = baz。
    • 是的,setattr 过多。我已经删除了它。代码并不那么可怕:module 是类的文档属性。 OP 是否真的应该这样做当然是另一个问题。
    【解决方案3】:

    如果 any 模块,更不用说 另一个 模块,那么让装饰器修改全局命名空间是不好的并且从不需要。改变遥远的全局变量的代码难以阅读和维护。您绝对应该考虑修改您的设计以避免可变的全局状态,尤其是隐式赋值。

    【讨论】:

      【解决方案4】:

      已经可以了:

      from othermodule import decorator
      
      @decorator
      class Someclass:
          pass
      

      只要输入othermodule.py:

      def decorator(cls):
          #.... do something with cls
          return cls
      

      【讨论】:

      • 是的,我知道它通常可以工作,但事实上我希望导入模块中的装饰器在原始模块的全局范围内定义一个变量,这会导致问题。
      猜你喜欢
      • 2015-05-15
      • 1970-01-01
      • 1970-01-01
      • 2015-02-21
      • 1970-01-01
      • 2021-07-16
      • 1970-01-01
      • 2016-01-22
      • 2014-07-21
      相关资源
      最近更新 更多