Python: how to pass argument name using variable - python

A module I'm using has many functions defined with different argument names more or less serving the same purpose:
def func1(start_date):
....
def func2(startdate):
....
def func3(s_date):
....
def func4(sdate):
....
and they appear all in different positions of the argument list (in the above simplified case they're all in position 1, but in reality that's not the case).
I want to write a wrapper that can pass the actual start_date to any of these functions via a dictionary from function name to argument name:
def func2arg_name():
return {'func1' : 'start_date',
'func2' : 'startdate',
'func3' : 's_date',
'func4' : 'sdate' }
Then the actual wrapper:
f2a = func2arg_name()
def func(func_name, sdate):
locals()[func_name](f2a[func_name] = sdate)
func('func1', '20170101')
Clearly this doesn't work. Essentially the f2a[func_name] is not being recognized as a legit keyword. Does any one know how to do this, i.e. pass the argument name using a variable? Note func1 to func4 are externally defined and cannot be changed.

Make a dict with the argument name as the key, and pass it using unpack operator:
locals()[func_name](**{f2a[func_name]: sdate})
See Unpacking argument lists in the Python tutorial.

Related

How to generate a new function name from an other one

Let us give an example.
If we have a function def f(func): ..., where func is a parameter corresponding to a function.
If we make the following call f(merge), I would like to return another function name (not a text) merge_ext that could be then executed.
I have identified the fact that a function name col be extract with the syntax my_function.__name__, but how can I generate the new function name that could be used as a function?
It looks like you're after decorators.
A decorator is a function that takes a function as arguments, and returns a function. Simple example :
def simple_decorator(func):
return func
You can use it with the # syntax :
#simple_decorator
def decorated_function(some_arg):
return something
In that case, calling function will call the function returned by the call simple_decorator(function), which means you cannot access the orginal function anymore.
But this can also be expressed like this :
def no_yet_decorated_function(some_arg):
return something
decorated_function = simple_decorator(no_yet_decorated_function)
Now, you can access both your functions.

Python - Passing Functions with Arguments as Arguments in other Functions

I'm new to programming and I've been stuck on this issue and would really like some help!
One of the parameters in my function is optional, but can take on multiple default values based on another function. Both functions take in the same input (among others). When I try to assign a default using the function as illustrated below:
def func(foo):
# returns different values of some variable k based on foo
def anotherFunc(foo, bar, k=func(foo)):
# this is the same foo input as the previous function
I get the following error:
NameError: name 'foo' is not defined
The thing is, the user can call 'anotherFunc' with any value of 'k' they want, which complicates things. Is there any way to have a function with arguments in it as a parameter in another function? Or is there any way for me to set multiple default values of 'k' based on the previous function while still allowing the user to choose their own 'k' if they wanted?
Thanks!
foo at the moment of defining the function acts as placeholder for the first function argument. It has no value until the function is called, for which its value can be accessed in the function body, like so:
def another_func(foo, bar, k=None):
if k is None:
k = func(foo)
...
You would probably want to do something like:
def func(foo):
return foo
def anotherfunc(foo, bar, k=None):
if k == None:
k = func(foo)
#process whatever

forcing value of lambda inner scope variable to outer variable - python

