Let us assume the following lists:
totest=[2,4,5,3,6]
l1=[6,8,7,9,4]
l2=[3,12,21,30]
l3=[2,5]
And the following function:
def evalitem(x):
...detail....
I have to execute the function against the intersection of totest against all the other lists in a sequence unless there is an exception.
There is always the following option:
test1=set(totest)&set(l1)
try:
for i in test1:
evalitem(i)
except:
return
test2=.....
But there should be a faster pythonic functional way to achieve this,with much better performance.
Do note that we go to evaluate test2 only if test1 does not raise an exception.
totest = set(totest)
for lst in l1, l2, l3:
for item in totest.intersection(lst):
evalitem(item)
If you don't know how to handle an exception (except: return doesn't count), there is no need to use try...except at all. Handle it in the code that calls the function in question.
Related
I have a function I'm using to test in an if/then.
The issue is that I'm executing the function BOTH in the if conditional, and then again after the if statement because the function returns two items.
This just seems wasteful and I'm trying to think of ways to improve this. Here's a really basic version of what I'm trying to avoid: "True" is returned to allow the condition to pass, but then then "coolstuff()" is executed again to get more information from the function.
"coolstuff()" could possibly return false, so I can't use the returned string "stuff" as the test.
def coolstuff():
return True, "stuff"
if coolstuff()[0]:
coolthing = coolstuff()[1]
print coolthing
There's gotta be a better way to do this, no? My brain is melting a little as I try to hash it out.
I basically want to do something like this (invalid) syntax:
def coolstuff():
return True, "stuff"
if a, b == coolstuff() and a:
print b
Just collect both results into variables
a, b = fn()
if a:
# work with b
def coolstuff():
if valid:
return "stuff"
return None
data = coolstuff()
if data:
print(data)
Call the function and capture the entire returned value:
x = coolstuff()
Now you have access to both parts of the returned value, in x[0] and x[1].
Store it:
state, coolvar = coolstuff()
if state:
do_whatever(coolvar)
If in newer Python, you could use the dreaded walrus (but I prefer ti7's approach of just assigning in a separate line):
if (x := coolstuff())[0]:
print(x[1])
I have a function that calls subprocess.check_call() twice. I want to test all their possible outputs. I want to be able to set the first check_call() to return 1 and the second to return 0 and to do so for all possible combinations. The below is what I have so far. I am not sure how to adjust the expected return value
#patch('subprocess.check_call')
def test_hdfs_dir_func(mock_check_call):
for p, d in list(itertools.product([1, 0], repeat=2)):
if p or d:
You can assign the side_effect of your mock to an iterable and that will return the next value in the iterable each time it's called. In this case, you could do something like this:
import copy
import itertools
import subprocess
from unittest.mock import patch
#patch('subprocess.check_call')
def test_hdfs_dir_func(mock_check_call):
return_values = itertools.product([0, 1], repeat=2)
# Flatten the list; only one return value per call
mock_check_call.side_effect = itertools.chain.from_iterable(copy.copy(return_values))
for p, d in return_values:
assert p == subprocess.check_call()
assert d == subprocess.check_call()
Note a few things:
I don't have your original functions so I put my own calls to check_call in the loop.
I'm using copy on the original itertools.product return value because if I don't, it uses the original iterator. This exhausts that original iterator when what we want is 2 separate lists: one for the mock's side_effect and one for you to loop through in your test.
You can do other neat stuff with side_effect, not just raise. As shown above, you can change the return value for multiple calls: https://docs.python.org/3/library/unittest.mock-examples.html#side-effect-functions-and-iterables
Not only that, but you can see from the link above that you can also give it a function pointer. That allows you to do even more complex logic when keeping track of multiple mock calls.
I've been working on a "learning project" which involves several short single-parameter functions, where the parameter might be either a numeric type or a list of numerics. E.g.,
def magnitude_of(v):
try:
return math.sqrt(sum([vi**2 for vi in v]))
except:
return abs(v)
This of course is necessary because if I did this:
def magnitude_of(v):
return math.sqrt(sum([vi**2 for vi in list(v)]))
...the code would fail because list() only accepts an iterable as an argument.
My question is: has there ever been consideration given at PSW to letting list() work with any argument? If so, what prevented the change from being implemented?
I would just create my own list function and use it for this particular purpose.
Ex:
def mlist(v):
try:
return list(v)
except(TypeError):
return [v]
Now you use mlist instead of list
l1 = mlist(1)
l2 = mlist([1])
Both will give [1] as the result
I cannot comment on whether this has come up at PSW, but I generally prefer using a ternary here instead of try... catch
e.g.
def magnitude_of(v):
return math.sqrt(sum([vi*vi for vi in (v if isinstance(v,list) else [v])]))
Granted, as others have mentioned it would probably be best if the function simply requires a list to be passed
This must be simple, but as an only occasional python user, fighting some syntax.
This works:
def perms (xs):
for x in itertools.permutations(xs): yield list(x)
But this won't parse:
def perms (xs): for x in itertools.permutations(xs): yield list(x)
Is there some restriction on the one-line function syntax?
The body definition (for...) can be either two or one line by itself, and the def: can be one or two lines with a simple body, but combining the two fails.
Is there a syntax rule that excludes this?
If you must have one line just make it a lambda:
perms = lambda xs: (list(x) for x in itertools.permutations(xs))
Quite often, when you have a short for loop for generating data you can replace it with either list comprehension or a generator expression for approximately the same legibility in slightly less space.
Yes, there are restrictions. No, you can't do that. Simply put, you can skip one line feed but not two.
See here.
The reason for this is that it would allow you to do
if test1: if test2: print x
else:
print y
Which is ambiguous.
In your case, I am not sure. But with some functions you can achive this by using semicolons.
>>> def hey(ho): print(ho); print(ho*2); return ho*3
...
>>> hey('you ')
you
you you
'you you you '
def perms (xs):
for x in itertools.permutations(xs): yield list(x)
You can use exec() to help this problem
exec('def perms (xs):\n for x in itertools.permutations(xs):\n yield list(x)\n')
beware to insert indented spacing or chr(9) after \n
Example for if Python in one line
for i in range(10):
if (i==1):
print(i)
exec('for i in range(10)\n if (i==1):\n print(i)\n')
This is My project on GitHub to use exec to run Python program in interactive console mode
*note multiple line exec run only when end with '\n'
I have a Python function called plot_pdf(f) that might throw an error. I use a list comprehension to iterate over a list of files on this function:
[plot_pdf(f) for f in file_list]
I want to use try-except block to skip any possible errors during the iteration loop and continue with the next file. So is the following code correct way to do the exception handling in Python list comprehension?
try:
[plot_pdf(f) for f in file_list] # using list comprehensions
except:
print ("Exception: ", sys.exc_info()[0])
continue
Will the above code terminate the current iteration and go to the next iteration? If I can't use list comprehension to catch errors during iteration, then I have to use the normal for loop:
for f in file_list:
try:
plot_pdf(f)
except:
print("Exception: ", sys.exc_info()[0])
continue
I want to know if I can use try-except to do exception handling in list comprehension.
try:
[plot_pdf(f) for f in file_list] # using list comprehensions
except:
print ("Exception: ", sys.exc_info()[0])
continue
If plot_pdf(f) throws an error during execution of comprehension, then, it is caught in the except clause, other items in comprehension won't be evaluated.
It is not possible to handle exceptions in a list comprehension, for a list comprehension is an expression containing other expression, nothing more (i.e. no statements, and only statements can catch/ignore/handle exceptions).
Function calls are expression, and the function bodies can include all
the statements you want, so delegating the evaluation of the
exception-prone sub-expression to a function, as you've noticed, is
one feasible workaround (others, when feasible, are checks on values
that might provoke exceptions, as also suggested in other answers).
More here.
You're stuck with your for loop unless you handle the error inside plot_pdf or a wrapper.
def catch_plot_pdf(f):
try:
return plot_pdf(f)
except:
print("Exception: ", sys.exc_info()[0])
[catch_plot_pdf(f) for f in file_list]
You could create a catch object
def catch(error, default, function, *args, **kwargs):
try: return function(*args, **kwargs)
except error: return default
Then you can do
# using None as default value
result (catch(Exception, None, plot_pdf, f) for f in file_list)
And then you can do what you want with the result:
result = list(result) # turn it into a list
# or
result = [n for n in result if n is not None] # filter out the Nones
Unfortunately this will not be even remotely C speed, see my question here