Calling function with unknown number of parameters - python

I am trying to create a set of functions in python that will all do a similar operation on a set of inputs. All of the functions have one input parameter fixed and half of them also need a second parameter. For the sake of simplicity, below is a toy example with only two functions.
Now, I want, in my script, to run the appropriate function, depending on what the user input as a number. Here, the user is the random function (so the minimum example works). What I want to do is something like this:
def function_1(*args):
return args[0]
def function_2(*args):
return args[0] * args[1]
x = 10
y = 20
i = random.randint(1,2)
f = function_1 if i==1 else function_2
return_value = f(x,y)
And it works, but it seems messy to me. I would rather have function_1 defined as
def function_1(x):
return x
Another way would be to define
def function_1(x,y):
return x
But that leaves me with a dangling y parameter.
but that will not work as easily. Is my way the "proper" way of solving my problem or does there exist a better way?

There are couple of approaches here, all of them adding more boiler-plate code.
There is also this PEP which may be interesting to you.
But 'pythonic' way of doing it is not as elegant as usual function overloading due to the fact that functions are just class attributes.
So you can either go with function like that:
def foo(*args):
and then count how many args you've got which will be very broad but very flexible as well.
another approach is the default arguments:
def foo(first, second=None, third=None)
less flexible but easier to predict, and then lastly you can also use:
def foo(anything)
and detect the type of anything in your function acting accordingly.
Your monkey-patching example can work too, but it becomes more complex if you use it with class methods, and does make introspection tricky.
EDIT: Also, for your case you may want to keep the functions separate and write single 'dispatcher' function that will call appropriate function for you depending on the arguments, which is probably best solution considering above.
EDIT2: base on your comments I believe that following approach may work for you
def weigh_dispatcher(*args, **kwargs):
#decide which function to call base on args
if 'somethingspecial' in kwargs:
return weight2(*args, **kwargs)
def weight_prep(arg):
#common part here
def weight1(arg1, arg2):
weitht_prep(arg1)
#rest of the func
def weight2(arg1, arg2, arg3):
weitht_prep(arg1)
#rest of the func
alternatively you can move the common part into the dispatcher

You may also have a function with optional second argument:
def function_1(x, y = None):
if y != None:
return x + y
else:
return x
Here's the sample run:
>>> function_1(3)
3
>>> function_1(3, 4)
7
Or even optional multiple arguments! Check this out:
def function_2(x, *args):
return x + sum(args)
And the sample run:
>>> function_2(3)
3
>>> function_2(3, 4)
7
>>> function_2(3, 4, 5, 6, 7)
25
You may here refer to args as to list:
def function_3(x, *args):
if len(args) < 1:
return x
else:
return x + sum(args)
And the sample run:
>>> function_3(1,2,3,4,5)
15

Related

Python function argument used as a function call in the return statement?

So I've come across the code below here, and I can't wrap my head around how the return statements work. operation is an argument in the functions seven and five but it's used as a function call in the return statements. What's happening here?
The code is :
def seven(operation = None):
if operation == None:
return 7
else:
return operation(7)
def five(operation = None):
if operation == None:
return 5
else:
return operation(5)
def times(number):
return lambda y: y * number
Edit: following #chepner comment this is how they are called, for example this:
print(seven(times(five())))
Those methods are basically allowing you to pass function objects which will be called. See this example
def square(x):
return x*x
def five(operation=None):
if operation is None:
return 5
else:
return operation(5)
I can now call five and pass square as the operation
>>> five(square)
25
What's happening here?
This code utilize that functions are first-class citizens in python, therefore functions might be passed as functions arguments. This ability is not unique to python language, but might be initally mind-boggling if you are accustomed to language without that feature.

How to pass function as variable with fixed argument

