一些背景:我们有一个交易系统,我们根据交易账单所在的国家/地区划分流量。我们有一个存在于 2 个实例中的日志记录表,一个数据库将事务记录到欧盟,另一个到其他任何地方。我们还有一个测试库,用于管理和隐藏使用数据库的内容,粗略地说,每个表都由一个类表示。我有一个代表该表的类,而 db session 管理器类对于该类的两个实例中的每一个都有两个成员。我想要做的是创建一个通用的“meta dao”类,该类将对其进行任意调用,检查 args,并根据其中一个输入参数,随后将调用分派(dispatch)到正确的 db 实例表示类实例。我最初考虑过重载每个方法,但那既笨重又肮脏。
我正在考虑使用 __getattr__
来覆盖方法查找,这样我就可以根据 __getattr__
接收到的方法的名称向下调用正确的实例,但是据我了解,我无法从 __getattr__
中检查
传入的方法参数,因此在这种情况下我无法从其中正确分派(dispatch)。有没有人对我可以追求的不同方向有任何想法,或者有什么方法可以从 __getattr__
中“检查”参数,而不仅仅是方法名称?
[编辑] 这是我所说内容的通用版本:
class BarBase(object):
def __init__(self, x):
self.x = x
def do_bar(self, i):
return self.x * i
class FooBar(BarBase):
def __init__(self, x):
super(FooBar, self).__init__(x)
def do_foo(self, i):
return self.x + i
class MetaFoo(object):
def __init__(self, bar_manager):
self.foo_manager = bar_manager
#something here that will take an arbitrary methodname and args as
#long as args includes a value named i, inspect i, and call
#bar_manager.fooa.[methodname](args) if i < 10,
#and bar_manager.foob.[methodname](args) if i >= 10
class BarManager(object):
def __init__(self):
self.bar_list = {}
def __get_fooa(self):
if 'fooa' not in self.bar_list.keys():
self.bar_list['fooa'] = FooBar('a')
return self.bar_list['fooa']
fooa = property(__get_fooa)
def __get_foob(self):
if 'foob' not in self.bar_list.keys():
self.bar_list['foob'] = FooBar('b')
return self.bar_list['foob']
foob = property(__get_foob)
def __get_foo(self):
if 'foo' not in self.bar_list.keys():
self.bar_list['foo'] = MetaFoo(self)
return self.bar_list['foo']
按照这些思路应该可以工作:
class ProxyCall(object):
'''Class implementing the dispatch for a certain method call'''
def __init__(self, proxy, methodname):
self.proxy = proxy
self.methodname = methodname
def __call__(self, *p, **kw):
if p[0] == "EU": # or however you determine the destination
return getattr(self.proxy.EU, self.methodname)(*p, **kw);
else:
return getattr(self.proxy.OTHER, self.methodname)(*p, **kw);
class Proxy(object):
'''Class managing the different "equivalent" instances'''
def __init__(self, EU, OTHER):
self.EU = EU
self.OTHER = OTHER
def __getattr__(self, name):
if not hasattr(self.EU, name):
# no such method
raise AttributeError()
else:
# return object that supports __call__ and will make the dispatch
return ProxyCall(self, name)
然后您将创建这两个实例并将它们组合到一个代理对象中:
eu = make_instance(...)
other = make_instance(...)
p = Proxy(eu, other)
p.somemethod(foo)
我是一名优秀的程序员,十分优秀!