Python: do r = random_stuff() while not meets_condition(r) - python

I often have to randomly generate stuff with certain constraints. In many cases, it's quicker to ignore the constraints in generation, check if they are met afterwards and redo the process otherwise. Lacking a do keyword, I usually write
r = random_stuff()
while not meets_condition(r):
r = random_stuff()
That's a bit ugly, as I have the same line of code twice. What I'd really like to have is a construct like
r = random_stuff() until meets_condition(r)
similar to the ternary operator introduced in 2.5:
a = b if condition else c
Just that here condition is evaluated before the left-hand side of the statement is executed. Does anybody have a suggestion for a design pattern (should work in Python 2.7) that remedies the while-constructs intrinsic unpythonic ugliness?

while True:
r = random_stuff()
if meets_condition(r):
break
or
condition = True
while condition:
r = random_stuff()
condition = not meets_condition(r)

Your idea is not bad - but not with the new keyword until, but rather like
a = (<expression> while <condition>)
extending the idea of generator expressions.
As they don't exist, it won't help you.
But what you can use, is the iter function with the sentinel.
dummy_sentinel = object()
for r in iter(random_stuff, dummy_sentinel):
if meets_condition(r): break
If you can be sure about your random_stuff() returning only a certain kind of values, such as numbers, strings, etc., you can take some other value as sentinel. Especially, when None never can occur, take this, in order to have a never-ending generator.
for r in iter(random_stuff, None):
if meets_condition(r): break
Then random_stuff() gets called until it meets the condition.
Even better might be
r = next(r for r in iter(random_stuff, None) if meets_condition(r))
which gives you the first matching one.

Maybe syntactic sugar is what the Dr. ordered? You could do something like this.
I was too lazy to handle kw args in find_condition. You get what you pay for :D.
def find_condition(cond_mk, cond_ck, *args):
"""
.. function:: find_condition(cond_mk, cond_ck) -> cond
Create conditions by calling cond_mk until one is found that passes
the condition check, cond_ck. Once cond_ck returns True, iteration
over cond_mk stops and the last value processed is returned.
** WARNING **
This function could loop infinitely.
``cond_mk`` - callable that creates a condition. It's return value is
passed to cond_ck for verification.
``cond_ck`` - callable that checks the return value of cond_mk.
``args`` - any arguments to pass to cond_mk should be supplied here.
"""
v = cond_mk(*args)
while not cond_ck(v):
v = cond_mk(*args)
return v
# Test it out..
import random
random.seed()
print find_condition(random.randint, lambda x: x > 95, 1, 100)

while not meets_condition(random_stuff()): pass
If you actually need the random_stuff() then it can be stored elsewhere as a side effect (e.g. make random_stuff the __call__ method of a class).

Okay, inspired by #jaime I wrote the following decorator:
def retry(condition):
def deco_retry(f):
def f_retry(*args, **kwargs):
success = False
while not success:
result = f(*args, **kwargs)
success = condition(result)
return result
return f_retry
return deco_retry
Now, the following works:
def condition(calue):
return value < .5
#retry(condition)
def random_stuff():
return random.random()
print random_stuff()
Also, inline:
#retry(lambda x: x < .5)
def random_stuff():
return random.random()
print random_stuff()
However, the retry is now bound to the random_stuff() method, which can now only be used with the condition with which it was decorated. Also, it doesn't work for instance methods (as in #retry(self.condition)). Any ideas to circumvent that?

Related

Python: using a function that returns two items in an If statement, without executing twice

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])

How to fix inconsistent return statement in python?

