Passing arguments of a function as parameter names in other function - python

Lets assume we have two functions foo and get_idin Python3. I want to call the get_id function inside the foo function while using an argument of the foo function as an argument name in the get_id function. For example:
I call the foo function:
result = foo("Person","name","John")
while the body of the function is:
def foo(arg_1, arg_2, arg_3):
res = get_id(arg_1, arg_2 = arg_3)
return res
What i want is:
res = get_id("Person", name = "John")
so that the get_id function will be parameterized by the arg_2 argument of the foo function. However, the way i am doing it so far results in error as python interpretes it as a String.Any advice is welcome.

I should probably not try to understand why you want to do this :) but here is a solution maybe:
def foo(arg_1, arg_2, arg_3):
kwargs = {
'arg_1_name': arg_1,
arg_2: arg_3,
}
return get_id(**kwargs)
just make sure to replace arg_1_name with the actual name of the parameter used in the get_id function

This is the way to pass parameter name as string :
def test(a):
print(a)
test(**{'a': 'hello world'})
I'm sure you can adapt this solution to your problem

Related

python: passing an Instance Method and its argument to function for execution

I know how to pass a function as argument, and then use the function later. However I could not figure out how to do this with a method. I'd like to provide users with an "API" that allows them to configure custom functions.
As a (not) working example, let's say I want the user to be able to supply some general pandas function:
import pandas as pd
# user-supplied data
right = pd.DataFrame({'right_a':[1,2],
'right_b':[3,4]})
# user-supplied function & arguments
myfun = pd.DataFrame.merge
args = {'right':right,
'right_on':'right_a',
'how':'inner'
}
user_configs = {'func': myfun,
'args':args}
def exec_func(exec_dict):
# some data that only the function knows:
left = pd.DataFrame({'left_a':[1,2],'left_b':['foo','bar']})
# some args that only the function knows
exec_dict['args']['left_on'] = 'left_a'
# apply the function
#result = left.merge(**exec_dict['args']) # desired result
result = left.exec_dict['func'](**exec_dict['args']) # generalized but not working code
return result
exec_func(user_configs)
the above code result in a
AttributeError: 'DataFrame' object has no attribute 'exec_dict'
for obvious reasons. How could i achieve the desired behavior, that allows the user to supply different functions?
So I have simplified your problem a little and omitted pandas. The way to go about calling a method of an instance by name is via the getattribute method:
class MethodProvider (object):
def __init__(self):
pass
def method1(self, foo):
print('Method1 was called with arguments %s'%foo)
def method2(self, baz):
print('Method2 was called with argument %s'%baz)
def exec_method(obj, meth, kwargs):
func = obj.__getattribute__(meth)
func(**kwargs)
# Test construction
mp = MethodProvider()
exec_method(
mp,
'method1',
{'foo': 'bar'}
)
exec_method(
mp,
'method2',
{'baz': 'buzz'}
)
Methods are, loosely speaking, functions that receive the instance as the first argument. exec_dict['func'] already is the method, it does not need to be looked up on left. Simply pass left as the first argument.
# |method/function|| called with... |
result = exec_dict['func'](left, **exec_dict['args'])
# | instance
# | further arguments
This code works for any callable that takes the dataframe left as its first argument, not just dataframe methods.
Instead of expecting func and args wrapped in a dictionary, exec_func can directly receive them. left_on can also be passed directly.
def exec_func(func, **args):
left = pd.DataFrame({'left_a':[1,2],'left_b':['foo','bar']})
# apply the function
result = func(left, left_on='left_a', **args)
return result
exec_func(**user_configs)
Note that it is customary to use args for positional and kwargs for keyword arguments/parameters, i.e. def exec_func(func, *args, **kwargs): ....

Redefining a function by supplying some of its arguments

let's suppose there is a function like below:
def func(arg1, args2):
# do sth using arg1 and arg2
In the runtime, I would like to keep use some value for args2 which we can't know when defining the func.
So what I would like to do is:
func_simpler = func(, args2=some_value_for_arg2)
func_simpler(some_value_for_arg1) # actual usage
Any idea on it? I know that there is a walk-around such as defining func better, but I seek for a solution more like func_simpler thing.
Thanks in advance!
You can use lambda in python
Original function
def func(arg1, arg2):
Then you get the value you want as default for arg2 and define simple_func
simple_func = lambda arg1 : func(arg1, arg2=new_default)
Now you can run simple_func
simple_func("abc") #"abc" = value for arg1
Hope I could help you
I was trying to solve this myself and I found a not-bad solution:
def func(a, b):
print(a, ": variable given everytime the model is used")
print(b, ": variable given when the model is defined")
enter code here
def model(b):
def model_deliver(a):
func(a, b)
return model_deliver
s = model(20)
s(12) #prints result as below
# 12 : variable given everytime the model is used
# 20 : variable given when the model is defined
Use functools.partial:
from functools import partial
def func(arg1, arg2):
print(f'got {arg1!r} and {arg2!r}')
simple_func = partial(func, arg2='something')
simple_func("value of arg1")
# got 'value of arg1' and 'something'
Using partial produces an object which has various advantages over using a wrapper function:
If the initial function and its arguments can be pickled, the partial object can be pickled as well.
The repr/str of a partial object shows the initial function information.
Repeated application of partial is efficient, as it flattens the wrappers.
The function and its partially applied arguments can be inspected.
Note that if you want to partially apply arguments of a method, use functools.partialmethod instead.

