tags:

views:

369

answers:

5

Does python have a function like call_user_func() in PHP?

PHP Version:

call_user_func(array($object,$methodName),$parameters)

How do I achieve the above in Python?

+6  A: 

I don't see the problem, unless methodName is a string. In that case getattr does the job:

>>> class A:
...     def func(self, a, b):
...         return a + b
... 
>>> a = A()
>>> getattr(a, 'func')(2, 3)
5

If object is also a string, then this would work, using globals or locals (but then you may have other, bigger, problems):

>>> getattr(locals()['a'], 'func')(2, 3)
5
>>> getattr(globals()['a'], 'func')(2, 3)
5


Edit: re your clarification. To initialise an object based on a string:

>>> class A:
...     def __init__(self): print('a')
... 
>>> class B:
...     def __init__(self): print('b')
... 
>>> clsStr = 'A'
>>> myObj = locals()[clsStr]()
a

I am not sure if this is really what you want though... unless you have many different classes, why not just perform string matching?


Another edit: Though the above works, you should seriously consider going with a solution such as provided by Ignacio Vazquez-Abrams. For one thing, by storing all possible classes in a dict, you avoid strange behaviour that may result from passing an incorrect string argument which just happens to match the name of a non-related class in the current scope.

Stephan202
eval is evil. Better use globals() or locals() instead.
muhuk
muhuk: How would you *instantiate* a new object from its class, given a sample object?
Arafangion
@muhuk: You're right. I decided to remove eval() from my answer (those interested can still have a look at the change history).
Stephan202
@Arafangion: I asked myself the same question, but as you can see in my edited answer, it is in fact possible :)
Stephan202
What if 'A' indicates a class that is not in either the local or global namespace?
Arafangion
Stephan202: Indeed, I've learnt something new - though I'm still dubious it's the whole answer. Thanks. :)
Arafangion
A: 

For a given object 'obj', a given method name 'meth', and a given set of arguments 'args':

    obj.__getattribute__(meth)(*args)

Should get you there.

Of course, it goes without saying - What the heck is it you want to do?

Arafangion
A: 

You can call use getattr with locals() or globals() to do something similar

# foo.method() is called if it's available in global scope
getattr(globals()['foo'], 'method')(*args)

# Same thing, but for 'foo' in local scope
getattr(locals()['foo'], 'method')(*args)

See also: Dive Into Python on getattr(), on locals() and globals()

Imran
Didn't answer the question - unless $object is the global namespace.
Arafangion
(the edited version) Does the same thing. $object has to exist somewhere for the PHP example (either in function or global scope)
Imran
I'd remove my negative vote if stack overflow allowed me, as it now looks good. (Apparently it's too old).
Arafangion
A: 

Picking which object to instantiate isn't that hard. A class is a first-class object and can be assigned to a variable or passed as an argument to a function.

class A(object):
    def __init__( self, arg1, arg2 ):
         etc.

class B(object):
    def __init__( self, arg1, arg2 ):
         etc.

thing_to_make = A
argList= ( some, pair )
thing_to_make( *argList )

thing_to_make = B
argList- ( another, pair )
thing_to_make( *argList )

def doSomething( class_, arg1, arg2 ):
    thing= class_( arg1, arg2 )
    thing.method()
    print thing

All works nicely without much pain. You don't need a "call_user_function" sort of thing in Python

S.Lott
like this idea. would have given you vote if stack overflow allowed me to. thanks
rubayeet
+3  A: 

If you need to use classes from far-off places (and in fact, if you need any classes at all) then you're best off creating and using a dictionary for them:

funcs = {'Eggs': foo.Eggs, 'Spam': bar.Spam}

def call_func(func_name, *args, **kwargs):
    if not func_name in funcs:
        raise ValueError('Function %r not available' % (func_name,))
    return funcs[func_name](*args, **kwargs)
Ignacio Vazquez-Abrams
Under most circumstances this solution is to be preferred over the (albeit more general) locals()/globals() trick.
Stephan202
...which is why I now referenced this answer in my answer, with an additional argument for its use.
Stephan202