我想为类定义属性,并能够在实际实例化该类的对象之前对其进行访问。

我会给出一些背景。我的应用程序处理组件库。每个组件都映射到一个Python类。现在,我想知道在实际实例化类之前组件需要什么配置。

一种解决方案是编写如下内容:

class Component:
    @classmethod
    def config(cls, name, description, default=None):
        ''' Define one configuration switch for the class. '''
        # now put this information in a class-specific dictionary

class Model1(Component):
    @classmethod
    def define_configuration(cls):
        cls.config('n', 'number of burzs to instigate')
        cls.config('skip', 'skip any barzs among the burzs', default=True)
    # ...

component_class = Model1
component_class.define_configuration()


但是,这看起来很丑。理想情况下,我希望能够编写如下内容,并且仍然能够将配置开关放入特定于类的字典中,以便以后使用。

class Model1(Component):
    config('n', 'number of burz to instigate')
    config('skip', 'skip any barz in the data', default=True)


我最初的解决方案是写类似:

class Model1(Component):
    Model1.config('n', 'number of burz to instigate')
    Model1.config('skip', 'skip any barz in the data', default=True)


但是我在SO上的其他问题上发现,执行主体时尚未定义类名。

我该怎么办?

tl; dr:如何获得定义类特定属性的良好语法(在实例该类的对象之前)?



(记录下来)这里是建议的解决方案(详细说明)。
i!我完全可以得到我想要的。 :-)

from collections import namedtuple
Config = namedtuple('Config', 'name desc default')

def config(name, description, default=None):
    ComponentMeta.tmp_config_storage.append(Config(name, description, default))

class ComponentMeta(type):
    tmp_config_storage = []
    def __init__(cls, clsname, bases, clsdict):
        for config in ComponentMeta.tmp_config_storage:
            if not 'my_config' in cls.__dict__:
                setattr(cls, 'my_config', [])
            cls.my_config.append(config)
        ComponentMeta.tmp_config_storage = []

class Component(object):
    __metaclass__ = ComponentMeta

class Model1(Component):
    config('x1', 'for model1')
    config('y1', 'for model1')

class Model2(Component):
    config('x2', 'for model2')

print 'config for Model1:', Model1.my_config
print 'config for Model2:', Model2.my_config

最佳答案

更正的

def config(name, description, default=None):
    ComponentMeta.config_items.append((name, description, default))

class ComponentMeta(type):
    config_items = []
    def __init__(cls, clsname, bases, clsdict):
        for options in ComponentMeta.config_items:
                cls.add_config(*options)
        ComponentMeta.config_items = []

class Component(object):
    __metaclass__ = ComponentMeta
    config_items = [] # this is only for testing. you don't need it
    @classmethod
    def add_config(cls, name, description, default=None):
        #also for testing
        cls.config_items.append((name, description, default))

class Model1(Component):
    config('n', 'number of burz to instigate')
    config('skip', 'skip any barz in the data', default=True)

print Model1.config_items


这是通过使config为将项目添加到ComponentMeta.config_instances的外部函数来实现的。 ComponentMeta然后在创建类时检查此列表,并在项目上调用config_item。请注意,这不是线程安全的(尽管我可以这样做)。另外,如果ComponentMeta的子类无法调用super或本身为空的ComponentMeta.config_items,则下一个创建的类将获取配置项。

10-06 07:29