我想为类定义属性,并且能够在实际实例化该类的对象之前访问它们。
我会给出一些背景信息。我的应用程序处理组件库。每个组件都映射到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:我如何获得一个很好的语法来定义特定于类的属性(在我实例化该类的对象之前)?
这是(用于记录)建议的解决方案(稍微详述)。 艾!我可以得到我想要的东西。 : - )
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
答案 0 :(得分:1)
一旦执行正文,就会定义一个类名。导入包含类的文件时会发生这种情况。这与创建类的实例不同。
class A(object):
""" doc """
config = []
def __init__(def):
pass
A.config.append(('n', 'number of burz to instigate'))
A.config.append(('skip', 'skip any barz in the data', default=True))
# access class specific config before object instantiation
x = A.config[0]
# instantiating your class, post configuration access
a_obj = A()
这种方法不适合您的目的吗?类配置可以存储在类变量中,在实例化此类的任何对象之前,可以对其进行修改和添加。
使用类变量应该符合您的目的。
答案 1 :(得分:1)
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
这可以通过使配置成为将项添加到ComponentMeta.config_instances
的外部函数来实现。 ComponentMeta
然后在创建类时检查此列表并在项目上调用config_item
。请注意,这不是线程安全的(尽管我可以这样做)。此外,如果ComponentMeta
的子类无法调用super
或空ComponentMeta.config_items
本身,则下一个创建的类将获取配置项。
答案 2 :(得分:1)
为什么不简单,比如说:
def makeconfigdict(cls):
thedict = {}
for name, value in cls.__dict__.items():
if isaconfig(value):
addconfigtodict(thedict, name, value)
delattr(cls, name)
cls.specialdict = thedict
return cls
@makeconfigdict
class Model1(Component):
n = config('number of burz to instigate')
skip = config('skip any barz in the data', default=True)
...
只要config
函数返回isaconfig
函数可以识别的对象,并且addconfigtodict
函数可以以任何你想要的格式正确设置到特殊字典中,你就是在三叶草中。
如果我正确理解您的规格,不想要Model1.skip
这样的普通属性,对吧?这就是为什么我在delattr
中调用makeconfigdict
(以及为什么我在类的字典上使用.items()
- 因为字典在循环期间被修改,所以最好使用{{1}获取所有名称和值的“快照”列表,而不是通常的.items()
,它只是在字典上迭代,因此不允许在循环期间修改它)。