2013-10-27 39 views
1

考虑一个类似字典界面的注册表。每个键都是一个字符串名称,每个值都是一个类。在此为了使用它的工作原理:代理类尚未定义

registry['foo'] = FooClass 
cls = registry['foo'] 
instance = cls 

但是在这个顺序它当然不会:

cls = registry['foo'] 
registry['foo'] = FooClass 
instance = cls() 

为了支持第二个用例,我implemented a class constructor wrapper in a function但“denaturates”之类的。我的意思是,这是行不通的:

cls = registry['foo'] 
registry['foo'] = FooClass 
issubclass(cls, FooClass) 

我想支持第三种情况,所以我在寻找到代理类注册表项的更好的方法。

+0

这的确是有趣的,+1 –

+0

你有没有考虑隐式创建一个元类,存储信息? –

回答

0

有趣的问题,我会尝试这样的事:

from abc import ABCMeta 


class Registry(object): 

    def __init__(self): 
     self._proxies = {} 
     self._classes = {} 

    def resolve(self, name): 
     try: 
      return self._classes[name] 
     except KeyError: 
      raise KeyError('Cannot resolve "%s".' 
          ' Class not registered yet.' % name) 

    def __getitem__(self, name): 
     """Return a proxy class bound to `name`.""" 
     if name not in self._proxies: 
      self._proxies[name] = make_proxy(lambda: self.resolve(name)) 
     return self._proxies[name] 

    def __setitem__(self, name, val): 
     """Store a class for `name`.""" 
     self._classes[name] = val 


def make_proxy(resolve): 
    """ 
    Return a proxy class. 

    :param resolve: a function that returns the actual class 

    """ 

    class ProxyMeta(ABCMeta): 
     """ 
     Custom meta class based on ABCMeta that forwards various checks 
     to the resolved class. 

     """ 
     def __eq__(self, y): 
      return resolve() == y 

     def __repr__(self): 
      return repr(resolve()) 

     def __str__(self): 
      return str(resolve()) 

    class Proxy(object): 
     """ 
     The actual proxy class. 

     """ 
     __metaclass__ = ProxyMeta 

     def __new__(cls, *args, **kwargs): 
      """Calling this class returns an instance of the resolved class.""" 
      return resolve()(*args, **kwargs) 

     @classmethod 
     def __subclasshook__(cls, subclass): 
      """issubclass() overwrite.""" 
      return issubclass(resolve(), subclass) 

    return Proxy 

>>> registry = Registry() 
>>> List = registry['list'] 
>>> List 
KeyError: 'Cannot resolve "list". Class not registered yet.' 
>>> registry['list'] = list 
>>> List 
<type 'list'> 
>>> issubclass(List, List) 
True 
>>> issubclass(list, List) 
True 
>>> List == list 
True 
>>> List() 
[] 
>>> registry['list'] = tuple 
>>> List() 
()