Python中的__getattribute__(或__getattr__)来模拟PHP的__call__

2 投票
3 回答
2037 浏览
提问于 2025-04-15 15:23

我想创建一个类,能够有效地做到这一点(把一点PHP和Python混合在一起)

  class Middle(object) :
    #  self.apply is a function that applies a function to a list
    #  e.g   self.apply = []  ... self.apply.append(foobar)       
    def __call(self, name, *args) :
       self.apply(name, *args)   

这样就可以让代码写成:

   m = Middle()
   m.process_foo(a, b, c)

在这个例子中,__call() 是PHP中的一个__call()方法,当在一个对象上找不到某个方法时,它会被调用。

3 个回答

-1

我最近确实做过这个。下面是我解决这个问题的一个例子:

class Example:
    def FUNC_1(self, arg):
        return arg - 1

    def FUNC_2(self, arg):
        return arg - 2

    def decode(self, func, arg):
        try:
            exec( "result = self.FUNC_%s(arg)" % (func) )
        except AttributeError:
            # Call your default method here
            result = self.default(arg)

        return result

    def default(self, arg):
        return arg

然后输出结果是:

>>> dude = Example()
>>> print dude.decode(1, 0)
-1
>>> print dude.decode(2, 10)
8
>>> print dude.decode(3, 5)
5
2

考虑一下,把参数直接作为方法的输入,而不是把它们编码在方法名里,然后再神奇地用作参数。

你在哪里写代码时不知道自己会调用哪些方法呢?

为什么要调用 c.do_Something(x),然后再从方法名中提取参数,而不直接调用 c.do('Something', x) 呢?

无论如何,处理找不到的属性其实很简单:

class Dispatcher(object):
    def __getattr__(self, key):
       try:
           return object.__getattr__(self, key)
       except AttributeError:
           return self.dispatch(key)

    def default(self, *args, **kw):
        print "Assuming default method"
        print args, kw

    def dispatch(self, key):
        print 'Looking for method: %s'%(key,)
        return self.default

这是一个测试:

>>> d = Dispatcher()
>>> d.hello()
Looking for method: hello
Assuming default method
() {}

这似乎会有很多“陷阱”——通过 getattr 返回的东西,不仅仅会被认为是一个函数,还会被认为是该实例上的一个绑定方法。所以一定要确保返回的是这个。

3

你需要定义 __getattr__,这个方法会在你的对象找不到某个属性时被调用。

注意,如果查找失败,就会调用 getattr,而且你不能像调用普通函数那样直接使用它,所以你需要返回一个将要被调用的方法。

def __getattr__(self, attr):
  def default_method(*args):
    self.apply(attr, *args)
  return default_method

撰写回答