I am new to python and i have this project I am working on a small project with two functions where the first returns the index of the first time a difference is spotted in a string. The next function does that but in a list of strings. Now, due to my being an amateur, i have used an excessive amount of if and else statements which resulted in too many return statements especially in the second function, and i get the error [R1710: inconsistent-return-statements]. How do i fix it and can anybody give me clear examples to better pieces of code? Sorry for the question being so long.
IDENTICAL = -1
def singleline_diff(line1, line2):
"""
Inputs:
line1 - first single line string
line2 - second single line string
Output:
Returns the index where the first difference between
line1 and line2 occurs.
Returns IDENTICAL if the two lines are the same.
"""
len1 = len(line1)
len2 = len(line2)
minimum_length = min(len1, len2)
if len1 != len2:
if minimum_length == 0:
return 0
for idx in range(minimum_length):
if line1[idx] == line2[idx]:
pass
else:
return idx
return idx + 1
for idx in range(len1):
if line1[idx] == line2[idx]:
pass
else:
return idx
return IDENTICAL
def multiline_diff(lines1, lines2):
"""
Inputs:
lines1 - list of single line strings
lines2 - list of single line strings
Output:
Returns a tuple containing the line number (starting from 0) and
the index in that line where the first difference between lines1
and lines2 occurs.
Returns (IDENTICAL, IDENTICAL) if the two lists are the same.
"""
line_no = singleline_diff(lines1, lines2)
len_lines1, len_lines2 = len(lines1), len(lines2)
if len_lines1 == len_lines2:
if (len_lines1 or len_lines2) == 0:
if len_lines1 == len_lines2:
return (IDENTICAL, IDENTICAL)
else:
idx = singleline_diff(lines1[line_no], lines2[line_no])
return (line_no, idx)
else:
idx = singleline_diff(lines1[line_no], lines2[line_no])
if line_no == IDENTICAL:
return (IDENTICAL, IDENTICAL)
elif line_no != IDENTICAL:
return (line_no, idx)
else:
return (line_no, 0)
Where was a semantic mistake in OP's code is in Abhishek Arya's answer
TL;DR - early return:
def your_function():
if not should_do():
return # NO RETURN VALUE!
# rest of the function
...yes, this will no longer emit the inconsistent-return-statements ;)
This Q/A pops also when you search for inconsistent-return-statements, I want to give a brief "common problems" guide for those.
Case A: return value is irrelevant, you just want to exit function early
There are cases, where there are functions (or "procedures" if you want to get technical about it) that just do something, but are not expected to have any return values AT ALL,
at the same time, there may be e.g. some sort of check at the start of the function whether this function run even makes sense, what may first come to your mind, is wrapping the whole function code in an if statement:
def your_function(article):
if display_content():
content = get_content(article)
# do some extensive logic to generate final content
# ...
print(content)
...this is oversimplified, but let's hope you can imagine how such coding can pretty quickly fall into a "spaghetti code" if there are more checks and more code in general + it also steals that one "tab" of a space that you so desperately need to fit into your project's max line length.
Luckily, same as in many other programming languages, there IS a way of an early ending of a function by returning at ANY place within the function run, meaning in any "Control Flow" - including if/elif/else, for/while loops, ...
Now you'd probably jump quick to just return None, False, etc. although it would work, you'd still get the pylint inconsistent-return-statements warning - to understand why let's see the warning's message:
Either all return statements in a function should return an
expression, or none of them should. pylint(inconsistent-return-statements)
From pylint's point of view, if you put anything after the return it will be considered as an expression. So what to do? Actually, in Python, you CAN return "nothing" (again this is not unique to Python)
def your_function(article):
if not display_content():
return
content = get_content(article)
# do some extensive logic to generate final content
# ...
print(content)
Although in Python returning "nothing" should be (and technically, to my knowledge, it is) an equivalent of return None, by physically writing "None" you are expressing the intention no matter the implicity of it.
Don't confuse this though with pylint(assignment-from-none) (Assigning result of a function call, where the function returns None) - where both "return" AND "return None" are considered as returning None!
Case B: Your function has a case when it doesn't return
Quite common mistake especially in a larger code is to create a code part which results in simply not returning anything. This is not exactly OP's case, since they used just a negation of the same condition, but pylint doesn't know that, so here's its thought process:
if SOME_CONDITION: # ok, here's just another condition
return someReturnExpression # and ok, it returns SOMETHING, let's note that
elif OPPOSITE_OF_SOME_CONDITION: # ok, here's just another condition
return someReturnExpression # and ok, it returns SOMETHING, let's note that
# WAIT ! What?! THERE WAS NO "else:"! Hmmm...
# ...what happens if both conditions fail? NOTHING WOULD BE RETURNED!
# We need to make a warning about that!
# (fact that sometimes they return SOMETHING and sometimes NOTHING)
So this inconsistent-return-statements could be resolved with
if SOME_CONDITION: # ok, here's some condition
return someReturnExpression # and ok, it returns SOMETHING, let's note that
else: # ok, here's else
return someReturnExpression # and ok, it returns SOMETHING, let's note that
# Ok, so if returns SOMETHING, else returns SOMETHING,
# so SOMETHING is returned every time! that's good!
...this in itself works, but it will generate yet another pylint issue
Unnecessary "else" after "return" pylint(no-else-return)
See python actually encourages early returns since it often leads to a cleaner code.
return during function run ENDS(/exits) the function and pylint sees that - it sees that if the condition was true, the function code would simply end there - so what it, Abhishek Arya, me and many others suggest is simply continuing with the code after the if part:
if SOME_CONDITION:
return someReturnExpression
# ... some more code ...
# ... some more code ...
return someReturnExpression
Case C: Combination
Simply don't combine "just" return with return SOMETHING,
if you really need to return None, simply explicitly return None in that case
def get_article(id):
article = find_article(id)
if article.id == 0:
return None
return article
This is just an example, this is not how you'd really check for some articles ;)
Look at the code here:
if len_lines1 == len_lines2:
return (IDENTICAL, IDENTICAL)
else:
idx = singleline_diff(lines1[line_no], lines2[line_no])
return (line_no, idx)
You could have written the above thing like:
if len_lines1 == len_lines2:
return (IDENTICAL, IDENTICAL)
idx = singleline_diff(lines1[line_no], lines2[line_no])
return (line_no, idx)
You just don't need an else block to return this expression as this part of code will automatically be called if the control doesn't go into if block. Hope it helps.

