在对象实例上使用装饰器(或其他模式)来生成类

时间:2012-08-02 18:36:33

标签: python decorator

我可以看到制作这项工作的多个障碍,这可能是不可能的,但我想我至少会问......

所以,我有一个类AbstractEnumeratedConstantsGroup,毫不奇怪,当子类创建了一个表示一组枚举常量的对象(ex FLAVORS,其值为('VANILLA', 'CHOCOLATE', 'STRAWBERRY'),其中FLAVORS[0]返回'VANILLA'FLAVORS[1]返回'CHOCOLATE'FLAVORS.VANILLA返回0FLAVORS.CHOCOLATE返回1等等)它使用元类和一些其他的步法,以便创建一个新的常量组所需的全部是:

class FLAVORS(AbstractEnumeratedConstantsGroup):
    _constants = ('VANILLA', 'CHOCOLATE', 'STRAWBERRY')
FLAVORS = FLAVORS()

我想进一步减少它:

@enumerated_constants_group
FLAVORS = ('VANILLA', 'CHOCOLATE', 'STRAWBERRY')

我不知道如何过去的问题是:

    1.没有好的方法从装饰器代码的定义范围中获取对象的标签名称 2.不能装饰不是类,方法或函数的东西

    我考虑过使用工厂/构建器,但我不喜欢的是它需要在代码中重复组名,或者组中有无用的__name__值(这是在__repr____str__中使用。例如:

    FLAVOR = enumerated_constants_group('FLAVOR', ('VANILLA', 'CHOCOLATE', 'STRAWBERRY'))
    

    FLAVOR = enumerated_constants_group(('VANILLA', 'CHOCOLATE', 'STRAWBERRY'))
    # FLAVOR.__name__ becomes some unfriendly machine-generated string
    

    作为装饰器思想的替代方案,是否可以从工厂方法引用调用范围(通过内省或隐式地将其传递给函数),以便调用方法将新创建的对象插入到使用给定名称调用命名空间?例如:

    enumerated_constants_group('FLAVOR', ('VANILLA', 'CHOCOLATE', 'STRAWBERRY'))
    # I could now reference FLAVOR in any arbitrary scope that the method was called from
    

    我能做些什么来实现我的目标吗?还有其他我没有想过的方法吗?

5 个答案:

答案 0 :(得分:3)

没有一般方法可以影响分配给裸名称时发生的情况(如FLAVORS = ('VANILLA', 'CHOCOLATE', 'STRAWBERRY')中所示)。所以你想要的是不可能的。

也就是说,您可以编写一个元类,用自己的实例替换返回的类,这样您在第一个示例中就不需要上一个FLAVORS = FLAVORS(...)行了。类定义本身就足以创建对象。

答案 1 :(得分:2)

你看过http://code.activestate.com/recipes/413486/

吗?

它允许您编写如下代码:

>>> from enum import enum
>>> FLAVORS = enum('VANILLA', 'CHOCOLATE', 'STRAWBERRY')
>>> print FLAVORS
enum (VANILLA, CHOCOLATE, STRAWBERRY)
>>> print FLAVORS.VANILLA
VANILLA
>>> f = FLAVORS.CHOCOLATE
>>> f in FLAVORS
True
>>> for f in FLAVORS:
...     print f
...
VANILLA
CHOCOLATE
STRAWBERRY

答案 2 :(得分:0)

作为中间步骤,你可以做到

FLAVORS = type("FLAVORS",
               (AbstractEnumeratedConstantsGroup,),
               {_constants = ('VANILLA', 'CHOCOLATE', 'STRAWBERRY')})()

导致假装饰者

def enumerated_constants_group(*args):
    AECG=AbstractEnumeratedConstantsGroup
    t = type(args[0], (AECG,), dict(_constants=args[1:]))
    return t()

FLAVORS = enumerated_constants_group('FLAVORS', 'VANILLA', 'CHOCOLATE', 'STRAWBERRY')

答案 3 :(得分:0)

除了函数/方法装饰器之外,你还有类装饰器(至少它们在python 2.4中),见http://www.python.org/dev/peps/pep-3129/

无论如何,我不确定这是你需要的。

我会使用工厂类(类型,值)作为args。

一个注意事项:如果你的代码是这样的,并且AbstractEnumeratedConstantsGroup没有添加任何功能,你为什么不只使用元组?

您可以使用以下内容定义constants.py模块:

FLAVOURS = ('VANILLA', 'CHOCOLATE', 'STRAWBERRY')
PETS = ('DOG', 'CAT', 'FISH')

然后使用代码中的那些元组:

import constants
for pet in constants.PETS:
    print 'I have a ', pet

答案 4 :(得分:0)