I have already found various answers to this question (eg. lambda function acessing outside variable) and all point to the same hack, namely (eg.) lambda n=i : n*2 with i a variable in the external scope of lambda (hoping I'm not misusing the term scope). However, this is not working and given that all answers I found are generally from couple of years ago, I thought that maybe this has been deprecated and only worked with older versions of python. Does anybody have an idea or suggestion on how to solve this?
SORRY, forgot the MWE
from inspect import getargspec
params = ['a','b']
def test(*args):
return args[0]*args[1]
func = lambda p=params : test(p)
I expected the signature of func to be ['a','b'] but if I try
func(3,2)
I get a Type error (TypeError: <lambda>() takes at most 1 argument (2 given) )
and it's true signature (from getargspec(func)[0] ) is ['p']
In my real code the thing is more complicated. Shortly:
def fit(self, **kwargs):
settings = self.synch()
freepars = self.loglike.get_args()
func = lambda p=freeparams : self.loglike(p)
minuit = Minuit(func,**settings)
I need lambda because it's the only way I could think to create inplace a function object depending on a non-hardcoded list of variables (extracted via a method get_params() of the instance self.loglike). So func has to have the correct signature, to match the info inside the dict settings
The inspector gives ['p'] as argument of func, not the list of parameters which should go in loglike. Hope you can easily spot my mistake. Thank you
There's no way to do exactly what you want. The syntax you're trying to use to set the signature of the function you're creating doesn't do what you want. It instead sets a default value for the argument you've defined. Python's function syntax allows you to define a function that accepts an arbitrary number of arguments, but it doesn't let you define a function with argument names in a variable.
What you can do is accept *args (or **kwargs) and then do some processing on the value to match it up with a list of argument names. Here's an example where I turn positional arguments in a specific order into keyword arguments to be passed on to another function:
arg_names = ['a', 'b']
def foo(*args):
if len(args) != len(arg_names):
raise ValueError("wrong number of arguments passed to foo")
args_by_name = dict(zip(arg_names, args))
some_other_function(**args_by_name)
This example isn't terribly useful, but you could do more sophisticated processing on the args_by_name dict (e.g. combining it with another dict), which might be relevant to your actual use case.

How to pass extra arguments to callback register functions with twisted python api?

I have the following python code using the twisted API.
def function(self,filename):
def results(result):
//do something
for i in range(int(numbers)) :
name = something that has to do with the value of i
df = function_which_returns_a defer(name)
df.addCallback(results)
It uses the Twisted API. What i want to achieve is to pass to the callbacked function (results) the value of the name which is constructed in every iteration without changing the content of the functions_which_returns_a defer() function along with the deferred object of course. In every result of the functions_which_returns_a deffer the value of the name should be passed to results() to do something with this. I.e: at the first iteration when the execution reach the results function i need the function hold the result of the deffered object along with the value of name when i=0,then when i=1 the defered object will be passed with the value of name, and so on.So i need every time the result of the defer object when called with the name variable alond with the name variable. When i try to directly use the value of nameinside results() it holds always the value of the last iteration which is rationale, since function_which_returns_a defer(name) has not returned.
You can pass extra arguments to a Deferred callback at the Deferred.addCallback call site by simply passing those arguments to Deferred.addCallback:
def function(self,filename):
def results(result, name):
# do something
for i in range(int(numbers)) :
name = something that has to do with the value of i
df = function_which_returns_a defer(name)
df.addCallback(results, name)
You can also pass arguments by keyword:
df.addCallback(results, name=name)
All arguments passed like this to addCallback (or addErrback) are passed on to the callback function.

Dynamic Keyword Arguments in Python?

Does python have the ability to create dynamic keywords?
For example:
qset.filter(min_price__usd__range=(min_price, max_price))
I want to be able to change the usd part based on a selected currency.
Yes, It does. Use **kwargs in a function definition.
Example:
def f(**kwargs):
print kwargs.keys()
f(a=2, b="b") # -> ['a', 'b']
f(**{'d'+'e': 1}) # -> ['de']
But why do you need that?
If I understand what you're asking correctly,
qset.filter(**{
'min_price_' + selected_currency + '_range' :
(min_price, max_price)})
does what you need.
You can easily do this by declaring your function like this:
def filter(**kwargs):
your function will now be passed a dictionary called kwargs that contains the keywords and values passed to your function. Note that, syntactically, the word kwargs is meaningless; the ** is what causes the dynamic keyword behavior.
You can also do the reverse. If you are calling a function, and you have a dictionary that corresponds to the arguments, you can do
someFunction(**theDictionary)
There is also the lesser used *foo variant, which causes you to receive an array of arguments. This is similar to normal C vararg arrays.
Yes, sort of.
In your filter method you can declare a wildcard variable that collects all the unknown keyword arguments. Your method might look like this:
def filter(self, **kwargs):
for key,value in kwargs:
if key.startswith('min_price__') and key.endswith('__range'):
currency = key.replace('min_price__', '').replace('__range','')
rate = self.current_conversion_rates[currency]
self.setCurrencyRange(value[0]*rate, value[1]*rate)

Categories

Resources