Suppose i have below statement :
for i in range(10000):
if i==5:
do_something_for_5()
else:
do_something()
so you can see python need to check 10000 times whether i equals to 5, and 9999 of checking is wasted. my question is, is there any trick that after catching 5 once, python will bypass if-checking and go directly to exec do_something()? somewhat like short-circuit the whole if checking. How to do that?
More..
I don't think it is python problem, you see such checking pattern frequently in many languages.(compilers will optimize it?) The case is just for demo, I just hate to see the computer to check and check and check fruitless and just want to know the trick to avoid this. It likes such scenario: you know there is only one bad guy, and once you catch the bad guy, you withdraw the policemen and security checking to let others go directly, that will let process run faster.
More general code like this:
for member in member_list:
if time_consuming_inspect(member)==special_character:#known there is only one candidate match in advance
do_special_thing(member)
else:
do_common_thing(member)
Do a straightforward thing: break out of the loop after seeing 5, and run another loop to finish the work:
for i in range(10000):
if i==5:
do_something_for_5()
break
else:
do_something()
for i in range(i+1, 10000):
do_something()
One way would be to write something like this instead:
for i in range(4):
do_something()
do_something_for_5()
for i in range(6, 10000):
do_something()
If the special case for 5 need not be executed in order, then this will reduce duplication:
for i in itertools.chain(range(5), range(6, 10000)):
print i
It sounds like you really want something like self-modifying code so that it never does the check again, but I would advise against that. There isn't much impact for an extra check.
Response to comment
The following is not recommended and is overkill for this example, but it does work. It uses a different function after the check for 5 has succeeded. Keep in mind the function that the variable is assigned to must be looked up, so I doubt there will be a speed increase. This probably has very limited use, but nevertheless:
do_something = None
def do_something_with_check(i):
if i != 5:
print 'Doing something with check.'
else:
do_something_for_5()
global so_something
do_something = do_something_without_check
def do_something_without_check(i):
print 'Doing something without check.'
def do_something_for_5():
print 'Doing something for 5.'
do_something = do_something_with_check
for i in range(10):
do_something(i)
prints out:
Doing something with check.
Doing something with check.
Doing something with check.
Doing something with check.
Doing something with check.
Doing something for 5.
Doing something without check.
Doing something without check.
Doing something without check.
Doing something without check.
seenFive = False
for i in range(10000):
if not seenFive and i==5:
do_something_for_5()
seenFive = True
else:
do_something()
You could not iterate over 5, and perform that function separately:
nums = range(10000) # list(range(10000)) on python3
nums.remove(5) # Get rid of 5 from the list.
do_something_for_5()
for i in nums:
do_something()
I'm not sure this will help since the overhead of making the list might be more than checking if i==5 in each iteration.
Related
In C++ we can write an infinite for loop like for(;;). Is here any syntax like this to write an infinite for loop in Python?
Note : I know that if I write for i in range(a_very_big_value) then it may run infinity. I am searching a simple syntax like C++ or any other tricks to write infinite for loop in Python.
Python's for statement is a "for-each" loop (sort of like range-for in C++11 and later), not a C-style "for-computation" loop.
But notice that in C, for (;;) does the same thing as while (1). And Python's while loop is basically the same as C's with a few extra bells and whistles. And, in fact, the idiomatic way to loop forever is:1
while True:
If you really do want to write a for loop that goes forever, you need an iterable of infinite length. You can grab one out of the standard library:2
for _ in itertools.count():
… or write one yourself:
def forever():
while True:
yield None
for _ in forever():
But again, this isn't really that similar to for (;;), because it's a for-each loop.
1. while 1: used to be a common alternative. It's faster in older versions of Python, although not in current ones, and occasionally that mattered.
2. Of course the point of count isn't just going on forever, it's counting up numbers forever. For example, if enumerate didn't exist, you could write it as zip(itertools.count(), it).
Yes, it is possible.
With a while loop:
while True:
...
With a for loop (just for kicks):
from itertools import cycle
for _ in cycle(range(1)):
...
The cycle returns 1 indefinitely.
In either case, it's up to you to implement your loop logic in such a way that you terminate eventually. And lastly, if you want to implement an execute-until-___ loop, you should stick to while True, because that's the idiomatic way of doing it.
I found the answer from here and here
Using itertools.count:
import itertools
for i in itertools.count():
if there_is_a_reason_to_break(i):
break
In Python2 xrange() is limited to sys.maxint, which may be enough for most practical purposes:
import sys
for i in xrange(sys.maxint):
if there_is_a_reason_to_break(i):
break
In Python3, range() can go much higher, though not to infinity:
import sys
for i in range(sys.maxsize**10): # you could go even higher if you really want
if there_is_a_reason_to_break(i):
break
So it's probably best to use count()
It is also possible to achieve this by mutating the list you're iterating on, for example:
l = [1]
for x in l:
l.append(x + 1)
print(x)
Yes, here you are:
for i in __import__("itertools").count():
pass
The infinite iterator part was taken from this answer. If you really think about it though, a while loop looks way better.
while True:
pass
You can use:
while True:
# Do stuff here
for _ in iter(str, "forever"):
... pass
This may help. Because the iter() function creates an iterator that will call str() with no arguments for each call to its next() method[ This returns an empty string ]; if the value returned by str() is equal to the string "forever"(WHICH WILL NEVER HAPPEN AS "" != "forever"), StopIteration will be raised thus breaking the loop, otherwise the loop will continue running and this is the case for our loop.
REF: https://docs.python.org/3/library/functions.html?highlight=iter#iter
I'm pretty new to this whole "programming thing" but at age 34 I thought that I'd like to learn the basics.
I unfortunately don't know any python programmers. I'm learning programming due to personal interest (and more and more for the fun of it) but my "social habitat" is not "where the programmers roam" ;) .
I'm almost finished with Zed Shaws "Learn Python the Hard Way" and for the first time I can't figure out a solution to a problem. The last two days I didn't even stumble upon useful hints where to look when I repeatedly rephrased (and searched for) my question.
So stackoverflow seems to be the right place.
Btw.: I lack also the correct vocabular quite often so please don't hesitate to correct me :) . This may be one reason why I can't find an answer.
I use Python 2.7 and nosetests.
How far I solved the problem (I think) in the steps I solved it:
Function 1:
def inp_1():
s = raw_input(">>> ")
return s
All tests import the following to be able to do the things below:
from nose.tools import *
import sys
from StringIO import StringIO
from mock import *
import __builtin__
# and of course the module with the functions
Here is the test for inp_1:
import __builtin__
from mock import *
def test_inp_1():
__builtin__.raw_input = Mock(return_value="foo")
assert_equal(inp_1(), 'foo')
This function/test is ok.
Quite similar is the following function 2:
def inp_2():
s = raw_input(">>> ")
if s == '1':
return s
else:
print "wrong"
Test:
def test_inp_2():
__builtin__.raw_input = Mock(return_value="1")
assert_equal(inp_1(), '1')
__builtin__.raw_input = Mock(return_value="foo")
out = StringIO()
sys.stdout = out
inp_1()
output = out.getvalue().strip()
assert_equal(output, 'wrong')
This function/test is also ok.
Please don't assume that I really know what is happening "behind the scenes" when I use all the stuff above. I have some layman-explanations how this is all functioning and why I get the results I want but I also have the feeling that these explanations may not be entirely true. It wouldn't be the first time that how I think sth. works turns out to be different after I've learned more. Especially everything with "__" confuses me and I'm scared to use it since I don't really understand what's going on. Anyway, now I "just" want to add a while-loop to ask for input until it is correct:
def inp_3():
while True:
s = raw_input(">>> ")
if s == '1':
return s
else:
print "wrong"
The test for inp_3 I thought would be the same as for inp_2 . At least I am not getting error messages. But the output is the following:
$ nosetests
......
# <- Here I press ENTER to provoke a reaction
# Nothing is happening though.
^C # <- Keyboard interrupt (is this the correct word for it?)
----------------------------------------------------------------------
Ran 7 tests in 5.464s
OK
$
The other 7 tests are sth. else (and ok).
The test for inp_3 would be test nr. 8.
The time is just the times passed until I press CTRL-C.
I don't understand why I don't get error- or "test failed"-meassages but just an "ok".
So beside the fact that you may be able to point out bad syntax and other things that can be improved (I really would appreciate it, if you would do this), my question is:
How can I test and abort while-loops with nosetest?
So, the problem here is when you call inp_3 in test for second time, while mocking raw_input with Mock(return_value="foo"). Your inp_3 function runs infinite loop (while True) , and you're not interrupting it in any way except for if s == '1' condition. So with Mock(return_value="foo") that condition is never satisfied, and you loop keeps running until you interrupt it with outer means (Ctrl + C in your example). If it's intentional behavior, then How to limit execution time of a function call in Python will help you to limit execution time of inp_3 in test. However, in cases of input like in your example, developers often implement a limit to how many input attempts user have. You can do it with using variable to count attempts and when it reaches max, loop should be stopped.
def inp_3():
max_attempts = 5
attempts = 0
while True:
s = raw_input(">>> ")
attempts += 1 # this is equal to "attempts = attempts + 1"
if s == '1':
return s
else:
print "wrong"
if attempts == max_attempts:
print "Max attempts used, stopping."
break # this is used to stop loop execution
# and go to next instruction after loop block
print "Stopped."
Also, to learn python I can recommend book "Learning Python" by Mark Lutz. It greatly explains basics of python.
UPDATE:
I couldn't find a way to mock python's True (or a builtin.True) (and yea, that sounds a bit crazy), looks like python didn't (and won't) allow me to do this. However, to achieve exactly what you desire, to run infinite loop once, you can use a little hack.
Define a function to return True
def true_func():
return True
, use it in while loop
while true_func():
and then mock it in test with such logic:
def true_once():
yield True
yield False
class MockTrueFunc(object):
def __init__(self):
self.gen = true_once()
def __call__(self):
return self.gen.next()
Then in test:
true_func = MockTrueFunc()
With this your loop will run only once. However, this construction uses a few advanced python tricks, like generators, "__" methods etc. So use it carefully.
But anyway, generally infinite loops considered to be bad design solutions. Better to not getting used to it :).
It's always important to remind me that infinite loops are bad. So thank you for that and even more so for the short example how to make it better. I will do that whenever possible.
However, in the actual program the infinite loop is how I'd like to do it this time. The code here is just the simplified problem.
I very much appreciate your idea with the modified "true function". I never would have thought about that and thus I learned a new "method" how tackle programming problems :) .
It is still not the way I would like to do it this time, but this was the so important clue I needed to solve my problem with existing methods. I never would have thought about returning a different value the 2nd time I call the same method. It's so simple and brilliant it's astonishing me :).
The mock-module has some features that allows a different value to be returned each time the mocked method is called - side effect .
side_effect can also be set to […] an iterable.
[when] your mock is going to be
called several times, and you want each call to return a different
value. When you set side_effect to an iterable every call to the mock
returns the next value from the iterable:
The while-loop HAS an "exit" (is this the correct term for it?). It just needs the '1' as input. I will use this to exit the loop.
def test_inp_3():
# Test if input is correct
__builtin__.raw_input = Mock(return_value="1")
assert_equal(inp_1(), '1')
# Test if output is correct if input is correct two times.
# The third time the input is corrct to exit the loop.
__builtin__.raw_input = Mock(side_effect=['foo', 'bar', '1'])
out = StringIO()
sys.stdout = out
inp_3()
output = out.getvalue().strip()
# Make sure to compare as many times as the loop
# is "used".
assert_equal(output, 'wrong\nwrong')
Now the test runs and returns "ok" or an error e.g. if the first input already exits the loop.
Thank you very much again for the help. That made my day :)
In C there's a clever trick that lets you avoid pyramid-style code by turning:
if (check1())
if (check2())
if (check3())
do_something();
into:
do {
if (!check1())
break;
if (!check2())
break;
if (!check3())
break;
do_something();
} while (0);
What's the cleanest way for me to do this in Python, which doesn't have a do-while construct?
Note: I'm not necessarily asking for a way to implement a do-while loop in Python, but a technique to avoid the aforementioned pyramid-style code.
Update: It seems there's some confusion. The only reason I'm using a loop is to be able to break out at any point in the body, which is only supposed to be executed once.
Essentially what I'm doing in Python is this:
while True:
if not check1():
break
if not check2():
break
if not check3():
break
do_domething()
break
I'm just wondering if there's a cleaner way.
The Pythonic way of writing this would be
if check1() and check2() and check3():
do_something()
In Python we emphasize clarity and simplicity of the code, not using clever programming tricks.
[Edit] If you need to "create a variable and use it in the first check", then you would use the pyramid-style:
if check1():
#variables and stuff here
if check2():
#variables and stuff here
if check3():
doSomething()
Or, as #Blender suggests, refactor it into a separate method. These are all much simpler and clearer ways of communicating your intent than using a loop that's not intended to loop.
Invert your conditions and break out early. If you structure your code well, you won't have to worry about if staircases in the first place:
def do_bigger_something():
if not check1():
return
if not check2():
return
if not check3():
return
do_something()
There's a good chance that if one portion of your code does a lot of these checks, it should be turned into a function anyways.
if (check1() and check2() and check3()):
do_something()
if check1() and check2() and check3():
do_something()
I'd say if the checks are not as trivial as this (which can be done with a simple and), refactor your code and break it out into a function instead of mis-using a loop for things it's not meant to do;
def doSomethingIfConditions():
if not check1():
return
if not check2():
return
if not check3():
return
doSomething()
...your code...
doSomethingOnConditions()
...your code...
Solution #1 (straightforward):
while True:
if not check1():
break
if not check2():
break
if not check3():
break
do_something()
break
Solution #2 (more pythonic):
for check in check1, check2, check3:
if not check():
break
else:
# the else part is only executed
# if we didn't break out the loop
do_something()
Solution #3 (even more pythonic):
if all(c() for c in check1,check2, check3):
# all(seq) will stop at the first false result
do_something()
I do not see the need for a loop... You break out of it at the end anyways.
if all((check1(), check2(), check3())):
print "Do something"
Or just go with the block-style if it's needed.
In C, the use of the do ... while(0) construct that you have shown is usually used when the C programmer wants something that behaves like a goto, but using an actual goto is out of the question (for various reasons). So, the break out of the do ... while(0) is really a kind of hack. Using the same idiom in Python would be perpetuating that hack.
In C, I would generally avoid using this particular use of do ... while(0), and instead opt for a checking function. In Python, this would be:
def do_checks():
if not check1():
return False
if not check2():
return False
if not check3():
return False
return True
if do_checks():
do_something()
Probably the most direct translation of C's do ... while(0) construct would be a loop with a single iteration. Don't do this.
for x in range(1):
if not check1():
break
if not check2():
break
if not check3():
break
do_something()
I find myself using this code pattern quite a bit, and every time I do I think there might be a better, clearer way of expressing myself:
do_something = True
# Check a lot of stuff / loops
for thing in things:
....
if (thing == 'something'):
do_something = False
break
if (do_something):
# Do something
So essentially, "plan on doing something but if this particular condition is found anytime, anywhere, don't do it"
Maybe this code is perfectly fine, but I wanted to see if anyone had a better suggestion.
Thanks for any input
Python for loops can have an else block, which is executed if those loop is not broken out of:
for thing in things:
...
if (thing == 'something'):
break
else:
... # Do something
This code will work in the same way as yours, but doesn't need a flag. I think this fits your criteria for something a bit more elegant.
Is while True an accepted method for looping over a block of code until an accepted case is reached as below? Is there a more elegant way to do this?
while True:
value = input()
if value == condition:
break
else:
pass
# Continue code here.
Thank you for any input.
That's the way to do this in Python. You don't need the else: pass bit though.
Note, that in python 2.x you're likely to want raw_input rather than input.
If it's deterministic, then yes. If it is not deterministic (thus meaning you could be stuck in a loop forever at some statistical likelihood) then no.
If you wanted to make it a little more clean and easier to debug as the code grows larger, use a boolean or integer to indicate the status of your loop condition.