3

一些背景:我们有一个交易系统,我们根据交易账单的国家划分流程。我们有一个存在于 2 个实例中的日志记录表,一个 DB 将事务记录到欧盟,另一个记录到其他任何地方。我们还有一个测试库,用于管理和隐藏使用数据库的内容,粗略地说,每个表都由一个类表示。我有一个代表表的类,而 db 会话管理器类对于该类的两个实例中的每一个都有两个成员。我想要做的是创建一个通用的'meta dao'类,它将对其进行任意调用,检查参数,并根据输入参数之一,随后将调用分派给正确的代表数据库实例的类实例。我最初考虑只是重载每个方法,但那

我正在考虑使用__getattr__来覆盖方法查找,以便我可以根据接收到的方法的名称调用正确的实例__getattr__,但据我了解,我不能从 insideinspect传入方法参数__getattr__,所以我可以在这种情况下,不能从它内部正确调度。有没有人对我可以追求的不同方向有任何想法,或者有一种从内部“检查”参数的方法,而不仅仅是方法名称__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']
4

3 回答 3

2

这些方面的东西应该起作用:

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) 
于 2011-12-14T19:28:56.133 回答
2

python 装饰器是你的朋友。你可以做这样的事情

class MetaFoo(object):

    def overload(func):
        """
        we need to check a named variable so for simplicity just checking kwargs
        """
        def _wrapper(*args, **kwargs):
            if kwargs.get('i',0) < 10:
                # get func.func_name from foo and call it
                print "calling foo.",func.func_name
            else:
                print "calling bar.",func.func_name

            func(*args, **kwargs)

        return _wrapper

    @overload
    def func1(self, i):
        print "default functionality"


MetaFoo().func1(i=5)
MetaFoo().func1(i=10)

输出:

calling foo. func1
default functionality
calling bar. func1
default functionality

如果你有几个方法可以覆盖,你可以单独应用装饰器,甚至可以将参数(例如 diff 阈值)传递给不同的方法,但是如果想要覆盖所有方法,你可以添加一个重载给定类的所有方法的元类,但在这种情况下__getattr__如建议的那样覆盖sth是一个很好的选择

于 2011-12-14T19:34:00.640 回答
0

基于传递的参数进行调度是一个两步过程:

  1. __getattr__返回一个代理方法
  2. python调用代理,然后决定调用哪个真实方法

这是一个例子:

from functools import partial

class TwoFold(object):
    EU = ('GERMANY','FRANCE','ITALY','GREECE',)
    def __getattr__(self, name):
        try:
            EU = object.__getattribute__(self, 'EU_' + name)
            Other = object.__getattribute__(self, 'Other_' + name)
        except AttributeError:
            raise AttributeError(
                "%r is missing an EU_%s or Other_%s" % (self, name, name)
                )
        judge = partial(self._judge, name, EU, Other)
        return judge
    def _judge(self, method_name, EU, Other, *args, **kwargs):
        if kwargs['country'].upper() in self.EU:
            method = EU
        else:
            method = Other
        return method(*args, **kwargs)
    def EU_log(self, tax, country):
        print "logging EU access for %s, tax rate of %r" % (country, tax)
    def Other_log(self, tax, country):
        print "logging non-EU access for %s, tax rate of %r" % (country, tax)

if __name__ == '__main__':
    test = TwoFold()
    test.log(7.5, country='France')
    test.log(10.1, country='Greece')
    test.log(8.9, country='Brazil')
    test.howsat('blah')

运行时,这给出:

logging EU access for France, tax rate of 7.5
logging EU access for Greece, tax rate of 10.1
logging non-EU access for Brazil, tax rate of 8.9

其次是:

Traceback (most recent call last):
  File "test.py", line 29, in <module>
    test.howsat('blah')
  File "test.py", line 10, in __getattr__
raise AttributeError("%r is missing an EU_%s or Other_%s" % (self, name, name))
AttributeError: <__main__.TwoFold object at 0x00B4A970> is missing an
    EU_howsat or Other_howsat

要完成这项工作,您要么必须始终使用相同的关键字参数(并在调用函数时为其命名),要么始终将参数放在相同的位置。或者,您可以为每种样式/类别/任何类型的方法制作几个不同的代理。

于 2012-02-29T23:29:23.447 回答