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:
- Define a function
with_price
def with_price(price: float, factor: float = 2.0):
return (price * factor)
- Define the function
a_method
. Note howmyfunction
is a generic parameter, not the function we just defined:
def a_method(a: float, myfunction):
b = myfunction(11)
return a * b
- Finally, call
a_method
, passingwith_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 followsclass 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
How to Compute the Intersection Point of Two Lines
Making All Possible Combinations of a List
Programmatically Saving Image to Django Imagefield
Finding Median of List in Python
Setting Different Color for Each Series in Scatter Plot on Matplotlib
Python Sharing a Lock Between Processes
Multiple Modeladmins/Views for Same Model in Django Admin
How to Get My Program to Sleep for 50 Milliseconds
How to Use Argsort in Descending Order
Pyaudio Working, But Spits Out Error Messages Each Time
How to Append One String to Another in Python
How to Sandbox Python in Pure Python
Python/Numpy First Occurrence of Subarray
Differencebetween Drawing Plots Using Plot, Axes or Figure in Matplotlib
Plotting a 2D Heatmap with Matplotlib
Why Does Assigning to My Global Variables Not Work in Python