0

我有一组类,它们代表不同的“工具”,每个类都有一个 ID 键、一个描述、一个标题和一些其他常量。这些都是“GenericTool”类的子类。

我想有一种方法来填充字典,键入所有子类的 ID,这样我就可以在给定 ID 的情况下轻松查找常量,而无需维护中央字典。

例如,文件tools/toola.py

import generic_tool as GT
class ToolA(GT.GenericTool):

    title = "Tool A"
    id = "tool_a"

文件tools/toolb.py

import generic_tool as GT
class ToolB(GT.GenericTool):

    title = "Tool B"
    id = "tool_b"

我想最终得到这样的字典:

{ 'tool_a': {'title': 'Tool A'},
  'tool_b': {'title': 'Tool B'} }

我已经研究过在超类中使用元类和代码__init__(),但这些似乎会影响类的运行时创建,而我只关心在第一次导入模块时执行一次。

4

2 回答 2

1

元类:

class GenericToolMeta(type):
    tool_dict = {}

    def __init__(cls, name, bases, dct):
        tool_dict[cls.id] = {'title': cls.title}
        super(GenericToolMeta, cls).__init__(name, bases, dct)
import generic_tool as GT
class ToolB(GT.GenericTool, metaclass=GT.GenericToolMeta):
    title = "Tool B"
    id = "tool_b"

或者使用装饰器:

tool_list = []

def tool(title, id):
    def decorator(cls):
        cls.title = title
        cls.id = id
        tool_list[id] = title
        return cls

    return decorator
import generic_tool as GT

@GT.tool(id="tool_b", title="Tool B")
class ToolB(GT.GenericTool):
    # ...
于 2013-04-28T22:30:42.107 回答
1

假设“无需维护中央字典”实际上意味着“无需维护手动更新的字典”,解决此问题的方法是使用元类。这需要定义generic_tool.GenericTool如下:

class GenericToolMeta(type):
    """Meta classs that is used by Tools to register in a central dictionary."""
    tools = {}

    def __new__(meta, classname, bases, classDict):
        new_class = type.__new__(meta, classname, bases, classDict)

        try:
            meta.tools[new_class.id] = new_class.title
        except AttributeError:
            pass
        return new_class

class GenericTool(object):
    __metaclass__ = GenericToolMeta

__metaclass__在你的基(GenericTool)中或直接在你的派生Tools中使用声明时,类本身会在定义时自动注册(即你称之为导入时间):

$ python
Python 2.7.3 (default, Jan  2 2013, 13:56:14) 
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import generic_tool
>>> generic_tool.GenericToolMeta.tools
{}
>>> import toola
>>> generic_tool.GenericToolMeta.tools
{'tool_a': 'Tool A'}
>>> import toolb
>>> generic_tool.GenericToolMeta.tools
{'tool_a': 'Tool A', 'tool_b': 'Tool B'}
>>> 
于 2013-04-28T22:34:00.797 回答