在导入时在Python中注册对象成员

问题描述:

我有一组类,它们代表不同的“工具”,每个工具都有一个ID键,一个描述,一个标题和一些其他常量。这些都是从“GenericTool”类中分类的。在导入时在Python中注册对象成员

我想有一种方法来填充字典,键入所有子类的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__()中的代码,但是th似乎会影响类的运行时创建,而我只关心一次,即第一次导入模块时。

+0

“*但不必维护*字典。*”:为什么? – Blender 2013-04-28 22:25:14

+0

因为在课堂上有类特定的信息似乎更加简洁,而不必照顾完全解耦的列表,这可能很容易失去同步。对于一些课程,当然可以手工完成,但是数百或更多的课程并不能很好地进行扩展,我可以设想一些有点像装饰器,这些信息是自动收集的。 – Inductiveload 2013-04-28 22:29:45

在假设 “而无需维护*辞典” 的真正含义“没有哈维持手动更新的字典“解决方案将通过使用元类。这将需要的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 

当你的基地(GenericTool)使用__metaclass__声明或直接在你的派生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'} 
>>> 
+0

是的,我的意思是“手动维护”,这似乎造成了一些混淆。显然,当__new__被调用时,我也完全误解了。感谢一个非常明确的例子! – Inductiveload 2013-04-28 22:51:44

元类:

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): 
    # ...