I'm newbie in Python, but the second time I encouter this problem.
Problem:
In some libraries there are functions with arguments. Sometimes there is argument as function, like this:
def somefun(fun):
x = [1,2,3]
z = fun(x)
return z
And I want to pass there some other function like this:
def func(x,y):
return x*y
which have more than one argument. I want to make one argument static, so somefun except func as argument.
Finally I want to make some kind of cycle where I can change static arg.
Something like this:
for i in xrange(1,9):
somefun(func(i,*))
Please do not offer me to change any functions. They are from library and it's not very comfortable to change them.
Thanks a lot!
You can use lambda statement:
somefun(lambda x: func(i, x))
It sure sounds like you are looking for functools.partial. From the docs:
functools.partial(func, *args, **keywords)
Return a new partial object which when called will behave like func called with the positional arguments args and keyword arguments keywords.
In your example, you could pass partial(func, 10) as the argument to somefun. Or you could create the partial objects and use them in a loop:
for i in xrange(1,9):
somefun(partial(func, i))
My solution with decorator
from functools import wraps
import numpy as np
def p_decorate(f):
#wraps(f)
def wrapped(*args):
z = f(*args)
return z
return wrapped
#p_decorate
def myfunc(a,b):
"""My new function"""
z = np.dot(a,b)
return z
x = [1,2,3]
y = [4,2,0]
r = myfunc(x,y)
print (r)
print (myfunc.__name__)
print (myfunc.__doc__)
You can change myfunc as you wish.You can also insert more function layers.Without the use of this decorator factory,you would lose the name of myfunc and the docstring.

Python why do my nested functions give a Nonetype error?

