Is it possible to unpack values into several functions? - python

Is it possible to unpack elements in python and pass them directly into several functions without assigning them into a variable first?
e. g.
def my_function():
return (1, 2)
# Not sure how the syntax would look like?
(function_1(#first element here), function_2(#second element here)) <= my_function()

It is possible, to not assign your output to any variable, for example by calling the function twice, which theoretically would make only sense if the function is a pure function. However I do not find any useful example. I am curious why you would like to do it.

There is a way around achieving that goal.
This, it would require you to create your own method that does that.
Here is a simple approach of how you might want to do that.
In my example, there is a function called dissolve_args_to_fns which accepts functions and a list that hold values to the functions input.
dissolve_args_to_fns implementation
from typing import Tuple, Any
from collections.abc import Iterable
def dissolve_args_to_fns(*fns, inputs: Tuple[Any, ...]):
# If there are more inputs than there are functions, and vice-versa, throw error
if len(fns) != len(inputs):
raise ValueError('The numbers of functions dont match the number of inputs each function')
# Holds the output corresponding to each function
outputs = []
for i, fn in enumerate(fns):
# Individual input for each function
inp = inputs[i]
# Checks if the input for the function is an iterable
# If so, then its probably for an argument that need multiple arguments
if isinstance(inp, Iterable) :
fn_out = fn(*inp)
else:
fn_out = fn(inp)
outputs.append(fn_out)
# returns an output if, there is any function that has an output
# This extra checking step is not necessary
if any(map(lambda x: x is not None, outputs)):
return outputs
Now that the function is done, we can begin testing it out.
Below, are 3 custom functions, some of which have an output, and others which don't
def show(value):
print("Here is", value)
def blink(value, blink_count:int = 2):
print(f" *blink* {value}" * blink_count)
def full_name(first_name, last_name) -> str:
return "%s %s" % (first_name, last_name)
I'll also be using the sum in-built function to show how wide this implementation can be used
_, name, _, _sum = dissolve_args_to_fn(show, full_name, blink, sum, inputs=(1, 2, ("Mike", "Tyson"), ([10, 5],)))
print("My name is", name)
print("Sum is:", _sum)
Well that's it. This simple function now works like magic.
Happy coding.
PS: As you can see, the simple implementation doesn't work for keyword arguments, but feel free to hack the code as a you please

The following is to the effect of what you described in your further comments:
list1 = []
list2 = []
def my_function():
return (1, 2)
def function_1(x1):
list1.append(x1)
def function_2(x2):
list2.append(x2)
lam = lambda x: (function_1(x[0]), function_2(x[1]))
lam(my_function())
Verification:
>>> print(list1)
[1]
>>> print(list2)
[2]

Related

Calling function with unknown number of parameters

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

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.

How can a function return a dynamic value that depends on the number of receivers in Python?

I was trying to do a "strange" (but useful in my case) function that can return a dynamic list whose len depends on the amount of receiver.
For example:
f() returns a dynamic list of None, so I can do the following:
a = f() => a = None
a, b = f() => a=b= None
(a, b) = f() => a=b= None
(a, b, c, d, e, f) = f() => a=b=c=d=e=f= None
I think this might be done via generator comprehension or iterator, but I was blocked on how to get the amount of recevier. Maybe I was in the wrong direction. Would you advise me some tips?
Any helps will be appreciated.
Many Thank,
Tiezhen
This is not possible in Python. The function on the right hand site has no knowledge of the context it was called in. The right hand site is evaluated before any of the name bindings take place.
Unfortunately, Python unpacks returned tuples using the Pythonic "it's easier to ask forgiveness than permission" approach. That is, if you have a statement:
a,b,c = f()
Behind the scenes, it's doing something along the lines of:
try:
a = returned[0]
b = returned[1]
c = returned[2]
except IndexError:
raise ValueError('need more than k values to unpack')
try:
_ = returned[4]
except IndexError:
pass
else:
raise ValueError('too many values to unpack')
So it's discovering dynamically the number of values returned. Unfortunately, that precludes us from being clever and creating a new type for handling variable returns:
class VariableReturn(object):
def __getitem__(self, index):
return ...
In Python 3, you can sort of do what you're asking, but the burden is on the caller, not the function being called. The function should always return the same number of results, but we'll trap the remaining results using extended tuple unpacking, as shown in this StackOverflow question.
Using this approach, you can return as many results as you'd like, but you need to always return at least as many as you need in the maximal case. The rest get packed into a trailing tuple.
a,*others = f()
a,b,*others = f()
a,b,c,*others = f()
If you don't mind using Python 3, you can ignore what you don't need, for example:
a, b, c, d, *_ = (x for x in range(100))
Try this:
def f(n):
return (None, ) * n
For example:
a, b, c = f(3)
... That's about as far as you can get, since in Python there's no way to know how many variables are in the left-hand side of an assignment.
Can't be done.
Functions in Python return one value, only. While it may sometimes look like more, it's still just one value: a tuple. Multiple assignment is then a process of tuple unpacking.
Your question then can be restated: can we create an object that acts like a tuple of varying length, depending on how many values need to be unpacked? And that's simply not made available as an option.
Probably the closest I can think of is to use a generator and get the desired number of items with itertools.islice:
a = itertools.count()
x, y, z = itertools.islice(a, 3) # 0, 1, 2
u, v = itertools.islice(a, 2) # 3, 4
But that's pretty far from what was hoped for.
pretty not nice but perhaps this helps you:
def f(x):
for i in x:
globals()[i] = None
f(['a','b','c'])

Is it possible to implement a Python for range loop without an iterator variable?

Is it possible to do following without the i?
for i in range(some_number):
# do something
If you just want to do something N amount of times and don't need the iterator.
Off the top of my head, no.
I think the best you could do is something like this:
def loop(f,n):
for i in xrange(n): f()
loop(lambda: <insert expression here>, 5)
But I think you can just live with the extra i variable.
Here is the option to use the _ variable, which in reality, is just another variable.
for _ in range(n):
do_something()
Note that _ is assigned the last result that returned in an interactive python session:
>>> 1+2
3
>>> _
3
For this reason, I would not use it in this manner. I am unaware of any idiom as mentioned by Ryan. It can mess up your interpreter.
>>> for _ in xrange(10): pass
...
>>> _
9
>>> 1+2
3
>>> _
9
And according to Python grammar, it is an acceptable variable name:
identifier ::= (letter|"_") (letter | digit | "_")*
You may be looking for
for _ in itertools.repeat(None, times): ...
this is THE fastest way to iterate times times in Python.
The general idiom for assigning to a value that isn't used is to name it _.
for _ in range(times):
do_stuff()
What everyone suggesting you to use _ isn't saying is that _ is frequently used as a shortcut to one of the gettext functions, so if you want your software to be available in more than one language then you're best off avoiding using it for other purposes.
import gettext
gettext.bindtextdomain('myapplication', '/path/to/my/language/directory')
gettext.textdomain('myapplication')
_ = gettext.gettext
# ...
print _('This is a translatable string.')
Here's a random idea that utilizes (abuses?) the data model (Py3 link).
class Counter(object):
def __init__(self, val):
self.val = val
def __nonzero__(self):
self.val -= 1
return self.val >= 0
__bool__ = __nonzero__ # Alias to Py3 name to make code work unchanged on Py2 and Py3
x = Counter(5)
while x:
# Do something
pass
I wonder if there is something like this in the standard libraries?
You can use _11 (or any number or another invalid identifier) to prevent name-colision with gettext. Any time you use underscore + invalid identifier you get a dummy name that can be used in for loop.
May be answer would depend on what problem you have with using iterator?
may be use
i = 100
while i:
print i
i-=1
or
def loop(N, doSomething):
if not N:
return
print doSomething(N)
loop(N-1, doSomething)
loop(100, lambda a:a)
but frankly i see no point in using such approaches
Instead of an unneeded counter, now you have an unneeded list.
Best solution is to use a variable that starts with "_", that tells syntax checkers that you are aware you are not using the variable.
x = range(5)
while x:
x.pop()
print "Work!"
I generally agree with solutions given above. Namely with:
Using underscore in for-loop (2 and more lines)
Defining a normal while counter (3 and more lines)
Declaring a custom class with __nonzero__ implementation (many more lines)
If one is to define an object as in #3 I would recommend implementing protocol for with keyword or apply contextlib.
Further I propose yet another solution. It is a 3 liner and is not of supreme elegance, but it uses itertools package and thus might be of an interest.
from itertools import (chain, repeat)
times = chain(repeat(True, 2), repeat(False))
while next(times):
print 'do stuff!'
In these example 2 is the number of times to iterate the loop. chain is wrapping two repeat iterators, the first being limited but the second is infinite. Remember that these are true iterator objects, hence they do not require infinite memory. Obviously this is much slower then solution #1. Unless written as a part of a function it might require a clean up for times variable.
We have had some fun with the following, interesting to share so:
class RepeatFunction:
def __init__(self,n=1): self.n = n
def __call__(self,Func):
for i in xrange(self.n):
Func()
return Func
#----usage
k = 0
#RepeatFunction(7) #decorator for repeating function
def Job():
global k
print k
k += 1
print '---------'
Job()
Results:
0
1
2
3
4
5
6
---------
7
If do_something is a simple function or can be wrapped in one, a simple map() can do_something range(some_number) times:
# Py2 version - map is eager, so it can be used alone
map(do_something, xrange(some_number))
# Py3 version - map is lazy, so it must be consumed to do the work at all;
# wrapping in list() would be equivalent to Py2, but if you don't use the return
# value, it's wastefully creating a temporary, possibly huge, list of junk.
# collections.deque with maxlen 0 can efficiently run a generator to exhaustion without
# storing any of the results; the itertools consume recipe uses it for that purpose.
from collections import deque
deque(map(do_something, range(some_number)), 0)
If you want to pass arguments to do_something, you may also find the itertools repeatfunc recipe reads well:
To pass the same arguments:
from collections import deque
from itertools import repeat, starmap
args = (..., my args here, ...)
# Same as Py3 map above, you must consume starmap (it's a lazy generator, even on Py2)
deque(starmap(do_something, repeat(args, some_number)), 0)
To pass different arguments:
argses = [(1, 2), (3, 4), ...]
deque(starmap(do_something, argses), 0)
We can use the while & yield, we can create our own loop function like this. Here you can refer to the official documentation.
def my_loop(start,n,step = 1):
while start < n:
yield start
start += step
for x in my_loop(0,15):
print(x)
#Return first n items of the iterable as a list
list(itertools.islice(iterable, n))
Taken from http://docs.python.org/2/library/itertools.html
If you really want to avoid putting something with a name (either an iteration variable as in the OP, or unwanted list or unwanted generator returning true the wanted amount of time) you could do it if you really wanted:
for type('', (), {}).x in range(somenumber):
dosomething()
The trick that's used is to create an anonymous class type('', (), {}) which results in a class with empty name, but NB that it is not inserted in the local or global namespace (even if a nonempty name was supplied). Then you use a member of that class as iteration variable which is unreachable since the class it's a member of is unreachable.
What about:
while range(some_number):
#do something

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