Pythonic way to Call a function with set of arguments until it return any thing but None

I know to use for loop and call my function till I get not None as return value, But I am looking for some python built in which can help here.
e.g. - iter(myfunc(), None) It will call myfunc() until it return None
I am looking to code exactly opposite to this e.g. - iter(myfunc(), not None), Call myfunc() until it returns any thing but None
Thanks in advance..
With just three lines:
x = None
while x is None:
x = f()
Do not look for a builtin for everything. In my opinion even the usual two-argument form of iter is not worth using because it's not a well known feature, and that makes it harder for most people to read. Just keep it simple and straightforward. An extra line or two will not hurt.
while True:
x = myfunc()
if x is not None:
break
There is no ready builtin, but it is easy enough to build a generator function:
def iter_while_none(f):
while True:
value = f()
if value is not None:
return
yield value
although the value yielded is not that interesting; it is, after all, None each time.
This answer is a bit of an exercise in the power of Python. I just get frustrated that iters 2-arity form doesn't take a function for its second parameter.
But it does, if you're crazy enough. See, you can redefine equality on an object, like so:
class Something:
def __eq__(self, other):
self.lastother = other
return other is not None
sentinel = Something()
myiter = iter(myfunc, sentinel)
for nope in myiter:
pass
match = sentinel.lastother
There. Enjoy. Python's pretty amazing that you can subvert the definition of equality this way. Have fun storming the castle!

Is there a way to check if function is recursive in python?