I'm new to programming.
def start():
x = 4
def addition():
n = 3
def exponential():
z = 2
def multiplication():
l = 2
print(x + n ** z * l)
return multiplication
equals = start()
equals()
why am I getting a "Nonetype" object is not callable error?
You're confusing a bunch of programming concepts:
Don't declare a function whenever you only need a statement
You're confusing function declaration with function call (invocation), and also the nesting is pointless. Declaring nested fn2 inside of fn1 doesn't magically also call fn2 and also transmit its return-value back to fn1. You still have to use an explicit return-statement from each fn.(If you forget that, you're implicitly returning None, which is almost surely not what you want)
For now, just don't ever nest functions at all.
Functions with no arguments are essentially useless, they can't take inputs and compute a result. Figure out what their arguments should be.
Specifically for the code you posted, addition(), multiplication() don't have any return value at all, i.e. None. exponential() returns multiplication, i.e. a function which only returns None. But then, both addition() and start() ignore that anyway, since they don't have a return-statement either, hence they implicitly return None.
Calling start() just gives you None, so you're just assigning equals = None. Not the result of some mathematical expression like you intended.
So:
reduce every unnecessary function to just a statement
declare each of your functions separately (non-nested)
each fn must have args (in this case at least two args, to make any sense)
each fn must have a return statement returning some value
only declaring a function and never calling it means it never gets run.
put an empty line in between function declarations (Then it's obvious if you forgot the return-statement)
Credits goes to #BrenBarn for being first to answer this. But I wanna post the code to make it more clear, and point out to some ways to make it better.
def start():
x = 4
def addition():
n = 3
def exponential():
z = 2
def multiplication():
l = 2
print (x + n ** z * l)
return multiplication()
return exponential()
return addition()
equals = start()
print equals #Output: 22
However, this is not the best way to list different methods. You should learn how to use a class in your python code.
I am going to define a class called "mathOperations". I will define three methods (functions): addition,exponential, multiplication. These functions are reusable.
class mathOperations():
def addition(self,x,y):
return x+y
def exponential(self,x,y):
return x**y
def multiplication(self,x,y):
return x*y
m= mathOperations()
z=2
l=2
x=4
n=3
result= m.addition(x,m.multiplication(m.exponential(n,z),l))
print result #Output:22
You should learn how to make your code reusable, try to google "procedural programming"; "Oriented Object Programming", or check "Learn Python the hard way" book. These are first and most used approach to make your code reusable. Think of it like a generic mathematical function to solve problems.

Is there a way to refer to the current function in python?

I want a function to refer to itself. e.g. to be recursive.
So I do something like that:
def fib(n):
return n if n <= 1 else fib(n-1)+fib(n-2)
This is fine most of the time, but fib does not, actually, refer to itself; it refers to the the binding of fib in the enclosing block. So if for some reason fib is reassigned, it will break:
>>> foo = fib
>>> fib = foo(10)
>>> x = foo(8)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in fib
TypeError: 'int' object is not callable
How can I prevent this from happening (from inside fib), if at all possible? As far as I know, the name of fib does not exist before the function-definition is fully executed; Are there any workarounds?
I don't have a real use case where it may actually happen; I am asking out of sheer curiosity.
I'd make a decorator for this
from functools import wraps
def selfcaller(func):
#wraps(func)
def wrapper(*args, **kwargs):
return func(wrapper, *args, **kwargs)
return wrapper
And use it like
#selfcaller
def fib(self, n):
return n if n <= 1 else self(n-1)+self(n-2)
This is actually a readable way to define a Fixed Point Combinator (or Y Combinator):
fix = lambda g: (lambda f: g(lambda arg: f(f)(arg))) (lambda f: g(lambda arg: f(f)(arg)))
usage:
fib = fix(lambda self: lambda n: n if n <= 1 else self(n-1)+self(n-2))
or:
#fix
def fib(self):
return lambda n: n if n <= 1 else self(n-1)+self(n-2)
The binding here happens in the formal parameter, so the problem does not arise.
There's no way to do what you're trying to do. You're right that fib does not exist before the function definition is executed (or, worse, it exists but refers to something completely different…), which means there is no workaround from inside fib that can possibly work.*
However, if you're willing to drop that requirement, there are workarounds that do work. For example:
def _fibmaker():
def fib(n):
return n if n <= 1 else fib(n-1)+fib(n-2)
return fib
fib = _fibmaker()
del _fibmaker
Now fib is referring to the binding in the closure from the local environment of a call to _fibmaker. Of course even that can be replaced if you really want to, but it's not easy (the fib.__closure__ attribute is not writable; it's a tuple, so you can't replace any of its cells; each cell's cell_contents is a readonly attribute, …), and there's no way you're going to do it by accident.
There are other ways to do this (e.g., use a special placeholder inside fib, and a decorator that replaces the placeholder with the decorated function), and they're all about equally unobvious and ugly, which may seem to violate TOOWTDI. But in this case, the "it" is something you probably don't want to do, so it doesn't really matter.
Here's one way you can write a general, pure-python decorator for a function that uses self instead of its own name, without needing an extra self parameter to the function:
def selfcaller(func):
env = {}
newfunc = types.FunctionType(func.__code__, globals=env)
env['self'] = newfunc
return newfunc
#selfcaller
def fib(n):
return n if n <= 1 else self(n-1)+self(n-2)
Of course this won't work on a function that has any free variables that are bound from globals, but you can fix that with a bit of introspection. And, while we're at it, we can also remove the need to use self inside the function's definition:
def selfcaller(func):
env = dict(func.__globals__)
newfunc = types.FunctionType(func.__code__, globals=env)
env[func.__code__.co_name] = newfunc
return newfunc
This is Python 3.x-specific; some of the attribute names are different in 2.x, but otherwise it's the same.
This still isn't 100% fully general. For example, if you want to be able to use it on methods so they can still call themselves even if the class or object redefines their name, you need slightly different tricks. And there are some pathological cases that might require building a new CodeType out of func.__code__.co_code. But the basic idea is the same.
* As far as Python is concerned, until the name is bound, it doesn't exist… but obviously, under the covers, the interpreter has to know the name of the function you're defining. And at least some interpreters offer non-portable ways to get at that information.
For example, in CPython 3.x, you can very easily get the name of the function currently being defined—it's just sys._getframe().f_code.co_name.
Of course this won't directly do you any good, because nothing (or the wrong thing) is bound to that name. But notice that f_code in there. That's the current frame's code object. Of course you can't call a code object directly, but you can do so indirectly, either by generating a new function out of it, or by using bytecodehacks.
For example:
def fib2(n):
f = sys._getframe()
fib2 = types.FunctionType(f.f_code, globals=globals())
return n if n<=1 else fib2(n-1)+fib2(n-2)
Again, this won't handle every pathological case… but the only way I can think of to do so is to actually keep a circular reference to the frame, or at least its globals (e.g., by passing globals=f.f_globals), which seems like a very bad idea.
See Frame Hacks for more clever things you can do.
Finally, if you're willing to step out of Python entirely, you can create an import hook that preprocesses or compiles your code from a Python custom-extended with, say, defrec into pure Python and/or bytecode.
And if you're thinking "But that sounds like it would be a lot nicer as a macro than as a preprocessor hack, if only Python had macros"… then you'll probably prefer to use a preprocessor hack that gives Python macros, like MacroPy, and then write your extensions as macros.
Like abamert said "..there is no way around the problem from inside ..".
Here's my approach:
def fib(n):
def fib(n):
return n if n <= 1 else fib(n-1)+fib(n-2)
return fib(n)
Someone asked me for a macro based solution for this, so here it is:
# macropy/my_macro.py
from macropy.core.macros import *
macros = Macros()
#macros.decorator()
def recursive(tree, **kw):
tree.decorator_list = []
wrapper = FunctionDef(
name=tree.name,
args=tree.args,
body=[],
decorator_list=tree.decorator_list
)
return_call = Return(
Call(
func = Name(id=tree.name),
args = tree.args.args,
keywords = [],
starargs = tree.args.vararg,
kwargs = tree.args.kwarg
)
)
return_call = parse_stmt(unparse_ast(return_call))[0]
wrapper.body = [tree, return_call]
return wrapper
This can be used as follows:
>>> import macropy.core.console
0=[]=====> MacroPy Enabled <=====[]=0
>>> from macropy.my_macro import macros, recursive
>>> #recursive
... def fib(n):
... return n if n <= 1 else fib(n-1)+fib(n-2)
...
>>> foo = fib
>>> fib = foo(10)
>>> x = foo(8)
>>> x
21
It basically does exactly the wrapping that hus787 gave:
Create a new statement which does return fib(...), which uses the argument list of the original function as the ...
Create a new def, with the same name, same args, same decorator_list as the old one
Place the old function, together followed by the return statement, in the body of the new functiondef
Strip the original function of its decorators (I assume you'd want to decorate the wrapper instead)
The parse_stmt(unparse_ast(return_call))[0] rubbish is a quick hack to get stuff to work (you actually can't just copy the argument AST from the param list of the function and use them in a Call AST) but that's just detail.
To show that it's actually doing that, you can add a print unparse_ast statement to see what the transformed function looks like:
#macros.decorator()
def recursive(tree, **kw):
...
print unparse_ast(wrapper)
return wrapper
which, when run as above, prints
def fib(n):
def fib(n):
return (n if (n <= 1) else (fib((n - 1)) + fib((n - 2))))
return fib(n)
Looks like exactly what you want! It should work for any function, with multiple args, kwargs, defaults, etc., but I'm too lazy to test. Working with the AST is a bit verbose, and MacroPy is still super-experimental, but i think it's pretty neat.

Ignore python multiple return value

Say I have a Python function that returns multiple values in a tuple:
def func():
return 1, 2
Is there a nice way to ignore one of the results rather than just assigning to a temporary variable? Say if I was only interested in the first value, is there a better way than this:
x, temp = func()
You can use x = func()[0] to return the first value, x = func()[1] to return the second, and so on.
If you want to get multiple values at a time, use something like x, y = func()[2:4].
One common convention is to use a "_" as a variable name for the elements of the tuple you wish to ignore. For instance:
def f():
return 1, 2, 3
_, _, x = f()
If you're using Python 3, you can you use the star before a variable (on the left side of an assignment) to have it be a list in unpacking.
# Example 1: a is 1 and b is [2, 3]
a, *b = [1, 2, 3]
# Example 2: a is 1, b is [2, 3], and c is 4
a, *b, c = [1, 2, 3, 4]
# Example 3: b is [1, 2] and c is 3
*b, c = [1, 2, 3]
# Example 4: a is 1 and b is []
a, *b = [1]
The common practice is to use the dummy variable _ (single underscore), as many have indicated here before.
However, to avoid collisions with other uses of that variable name (see this response) it might be a better practice to use __ (double underscore) instead as a throwaway variable, as pointed by ncoghlan. E.g.:
x, __ = func()
Remember, when you return more than one item, you're really returning a tuple. So you can do things like this:
def func():
return 1, 2
print func()[0] # prints 1
print func()[1] # prints 2
The best solution probably is to name things instead of returning meaningless tuples (unless there is some logic behind the order of the returned items). You can for example use a dictionary:
def func():
return {'lat': 1, 'lng': 2}
latitude = func()['lat']
You could even use namedtuple if you want to add extra information about what you are returning (it's not just a dictionary, it's a pair of coordinates):
from collections import namedtuple
Coordinates = namedtuple('Coordinates', ['lat', 'lng'])
def func():
return Coordinates(lat=1, lng=2)
latitude = func().lat
If the objects within your dictionary/tuple are strongly tied together then it may be a good idea to even define a class for it. That way you'll also be able to define more complex operations. A natural question that follows is: When should I be using classes in Python?
Most recent versions of python (≥ 3.7) have dataclasses which you can use to define classes with very few lines of code:
from dataclasses import dataclass
#dataclass
class Coordinates:
lat: float = 0
lng: float = 0
def func():
return Coordinates(lat=1, lng=2)
latitude = func().lat
The primary advantage of dataclasses over namedtuple is that its easier to extend, but there are other differences. Note that by default, dataclasses are mutable, but you can use #dataclass(frozen=True) instead of #dataclass to force them being immutable.
Here is a video that might help you pick the right data class for your use case.
Three simple choices.
Obvious
x, _ = func()
x, junk = func()
Hideous
x = func()[0]
And there are ways to do this with a decorator.
def val0( aFunc ):
def pick0( *args, **kw ):
return aFunc(*args,**kw)[0]
return pick0
func0= val0(func)
This seems like the best choice to me:
val1, val2, ignored1, ignored2 = some_function()
It's not cryptic or ugly (like the func()[index] method), and clearly states your purpose.
If this is a function that you use all the time but always discard the second argument, I would argue that it is less messy to create an alias for the function without the second return value using lambda.
def func():
return 1, 2
func_ = lambda: func()[0]
func_() # Prints 1
This is not a direct answer to the question. Rather it answers this question: "How do I choose a specific function output from many possible options?".
If you are able to write the function (ie, it is not in a library you cannot modify), then add an input argument that indicates what you want out of the function. Make it a named argument with a default value so in the "common case" you don't even have to specify it.
def fancy_function( arg1, arg2, return_type=1 ):
ret_val = None
if( 1 == return_type ):
ret_val = arg1 + arg2
elif( 2 == return_type ):
ret_val = [ arg1, arg2, arg1 * arg2 ]
else:
ret_val = ( arg1, arg2, arg1 + arg2, arg1 * arg2 )
return( ret_val )
This method gives the function "advanced warning" regarding the desired output. Consequently it can skip unneeded processing and only do the work necessary to get your desired output. Also because Python does dynamic typing, the return type can change. Notice how the example returns a scalar, a list or a tuple... whatever you like!
When you have many output from a function and you don't want to call it multiple times, I think the clearest way for selecting the results would be :
results = fct()
a,b = [results[i] for i in list_of_index]
As a minimum working example, also demonstrating that the function is called only once :
def fct(a):
b=a*2
c=a+2
d=a+b
e=b*2
f=a*a
print("fct called")
return[a,b,c,d,e,f]
results=fct(3)
> fct called
x,y = [results[i] for i in [1,4]]
And the values are as expected :
results
> [3,6,5,9,12,9]
x
> 6
y
> 12
For convenience, Python list indexes can also be used :
x,y = [results[i] for i in [0,-2]]
Returns : a = 3 and b = 12
It is possible to ignore every variable except the first with less syntax if you like. If we take your example,
# The function you are calling.
def func():
return 1, 2
# You seem to only be interested in the first output.
x, temp = func()
I have found the following to works,
x, *_ = func()
This approach "unpacks" with * all other variables into a "throwaway" variable _. This has the benefit of assigning the one variable you want and ignoring all variables behind it.
However, in many cases you may want an output that is not the first output of the function. In these cases, it is probably best to indicate this by using the func()[i] where i is the index location of the output you desire. In your case,
# i == 0 because of zero-index.
x = func()[0]
As a side note, if you want to get fancy in Python 3, you could do something like this,
# This works the other way around.
*_, y = func()
Your function only outputs two potential variables, so this does not look too powerful until you have a case like this,
def func():
return 1, 2, 3, 4
# I only want the first and last.
x, *_, d = func()

Categories

Resources