python静态调用魔法

时间:2014-05-10 09:14:12

标签: python

我正在尝试构建一个包含Service个实例的Registry类。 RegistryService类如下;

class Registry:

    def __init__(self, registrar):
        self.registrar = registrar

    def get(self, key):
        layers = key.split('.')
        value = self.registrar
        for item in layers:
            value = value[item]
        return value

class Service:

    instance = None

    @classmethod
    def boot(cls, object, configuration = {}):
        if cls.instance is None:
            cls.instance = object(configuration)

我目前想要的是在调用boot函数之后,注册表函数应该可以从Service类静态访问,而无需在Service类中定义函数。因此,在使用以下代码启动后,我想使用get函数。

Service.boot(Config, {'a' : 'b'});
Service.get('a');

注意:Config对象是Registry

的扩展

我尝试了__getattr__魔术方法,但它并不适用于静态方法。 我已尝试__call__但之后我需要拨打Service().get()这不是我想要的。

那么,有可能在python中实现这一点吗?我不想在Service图层中重新定义类方法。

注意:在PHP中,存在__callStatic()函数,它完全符合我的要求。但是,我无法在python上找到实现。

1 个答案:

答案 0 :(得分:2)

如果您可以略微修改您的通话模式,我可以想象它是可行的:

cfg = Service.boot(Config, {'a' : 'b'})
cfg.get('a')

通过这种方式,如果让__getattr__返回提供这些方法的对象,则可以完美地使其与boot()一起使用。

如果没有,您可以尝试以下方法之一:

  1. 只需致电cfg.instance.get('a')
  2. 即可
  3. Service一个元类:

    class Registry:
    
        def __init__(self, registrar):
            self.registrar = registrar
    
        def get(self, key):
            layers = key.split('.')
            value = self.registrar
            for item in layers:
                value = value[item]
            return value
    
    class DeflectToInstance(type):
        def __getattr__(selfcls, a): # selfcls in order to make clear it is a class object (as we are a metaclass)
            try:
                # first, inquiry the class itself
                return super(Meta, selfcls).__getattr__(a)
            except AttributeError:
                # Not found, so try to inquiry the instance attribute:
                return getattr(selfcls.instance, a)
    
    class Service:
        __metaclass__ = DeflectToInstance
        instance = None
    
        @classmethod
        def boot(cls, NewCls, configuration={}):
            if cls.instance is None:
                cls.instance = NewCls(configuration)
    
    Service.boot(Registry, {'a': 'b'})
    print Service.get('a')
    

    这里的元类提供了一种适当的方法来将类的属性访问转移到其属性之一。

    请注意,在Py3下,语法略有不同。 IIRC,它是

    class Service(metaclass=DeflectToInstance):
    

  4. (但是,对于我来说,使用Service类来进行这种封装似乎有点不对。

    您可以在一个地方从我的第一个想法开始cfg = boot(...),然后使用cfg进行每次访问。您甚至(误导性地)将其命名为Config

    class Registry:
    
        def __init__(self, registrar):
            self.registrar = registrar
    
        def get(self, key):
            layers = key.split('.')
            value = self.registrar
            for item in layers:
                value = value[item]
            return value
    
    cfg = Registry(...)
    

    Config = Registry(...)
    

    然后随时随地使用cfg(或Config)。)