I want to write a testing function for an exercise, to make sure a function is implemented correctly.
So I got to wonder, is there a way, given a function "foo", to check if it is implemented recursively?
If it encapsulates a recursive function and uses it it also counts. For example:
def foo(n):
def inner(n):
#more code
inner(n-1)
return inner(n)
This should also be considered recursive.
Note that I want to use an external test function to perform this check. Without altering the original code of the function.
Solution:
from bdb import Bdb
import sys
class RecursionDetected(Exception):
pass
class RecursionDetector(Bdb):
def do_clear(self, arg):
pass
def __init__(self, *args):
Bdb.__init__(self, *args)
self.stack = set()
def user_call(self, frame, argument_list):
code = frame.f_code
if code in self.stack:
raise RecursionDetected
self.stack.add(code)
def user_return(self, frame, return_value):
self.stack.remove(frame.f_code)
def test_recursion(func):
detector = RecursionDetector()
detector.set_trace()
try:
func()
except RecursionDetected:
return True
else:
return False
finally:
sys.settrace(None)
Example usage/tests:
def factorial_recursive(x):
def inner(n):
if n == 0:
return 1
return n * factorial_recursive(n - 1)
return inner(x)
def factorial_iterative(n):
product = 1
for i in xrange(1, n+1):
product *= i
return product
assert test_recursion(lambda: factorial_recursive(5))
assert not test_recursion(lambda: factorial_iterative(5))
assert not test_recursion(lambda: map(factorial_iterative, range(5)))
assert factorial_iterative(5) == factorial_recursive(5) == 120
Essentially test_recursion takes a callable with no arguments, calls it, and returns True if at any point during the execution of that callable the same code appeared twice in the stack, False otherwise. I think it's possible that it'll turn out this isn't exactly what OP wants. It could be modified easily to test if, say, the same code appears in the stack 10 times at a particular moment.
from inspect import stack
already_called_recursively = False
def test():
global already_called_recursively
function_name = stack()[1].function
if not already_called_recursively:
already_called_recursively = True
print(test()) # One recursive call, leads to Recursion Detected!
if function_name == test.__name__:
return "Recursion detected!"
else:
return "Called from {}".format(function_name)
print(test()) # Not Recursion, "father" name: "<module>"
def xyz():
print(test()) # Not Recursion, "father" name: "xyz"
xyz()
The output is
Recursion detected!
Called from <module>
Called from xyz
I use the global variable already_called_recursively to make sure I only call it once, and as you can see, at the recursion it says "Recursion Detected", since the "father" name is the same as the current function, which means I called it from the same function aka recursion.
The other prints are the module-level call, and the call inside xyz.
Hope it helps :D
I have not yet verified for myself if Alex's answer works (though I assume it does, and far better than what I'm about to propose), but if you want something a little simpler (and smaller) than that, you can simply use sys.getrecursionlimit() to error it out manually, then check for that within a function. For example, this is what I wrote for a recursion verification of my own:
import sys
def is_recursive(function, *args):
try:
# Calls the function with arguments
function(sys.getrecursionlimit()+1, *args)
# Catches RecursionError instances (means function is recursive)
except RecursionError:
return True
# Catches everything else (may not mean function isn't recursive,
# but it means we probably have a bug somewhere else in the code)
except:
return False
# Return False if it didn't error out (means function isn't recursive)
return False
While it may be less elegant (and more faulty in some instances), this is far smaller than Alex's code and works reasonably well for most instances. The main drawback here is that with this approach, you're making your computer process through every recursion the function goes through until reaching the recursion limit. I suggest temporarily changing the recursion limit with sys.setrecursionlimit() while using this code to minimize the time taken to process through the recursions, like so:
sys.setrecursionlimit(10)
if is_recursive(my_func, ...):
# do stuff
else:
# do other stuff
sys.setrecursionlimit(1000) # 1000 is the default recursion limit

Pythonic way to efficiently handle variable number of return args

So I have a function that can either work quietly or verbosely. In quiet mode it produces an output. In verbose mode it also saves intermediate calculations to a list, though doing so takes extra computation in itself.
Before you ask, yes, this is an identified bottleneck for optimization, and the verbose output is rarely needed so that's fine.
So the question is, what's the most pythonic way to efficiently handle a function which may or may not return a second value? I suspect a pythonic way would be named tuples or dictionary output, e.g.
def f(x,verbose=False):
result = 0
verbosity = []
for _ in x:
foo = # something quick to calculate
result += foo
if verbose:
verbosity += # something slow to calculate based on foo
return {"result":result, "verbosity":verbosity}
But that requires constructing a dict when it's not needed.
Some alternatives are:
# "verbose" changes syntax of return value, yuck!
return result if verbose else (result,verbosity)
or using a mutable argument
def f(x,verbosity=None):
if verbosity:
assert verbosity==[[]]
result = 0
for _ in x:
foo = # something quick to calculate
result += foo
if verbosity:
# hard coded value, yuck
verbosity[0] += # something slow to calculate based on foo
return result
# for verbose results call as
verbosity = [[]]
f(x,verbosity)
Any better ideas?
Don't return verbosity. Make it an optional function argument, passed in by the caller, mutated in the function if not empty.
The non-pythonic part of some answers is the need to test the structure of the return value. Passing mutable arguments for optional processing avoids this ugliness.
I like the first option, but instead of passing a verbose parameter in the function call, return a tuple of a quick result and a lazily-evaluated function:
import time
def getResult(x):
quickResult = x * 2
def verboseResult():
time.sleep(5)
return quickResult * 2
return (quickResult, verboseResult)
# Returns immediately
(quickResult, verboseResult) = getResult(2)
print(quickResult) # Prints immediately
print(verboseResult()) # Prints after running the long-running function

Categories