以编程方式定义类定义的属性

时间:2014-02-21 18:06:29

标签: python class

我有一些对象包含应用程序的常量数据库值,看起来像这样:

class TestObject(object):
    """reflects constants in _test_object"""
    _pairs = (
        ( 1       , 'A' ),         
        ( 2       , 'B' ),         
        ( 4       , 'C' ),         
        ( 8       , 'D' ),          
    )
    mapping = setup(_pairs)

mapping函数创建一个dict,根据_pairs给我一个k,v和v,k查找。它们都是“id,name”的形式。

为了让应用程序更容易,我经常将“文本值”设置为属性:

class TestObject(object):
    ...
    ...
    A = 1
    B = 2
    C = 4
    D = 8

虽然这使得使用这些类非常棒,但重新键入所有内容并使其保持同步有点笨拙。另外,我必须编写单元测试以确保属性与_pairs中的正确ID匹配。

我一直试图绕过一种方法来跳过这个问题,然后只使用应用程序启动时的属性自动填充每个TestObject类。

我知道我可以覆盖类并让它检查_pairs / mapping属性以进行故障转移,但我真的很感兴趣是否有可能以编程方式填充我需要的类。还没有__class__,因为该类尚未定义。

为了清楚起见,我想要做的事情的类型是:

class NotValidPython():
    _pairs = ((1,'A'),)
    for (k,v) in _pairs:
        setattr( __class__, v, k )

3 个答案:

答案 0 :(得分:3)

使用装饰者:

def dynamic_attrs(cls):
    for v, k in getattr(cls, '_pairs', []):
        setattr(cls, k, v)
    # you also optionally delete the _pairs attr here using del cls._pairs
    return cls

@dynamic_attrs
class TestObject(object):
    """reflects constants in _test_object"""
    _pairs = (
        ( 1       , 'A' ),
        ( 2       , 'B' ),
        ( 4       , 'C' ),
        ( 8       , 'D' ),
    )

答案 1 :(得分:1)

可以使用元类。您可以覆盖元类中的__new__,然后填充属性字典,或覆盖__init__,然后覆盖属性字典或使用setattr在类对象本身上设置属性。

使用__new__

class Meta(type):

    def __new__(meta, clsname, bases, dct):
        dct.update(dict((k, v) for v, k in dct.pop('_pairs')))
        return type.__new__(meta, clsname, bases, dct)

class TestObject(object):
    __metaclass__ = Meta

    """reflects constants in _test_object"""
    _pairs = (
        ( 1       , 'A' ),         
        ( 2       , 'B' ),         
        ( 4       , 'C' ),         
        ( 8       , 'D' ),          
    )

使用__init__

class Meta(type):

    def __init__(cls, clsname, bases, dct):
        attrs = dct.pop('_pairs')
        for v, k in attrs:
            setattr(cls, k, v)

答案 2 :(得分:0)

无需使用元类。只需将代码放在与类定义相同的模块中,但外部类定义:

class TestClass():
    _pairs = ((1,'A'),)

for (k, v) in TestClass._pairs:
    setattr(TestClass, v, k)