Python 静态方法的魔法调用
我正在尝试创建一个 Service
类,用来保存 Registry
实例。Registry
和 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 Service:
instance = None
@classmethod
def boot(cls, object, configuration = {}):
if cls.instance is None:
cls.instance = object(configuration)
我现在想要的是,在调用 boot
函数后,Service
类可以静态地访问 Registry
的功能,而不需要在 Service
类中定义这些函数。所以,在用以下代码启动后,我想直接使用 get
函数。
Service.boot(Config, {'a' : 'b'});
Service.get('a');
注意:Config 对象是 Registry 的一个扩展
我尝试过使用 __getattr__
这个魔法方法,但它在静态方法上不起作用。我也试过 __call__
,但这样的话我就需要调用 Service().get()
,这不是我想要的。
所以,在 Python 中,这种情况可以实现吗?我不想在 Service
层重新定义类方法。
注意:在 PHP 中,有一个 __callStatic()
函数,正好实现了我想要的功能。不过,我找不到在 Python 中的实现。
1 个回答
2
如果你能稍微调整一下你的调用方式,我觉得这样是可行的:
cfg = Service.boot(Config, {'a' : 'b'})
cfg.get('a')
这样的话,如果你让 boot()
返回一个提供这些方法的对象,你就可以完美地使用 __getattr__
了。
如果不行,你可以试试以下几种方法:
- 直接调用
cfg.instance.get('a')
给
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')
这里的元类提供了一种合适的方法,可以把对类属性的访问转发到它的某个属性上。
要注意的是,在 Python 3 中,语法稍微有点不同。如果我没记错的话,应该是
class Service(metaclass=DeflectToInstance):
(不过,我觉得仅仅为了这种封装使用 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
)。