Getting inputs to a function from a python object

I have a class. This class has a list of functions that are to be evaluated by a different program.
class SomeClass(object):
def __init__(self, context):
self.functions_to_evaluate = []
There is a function that adds functions to an instance of SomeClass, via something like:
new_function = check_number(5)
SomeClassInstance.functions_to_evaluate.append(new_function)
Where check_number is a function that will check if number is greater than 10, let's say.
If I take SomeClassInstance.functions_to_evaluate and print it, I get a bunch of python objects, like so:
<some_library.check_number object at 0x07B35B90>
I am wondering if it is possible for me to extract the input given to check_number, so something like:
SomeClassInstance.functions_to_evaluate[0].python_feature() that will return "5" or whatever the input to check_number was to me.
You can use the standard library functools.partial, which creates a new partially applied function *.
>>> from functools import partial
>>> def check_number(input):
... return input > 10
>>> fn = partial(check_number, 5)
>>> fn.args # this attribute gives you back the bound arguments, as a tuple.
(5,)
>>> fn() # calls the function with the bound arguments.
False
*: actually the partial object is not a function instance, but it is a callable, and from a duck-type perspective it's a function.
If new_function = check_number(5) is a closure, then you can extract this value using __closure__[0].cell_contents:
Example:
def foo(x):
def inn(y):
return x
return inn
s = foo(5)
print(s.__closure__[0].cell_contents)
Output:
5
I understand your confusion, but:
new_function = check_number(5)
Is calling the function, and the new_function variable gets assigned the return value of the function.
If you have this check_number function:
def check_number(input):
return input > 10
Then it will return False, and new_function will be False. Never <some_library.check_number object at 0x07B35B90>.
If you're getting <some_library.check_number object at 0x07B35B90> then your check_number() function is returning something else.
There are probably several ways to skin this cat. But I'd observe first and foremost that you're not adding python function objects to the functions_to_evaluate list, you're adding the evaluations of functions.
You could simply add a tuple of function, args to the list:
SomeClassInstace.functions_to_evaluate.append((check_number, 5))
And then you can:
for f, args in SomeClassInstance.functions_to_evaluate:
print(args)

Python notation or operation "**"

I saw the following code:
def __init__(self, fn, **kw):
[setattr(self,k,v) for (k,v) in kw.items()]
......
What does the input argument **kw mean?
kw is bound to a dict mapping keyword argument names to their values.
Try calling
def return_kwargs(**kw):
return kw
as return_kwargs(foo=1, bar="2", baz="hamspamspam").
Suppose you have a dict kw = {'a':1,'b':2}, then calling myfunction(**kw) is equivalent to calling myfunction(a=1,b=2).
This particular construction means what all keyword arguments for the constructor will end up as object attributes.
foo = Foo( func, bar = 1, baz = "aa" )
this would create an object with attribute "bar" set to 1 and "baz" to "aa"
Inside the function, kw is a dictionary that contains all the keyword=value arguments that you gave to your function:
def demo(**kw):
print kw
demo(a=1, b="hello")
Run the above and it will display a dictionary with two keys, a and b. So it works as a way to accept any keyword argument you decide to use when you call the function.
That's what it does. Why would anyone want to do that? Perhaps in a function that calls another function (given as a separate argument), and **kw is to hold options for the second function.

Error calling function from dictionary

I just want to create a class with a lot of functions which need to import some variables of the class for there output. To make the use more efficient i wanted to store the functions in a dictionary, but somehow that is not working at all...
class A(object):
var = 'hello'
def g(self,x):
return self.var
dict = {'g':g}
if __name__ == "__main__":
a = A()
print a.g(0)
print a.dict['g'](0)
OUTPUT
hello
print a.dict['g'](0)
TypeError: g() takes exactly 2 arguments (1 given)
what is happening within the dictionary with the function g???
When a function is called as a method, it implicitly gets the invocant as first argument. But that's not the case when you pull it out of the dict. You you'd have to call
print a.dict['g'](a, 0)
On a side note, I'd expect the call through dict to be slower, not faster, because you first need to get the dict from the object, which is itself basically equivalent to getting the method.
In addition to Jan Hudec's answer, you could also do without dict entirely by using the getattr() built-in function, like so:
class A(object):
var = 'hello'
def g(self,x):
return self.var
if __name__ == '__main__':
a = A()
print a.g(0)
print getattr(a, 'g')(0)
With the advantage of keeping your classes clean.

Categories