【问题标题】:Decorator that creates classes创建类的装饰器
【发布时间】:2013-08-30 09:19:48
【问题描述】:

我有课

class Test:
    name = "Test"

我想创建一个装饰器 mc_me 之后:

@mc_me
class Test:
    name = "Test"

将为我提供三个类,就像我写的一样:

class Test:
    name = "Test"

class TestSuper:
    name = "TestSuper"

class TestExtra:
    name = "TestExtra"

所以本质上第一个棘手的部分是深度复制一个类,第二个是在调用者的范围内分配三个变量。感觉应该是有可能的……

【问题讨论】:

    标签: python python-decorators


    【解决方案1】:
    import inspect
    
    def mc_me(cls):
        main_locals = inspect.currentframe().f_back.f_locals
        for suffix in ['Super', 'Extra']:
            new_name = cls.__name__ + suffix
            main_locals[new_name] = type(new_name, (), {'name': new_name})
        return cls
    

    小心,这不是最好的编码方式。拥有权利的同时也被赋予了重大的责任。我鼓励您检查inspect 方法的所有可能缺点(Google 是您的朋友)。

    【讨论】:

    • 有病又漂亮! :) 附注:“CPython 实现细节:此函数依赖于解释器中的 Python 堆栈框架支持,这并不保证在所有 Python 实现中都存在。” inspect.currentframe
    • 只适用于顶级或类级别,我很确定你应该返回cls
    • 忘了return cls,你是对的。我看不到顶级限制的问题。
    【解决方案2】:

    不可能。制作 3 节课很容易。但是,将结果分配给 3 个变量?这违反了 Python 的作用域规则。

    @mc_me
    class Test:
        name = "Test"
    

    等价于

    class Test:
        name = "Test"
    Test = mc_me(Test)
    

    装饰器无法说它想创建更多变量并分配给这些变量。即使您以某种方式设法使其工作(可能仅在模块或类范围内使用 inspect 疯狂),Python 也无法知道对 TestSuperTestExtra 的引用应该引用由编译字节码时的装饰器。

    【讨论】:

    • 是的,确切地说,我在想一些类似于...(Test, TestSuper, TestExtra) = mc_me(Test)“制作 3 个类很容易”- 使用类型?你能以某种方式进行深拷贝和猴子补丁吗? (我知道这听起来像继承)。在任何情况下,下面应该是一个简单的替代类 Test: name = "Test" TestSuper = mc_me(Test, "Super") TestExtra = mc_me(Test, "Extra")`
    • Python 无法知道对 TestSuper 或 TestExtra 的引用应该引用由装饰器在编译字节码时创建的变量。 确定吗?字节码不包括新创建的TestSuperTestExtra,而是创建它们的指令。事实上,它有效。
    【解决方案3】:

    事实证明,放弃装饰器的想法,使用返回元组的常规函数​​是最接近我想要的结果的。

    # Library code
    def mc_me(base):
        class Sp(base):
            name = base.name + "Super"
    
        class Ex(base):
            name = base.name + "Extra"
    
        return (Sp, Ex)
    
    # Application code
    class Test:
        name = "Test"
    
    (TestSuper, TestExtra) = mc_me(Test)
    

    【讨论】:

      猜你喜欢
      • 2015-03-28
      • 1970-01-01
      • 1970-01-01
      • 2014-02-13
      • 1970-01-01
      • 2020-09-05
      • 2017-11-16
      • 2017-02-04
      • 1970-01-01
      相关资源
      最近更新 更多