Python __getattribute__ (or __getattr__) to emulate php __call

I would like to create a class that does this efficiently (mixing a little PHP with Python)

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

So, with code, you can say:

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

In this case, __call () is PHP's __call () method that is called when no method is found on the object.

+2


source to share


3 answers


You need to define __getattr__

, it is called if any attribute is not found on your object .

Note that getattr is called for any unsuccessful lookup and that you are not getting it as a function, so you need to return the method that will be called.



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

      

+3


source


Consider the arguments passed to your methods as arguments, not encoded in the method name, which will then be magically used as an argument.

Where do you write code that doesn't know what methods it will call?

Why call c.do_Something(x)

and then unpack the method name instead of calling c.do('Something', x)

?

It's easy enough to handle unreasonable attributes anyway:



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

      

Test:

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

      

This seems to be fraught with "gotchas" - the thing returned by getattr will be considered not just a function, but also a bound method on that instance. So be sure to return this.

+2


source


I actually did this recently. Here's an example of how I solved it:

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

      

and the output is:

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

      

-1


source







All Articles