How to Pass a Method as a Parameter in Python

How do I pass a method as a parameter in Python

Yes it is, just use the name of the method, as you have written. Methods and functions are objects in Python, just like anything else, and you can pass them around the way you do variables. In fact, you can think about a method (or function) as a variable whose value is the actual callable code object.

Since you asked about methods, I'm using methods in the following examples, but note that everything below applies identically to functions (except without the self parameter).

To call a passed method or function, you just use the name it's bound to in the same way you would use the method's (or function's) regular name:

def method1(self):
return 'hello world'

def method2(self, methodToRun):
result = methodToRun()
return result

obj.method2(obj.method1)

Note: I believe a __call__() method does exist, i.e. you could technically do methodToRun.__call__(), but you probably should never do so explicitly. __call__() is meant to be implemented, not to be invoked from your own code.

If you wanted method1 to be called with arguments, then things get a little bit more complicated. method2 has to be written with a bit of information about how to pass arguments to method1, and it needs to get values for those arguments from somewhere. For instance, if method1 is supposed to take one argument:

def method1(self, spam):
return 'hello ' + str(spam)

then you could write method2 to call it with one argument that gets passed in:

def method2(self, methodToRun, spam_value):
return methodToRun(spam_value)

or with an argument that it computes itself:

def method2(self, methodToRun):
spam_value = compute_some_value()
return methodToRun(spam_value)

You can expand this to other combinations of values passed in and values computed, like

def method1(self, spam, ham):
return 'hello ' + str(spam) + ' and ' + str(ham)

def method2(self, methodToRun, ham_value):
spam_value = compute_some_value()
return methodToRun(spam_value, ham_value)

or even with keyword arguments

def method2(self, methodToRun, ham_value):
spam_value = compute_some_value()
return methodToRun(spam_value, ham=ham_value)

If you don't know, when writing method2, what arguments methodToRun is going to take, you can also use argument unpacking to call it in a generic way:

def method1(self, spam, ham):
return 'hello ' + str(spam) + ' and ' + str(ham)

def method2(self, methodToRun, positional_arguments, keyword_arguments):
return methodToRun(*positional_arguments, **keyword_arguments)

obj.method2(obj.method1, ['spam'], {'ham': 'ham'})

In this case positional_arguments needs to be a list or tuple or similar, and keyword_arguments is a dict or similar. In method2 you can modify positional_arguments and keyword_arguments (e.g. to add or remove certain arguments or change the values) before you call method1.

Passing a method as a parameter to another method

In your snippet you are printing the function object a_method.

Passing a function as a parameter to another function is possible, but you need to actually call it if you want it to execute.

Considering your example:

  1. Define a function with_price
def with_price(price: float, factor: float = 2.0):
return (price * factor)

  1. Define the function a_method. Note how myfunction is a generic parameter, not the function we just defined:
def a_method(a: float, myfunction):
b = myfunction(11)
return a * b

  1. Finally, call a_method, passing with_price as parameter:
print( a_method(2, with_price) )

Python passing instance methods as arguments

Python object methods are functions that expect the instance as their first parameter. Calling myInstance.method(x) is similar to calling type(myInstance).method(myinstance,x)

An example of how this works can be seen when calling the map function.

L = [ [1,2,3],[4,5],[6,7,8,9] ]

print(*map(list.pop,L)) # 3 5 9

print(L) # [[1, 2], [4], [6, 7, 8]]

We passed a method of the list class as a parameter to map() which handles the lists in L internally. So the map() function is applying a method on list instances that it has internally.

To do the same thing, you can define a method or function that expects a method as a parameter and add your object instance as the first parameter when calling it:

def apply(method):
myInstance = list()
method(myInstance)

how to pass method name as a parameter in python class

I guess that you may want to use the function getattr.

class Foo(object):
faker = Faker()

def __init__(self, custom_method, num=1):
self.custom_method = custom_method
self.num = num

@property # Briefly, the property decorator makes the job of calling the callable for you. I.e. There is no need to do self.method(), self.method is enough.
def random_first_name(self):
return self.faker.first.name()

@property
def random_phone(self):
return self.faker.random.phone()

def call_method_num_times(self):
return [getattr(self, self.custom_method)\
for _ in range(self.num)]

I cannot instantiate this class, but this could be used as follows:

>>> foo1 = Foo('random_first_name', 1)
>>> foo1.call_method_num_times()
['John']

>>> foo2 = Foo('random_phone', 2)
>>> foo2.call_method_num_times()
['0123456789', '9876543210']


To (even more) reorganize your class in a (subjectively) better fashion, I would do

class Foo(object):

def __init__(self):
self.faker = Faker()

@property
def random_first_name(self):
return self.faker.first.name()

@property
def random_phone(self):
return self.faker.random.phone()

def call_method_num_times(self, custom_method, num=1):
return [getattr(self, custom_method)\
for _ in range(num)]

Thus allowing you for instantiating Foo only once

>>> foo = Foo()
>>> foo.call_method_num_times('random_first_name')
['John']
>>> foo.call_method_num_times('random_phone', 2)
['0123456789', '9876543210']


If you are not comfortable with the use of the python native property descriptor, you can keep your two methods as explicite ones. In this case, you would define the class Foo as follows

class Foo(object):

def __init__(self):
self.faker = Faker()

def random_first_name(self):
return self.faker.first.name()

def random_phone(self):
return self.faker.random.phone()

def call_method_num_times(self, custom_method, num=1):
return [getattr(self, custom_method)()\
for _ in range(num)]

Which would change nothing in ways of using Foo

>>> foo = Foo()
>>> foo.call_method_num_times('random_first_name')
['John']
>>> foo.call_method_num_times('random_phone', 2)
['0123456789', '9876543210']

Python, How to pass function to a class method as argument

You need to pass the class instance into the method too,
do this :

class myclass():
def __init__(self):
self.value = 6
def custom(self, func, **kwargs):
func(self, **kwargs) ## added self here
return self

c = myclass()
def add(self, **kwargs): ## added self here
self.value += kwargs['val']

kwargs = {'val': 4}
c.custom(add, **kwargs )
print (c.value)

output : 10

How to pass an instance method, that uses instance variables, as argument to another function?

For your second implementation, have you considered the following:

>>> myAa = A(42)
>>> myAb = A(43)
>>> myB = B(myAb)
>>> myB.run_function_2(myAa.foo)
42

This might not be what you want. How about using getattr() and just passing in the desired method name:

>>> class C:
... def __init__(self, A):
... self.A = A
... def run_fct(self, bar):
... fct = getattr(self.A, bar)
... fct()
...
>>> myC = C(myAa)
>>> myC.run_fct('foo')
42

How do I pass a pandas method as a parameter?

You can use [getattr][1] built-in and __name__ attribute to do so, but I guess it makes your code somewhat unclear. May be a better approach exists.

df = pd.DataFrame({'col1': list(range(5)), 'col2': list(range(5, 0, -1))})
df
Out:
col1 col2
0 0 5
1 1 4
2 2 3
3 3 2
4 4 1

Define my_func this way and apply it to df:

def my_func(df, pandas_stat):
for col in df.columns:
stat = getattr(df[col], pandas_stat.__name__)()
print(stat)

my_func(df, pd.DataFrame.mean)
Out
2.0
3.0

Explanation: pd.DataFrame.mean has attribute __name__ which value is 'mean'. Getattr can get this attribute from pd.DataFrame object, than you can call it.

You can even pass an arguments, if you need it:

def my_func(df, pandas_stat, *args, **kwargs):
for col in df.columns:
stat = getattr(df[col], pandas_stat.__name__)(*args, **kwargs)
print(stat)

my_func(df, pd.DataFrame.apply, lambda x: x ** 2)
Out:
0 0
1 1
2 4
3 9
4 16
Name: col1, dtype: int64
0 25
1 16
2 9
3 4
4 1
Name: col2, dtype: int64

But I repeat, I guess this approach is a little confusing.

Edit
About an error:

> my_func(A, pd.DataFrame.mode)
Traceback (most recent call last):

File "<ipython-input-334-dd913410abd0>", line 1, in <module>
my_func(A, pd.DataFrame.mode)

File "<ipython-input-329-8acf337bce92>", line 3, in my_func
stat = df[col].pandas_stat()

File "/anaconda3/envs/py36/lib/python3.6/site-packages/pandas/core/generic.py", line 4376, in __getattr__
return object.__getattribute__(self, name)

AttributeError: 'Series' object has no attribute 'pandas_stat'

When df[col].pandas_stat() is executed, a dot . operator invokes a __getattribute__ method of dataframe object. It is an analog of a getattr, but it gets self as a first argument automaticly.

So, the second is the 'name' of a method, which is 'pandas_stat' in your code. It breaks down the execution, because pandas dataframe has no attribute with a such name.

If you provide correct name of actual method ('mean', 'apply' or so) to the getattr, this function find this method in pd.DataFrame.__dict__ where all the methods are listed, and return it. So you can call it via (*args, **kwargs) syntax.

Pass method as a parameter on python

Uses getattr if you want to get the method from a string parameter.

class A:
def foo(self):
print("foo")

def access_to(c, method="foo"):
return getattr(c, method)

a = A()
b = 5
access_to(a)()
access_to(b)()

It prints foo for a, then it raises error for b

I have to say that I recommend not to abuse this type of functions unless you have to for some specific reasons.



Related Topics



Leave a reply



Submit