How to set multiple function keywords at once, in Python 2? - python

all.
I was wondering if it was possible to set multiple keywords at once (via list?) in a function call.
For example, if you do:
foo, bar = 1, 2
print(foo, bar)
The output is (1,2).
For the function
def printer(foo, bar)
print(foo,bar)
Is it possible to do something like:
printer([foo, bar] = [1,2])
where both keywords are being set with a list?
In particular, the reason why I ask is because I have a function that returns two variables, scale and offset:
def scaleOffset(...):
'stuff happens here
return [scale, offset]
I would like to pass both of these variables to a different function that accepts them as keywords, perhaps as a nested call.
def secondFunction(scale=None, offset=None):
'more stuff
So far I haven't found a way of doing a call like this:
secondFunction([scale,offset] = scaleOffset())

To pass args as a list
arg_list = ["foo", "bar"]
my_func(*arg_list)
To pass kwargs, use a dictionary
kwarg_dict = {"keyword": "value"}
my_func(**kwarg_dict)

Related

Pythonic way to override variables in function with arguments

New to python and have situation like this:
myfun.py:
def fun(x, ...):
par1 = ...
par2 = ...
... # many pars
parn = ...
return #*long and complicated function of all the pars and x inputs*
Sometimes I'd like to modify one or more of the pars without modifying myfun.py itself. I know I could:
Define every par as an argument to fun and give it a default value
Make a dictionary par_dict = {'par1': ..., ...} then wherever I have par1 in my return code replace it with par_dict['par1']. Then use par_dict.update() to take a dictionary argument and update my pars.
Any clean and compact alternatives to these options? I'd like something like this:
fun(x_in, par10=5)
# output uses 5 where par10 occurs in the function, in other words the argument to the function overrides the values set inside the function.
Thank you.
The most pythonic way I find is something like this:
First you define the function, such as
def fun(x, *, par1=1, par2=2, ..., parn=999):
return # function using all params
The function has its default settings, with the predefined values for the parameters. The * as second argument is to prevent the use of positional arguments for further than the x variable.
Then you may use configurable dictionaries to alter the params:
params = {
'par1': 10,
'par2': 20,
...
'parn': 0}
fun(X, **params)
The **params distributes the variables declared in the dictionary to the input parameters in the function.
EDIT It is also possible to use nested functions, like this:
def outer(par1=1, par2=2, ..., parn=999):
def inner(x):
return # function using x and pars...
return inner
Notice that the params of the outer function don't need to have default values. Then you "instance" the function, using it with any set of new params.
params = {...} # like the previous example
fun = outer(**params)
fun(X)
You can use outer to create different functions, that behaves as the params you input, for instance:
params1 = {...}
fun1 = outer(**params1)
params2 = {...}
fun2 = outer(**params2)
a = fun1(X)
b = fun2(X)
In this case a and b are different.

Calling a function depending on number of parametres in Python

Imagine this situation:
def foo1(item1, item2, item3):
pass
def foo2(item4, item5):
pass
item_to_pass = "random item"
x = 3
I need to call one of the functions which takes x arguments. As parameters, I want to pass item_to_pass (or any other variable).
Basically, I know how to find out how many parameters does a function have using inspect module. But what I don't know is how to call a certain function with those arguments (let's say those arguments are all the same). Also note that I can not pass a list of items as an argument instead of multiple parameters, I need to have different amount of arguments and based on that call the function.
Do you have any idea, how could I solve this?
Is this what you are looking for:
import inspect
def foo1(item1, item2, item3):
print("foo1 called")
def foo2(item4, item5):
print("foo2 called")
def fooWrapper(*args):
# map functions to function's arguments
funcs = {fn: len(inspect.getfullargspec(fn).args) for fn in (foo1, foo2)}
# lookup all functions that take the same amount of arguments as given.
for fn, argLen in funcs.items():
if len(args) == argLen:
fn(*args)
break
item_to_pass = "random item"
x = 3
foo1_Argument = "foo"
fooWrapper(item_to_pass, x)
fooWrapper(item_to_pass, x, foo1_Argument)
Out:
foo2 called
foo1 called

Calling function with dynamic args

