2013-10-27 66 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() 
()