I'm creating a function that takes in a callback function as an argument. I want to be able to use it like this:
def callback1(result, found_index):
# do stuffs
def callback2(result):
# do same stuffs even though it's missing the found_index parameter
somefunct(callback1)
somefunct(callback2)
# somefunct calls the callback function like this:
def somefunct(callback):
# do stuffs, and assign result and found_index
callback(result, found_index) # should not throw error
For context, I am somewhat trying to replicate how javascript's callback functions work for the .forEach function on arrays. You can make a function that takes in only the array item on that specific iteration, or the array item and index, or even the array item, index, and original array:
let some_array = ["apple", "orange", "banana"];
function callback1(value, index) {
console.log(`Item at index ${index}: ${value}`);
}
function callback2(value) {
console.log(`Value: ${value}`);
}
some_array.forEach(callback1); // runs with no errors
some_array.forEach(callback2); // runs with no errors
Furthermore, I don't want the callback function to force the * operator, but also allow them to use it if needed. Thank you, wonderful people of python.
(Posting this separately since it's fundamentally different to my other answer.)
If you need to pass a lot of values to some callbacks, without requiring other callbacks to declare a lot of unused parameters, a neat solution is to encapsulate all of those values in a single object. You can use collections.namedtuple to define a value type with named attributes, and then the callback can take one parameter and decide which attributes to use.
from collections import namedtuple
SomeFunctionResult = namedtuple('SomeFunctionResult', 'foo bar baz qux quz')
def some_function(callback):
result = SomeFunctionResult('foo', 'bar', 'baz', 'qux', 'quz')
callback(result)
Example:
>>> some_function(lambda r: print(r.foo, r.bar))
foo bar
>>> some_function(lambda r: print(r.baz, r.qux, r.quz))
baz qux quz
The downside is that this makes some_function less usable with existing functions which might expect to receive foo directly, rather than an object with a foo attribute. In that case, you have to write some_function(lambda r: blah(r.foo)) which is not as neat as some_function(blah).
The simplest approach would be to unify the signatures of your callbacks. Let's say you defined your forEach function as follows
def forEach(iterable, callback):
for index, elem in enumerate(iterable):
callback(elem, index)
You could then define Python analogs of the callack1 and callback2 Javascript functions as
def callback1(value, index):
print(f"Item at index {index}: {value}")
def callback2(value, _index):
print(f"Value: {value})
Rather than performing any complicated parameter-count-reasoning, exception handling, or dynamic dispatch within forEach, we delegate the decision of how to handle the value and index arguments to the callbacks themselves. If you need to adapt a single-parameter callback to work with forEach, you could simply use a wrapper lambda that discards the second argument:
forEach(some_iterable, lambda value, _index: callback(value))
However, at this point, you just have an obfuscated for loop, which would be much more cleanly expressed as
for elem in some_iterable:
callback(elem)
In this case, it is easier to ask for forgiveness than permission.
def some_function(callback):
result = 'foo'
found_index = 5
try:
callback(result, found_index)
except TypeError:
callback(result)
Example:
>>> some_function(print)
foo 5
>>> some_function(lambda x: print(x))
foo
this is the modified python code snippet you have provided that produces error , this works with no problem , you just have to unify the callback arguments number and type for each callback function called within the main function and define somefunc before calling it .
def callback1(result, found_index):
# do stuffs
result="overridden result in callback 1"
found_index ="overridden found_index in callback 1"
print(result,found_index)
def callback2(result,found_index):
# do same stuffs even though it's missing the found_index parameter
result="overridden result in callback 2"
print(result,found_index)
# somefunct calls the callback function like this:
def somefunct(callback):
# do stuffs, and assign result and found_index
result = "overridden result in somefunct"
found_index = "overridden index in somefunct"
callback(result, found_index) # NOW it should not throw error as the callback is fed with the 2 arguments used in callback1 and ignored in callback2
somefunct(callback1)
somefunct(callback2)
use optional arguments and check how much elemnts returned, sort of switch case:
https://linux.die.net/diveintopython/html/power_of_introspection/optional_arguments.html

Applying a list of functions to a single dynamic string

I'm creating a small python app that formats a file's name to a set of rules. I'm having problems finding a way of applying a list of general formatting functions to the same string. I want to apply one function, then another, then another.
I've managed to find a way that works, but I feel that it's very clumsy.
Here I have a list of lists that includes one function and a dictionary of the kwargs. (All of these functions have a "text" parameter that is not included in the dictionary).
functions = [
[SRF.change, {'old': '.', 'new': ' '}],
[SRF.surround, {'value': SU.get_year}],
[SRF.remove, {'chars': '[],'}],
[SRF.capitalize_words, {}],
[SRF.remove_including, {'value': 'mp4'}]]
I then pass it into the custom_rename function. It loops over the list of functions and applies it to the "text" variable. As you can see, the variable changes every time func(text, **kwargs) is called.
def custom_rename(text, functions_list):
# Apply a list of functions to a string
for func_list in functions_list:
func = func_list[0] # Function
kwargs = func_list[1] # Dictionary
try:
text = func(text, **kwargs)
except AttributeError:
pass
return text
Is there a more elegant way of doing this? I, for example, do not like that I have to know that the function is in position [0] and the dictionary is in [1].
Instead of storing [function, arguments] lists, you can use functools.partial to create callables with the arguments already baked in:
from functools import partial
functions = [
partial(SRF.change, old='.', new=' '),
partial(SRF.surround, value=SU.get_year),
partial(SRF.remove, chars='[],'),
SRF.capitalize_words,
partial(SRF.remove_including, value='mp4')
]
Now your custom_rename function can be simplified to this:
def custom_rename(text, functions_list):
# Apply a list of functions to a string
for func in functions_list:
try:
text = func(text)
except AttributeError:
pass
return text

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.

Categories