I'm debugging some code in PyCharm by stepping through line-by-line. The code involves a long for-loop, but for debugging purposes, I don't need to iterate through the whole thing. Instead, I'd like to break out after a few iterations. I'm trying to figure out how to do so without modifying my code to have special debugging instructions.
Example for loop
indices = range(10000, 0, -1)
for i, val in enumerate(indices):
print(val) # I can tell that it's working after a few iterations
The first thing I tried was typing break in the debugging console when paused at the print(val) line. This resulted in a syntax error
SyntaxError: 'break' outside loop
I also thought about using the debugging console line to modify the variable that I am enumerating over. For example, entering
indices = []
This has no effect on the iterator. Apparently, the iterator has an independent copy of the variable.
In another language, Java for example, I would take advantage of the termination condition, but python loops don't have a termination condition. I could rewrite my for-loop as a while-loop so that it would have an explicit termination condition, but that would obfuscate the code.
The other option would be to add special debugging instructions. For example,
mode = 'debug'
indices = range(10000, 0, -1)
for i, val in enumerate(indices):
print(val) # I can tell that it's working after a few iterations
if mode == 'debug' and i % 10:
break
I dislike doing this because inevitably, one of these special instructions gets left in after debugging is finished and mucks everything up.
Do I have any other options to break out of the loop from the debug console or without modifying the code?
I dislike doing this because inevitably, one of these special instructions gets left in after debugging is finished and mucks everything up.
Python for loops just aren't designed to be changed during execution, besides hard coding break, return or throwing StopIteration. (You are debugging, so either change the range in the loops expression list, or let it run through). The reason being the advantages of straightforward simplicity outweigh exposing the for loop counter - see PEP 212.
Related
I have a breakpoint in my Python debugger. I am using PyCharm. I want to iterate lets say 100 times to reach the point where I want to debug.
Now I can press 100 x times Resume Program, but is there a way to just execute a command to run n times over the breakpoint.
You can use a function in a conditional breakpoint to count iterations, take for example:
The conditional breakpoint can call a function which in addition to returning a boolean, counts the number of loop iterations.
def your_counter(stop):
global count
count = count + 1
if stop == count:
# count = 0 for periodic break
return True
else:
return False
The solution shown is for cases when a one-liner condition might not be practical, and/or when a loop counter needs to be implemented externally. Since the breakpoint condition is programmatic you can implement it to break periodically, or on any series/frequency criteria you want to apply.
The custom condition would break at the exact iteration you want, after you're done "step debugging" either press resume, stop, "run to cursor", or disable the breakpoint right-clicking on it (in practice this gets you out of the loop).
You can also change the value of any variable in the middle of debugging by editing in "variable watches".
PyCharm offers the possibility to add conditions on specific breakpoint.
This feature is called Conditional Breakpoints and you can find the documentation here.
I think that this is what you are looking for, because in this way you are able to enable the breakpoint only under specific conditions.
def function():
while True:
...omission...(this function is repeated permanently)
i =0
while i < 4:
driver.execute_script("""window.open("URL")""")
driver.switch_to.window(driver.window_handles[-1])
time.sleep(1)
function()
time.sleep(1)
i += 1 #open new tab and run function.
it doesn't work because while true loop is repeated permanently. Is there any ways to run multiple functions together?
https://imgur.com/a/4SIVekS This picture shows what I want
According to your picture, what you want is to launch the function a set number of times (4?), and run those in parrallel.
On a single core, as is the normal behavior, straight up parallel processing is impossible. You need to access other cores and manage a decentralized processing. while is useless there. I'm worried the level of difficulty is over your current skills, but here we go.
The overall flow that you (probably, depends on the actual memory safety of your functions) need is:
- to create a thread pool with the set number of threads for the number of runs you want.
- indicate the function you need to run
- start them, making sure the start itself is non-blocking.
- ensure one functions's processing doesn't impact another's results. race conditions are a common problem.
- gather results, again, in a non-blocking way.
You can use several methods. I highly recommend you read up a lot on the following documentations.
Threading:
https://docs.python.org/3/library/threading.html
Multiprocessing:
https://docs.python.org/3/library/multiprocessing.html
I don't understand your question because I don't understand what your function is supposed to do.
while True:
will always create an infinite loop. "while" is a command that tells python to loop through the following block so long as the expression following it evaluates to True. True always evaluates to True.
It seems like you want to use a conditional, like you do in "while x < 4".
x < 4
...is an expression that evaluates to true when x is less than 4, and false if x is not less than 4. Everything below the line:
while x < 4:
will then run if x is less than 4, and when it's done running that code, it will go back and evaluate if x is less than 4 again, and if it is, run the code again. To include another while loop inside of that loop, that new loop also needs an expression to evaluate. If you want to evaluate the same expression, write it out:
while x < 4:
# do something
while x < 4:
#do more things
# do even more things
# change x at some point, or else you're in an infinite loop.
However, there's no reason to do that specifically, because you're already doing it. All of the code is only running when x < 4, so checking that condition again right there is redundant, and doing it in another loop doesn't make sense. If the inside loop is also incrementing x, then the outside loop won't loop and doesn't need to increment x.
Also, if you want a function to check a condition based on a variable outside the function, you'll want to pass things to that function.
any code editor knows where to indent in python since python uses : as its indent flag, but after completing a code block, we will want our cursor to go back in the last place it was, like this:
def test_func():
print("Here we have an auto indent")
# but how to
# return, without pressing the backspace key
No, it is not possible for an IDE to know when your block is ending in all cases.
The are a few exceptions where it is reasonable to guess that you wanted to end the current indentation level. E.g. using pass to leave a block 'empty' where the Python grammar requires you to use a block, or using return, break or continue, statements that make it impossible for Python to reach the remainder of the indented block.
However, because you must un-indent to signal the end of a block in Python, your IDE can't know in all cases when a block ends either. You can easily follow a print() call with several empty lines, then another line of code at the same indentation level, and it'll still be part of test_func() body.
It depends entirely on your editor if they implement auto-indentation rules at all, but any that does, is bound by the same limitations inherent in Python.
Is there a command to step out of cycles (say, for or while) while debugging on ipdb without having to use breakpoints out of them?
I use the until command to step out of list comprehensions, but don't know how could I do a similar thing, if possible, of entire loop blocks.
I believe this is the intent of the until command. It's like a next except that when a jump occurs to a previous line number for the loop, it will continue until exiting the loop.
unt(il)
Continue execution until the line with a number greater than the current
one is reached or until the current frame returns
In general, to "step out" of the current function, use return.
r(eturn)
Continue execution until the current function returns.
You can use j <line number> (jump) to go to another line.
for example, j 28 to go to line 28.
This could sound obvious: jump makes you jump.
This means that you don't execute the lines you jump: you should use this to skip code that you don’t want to run.
You probably need tbreak (Temporary breakpoint, which is removed automatically when it is first hit. The arguments are the same as break) as I did when I found this page.
If you are willing to use another debugger, trepan, has more ways you can step. It is more gdb-like. So you can give a count of how many times you want to step. Or you can give a line number in a continue debugger command which in essence sets a temporary breakpoint at the line and then issues "continue". Other things that change stepping are "set different". See also the even suffixes you can put on step.
Note that like ipdb, there is syntax highlighting of the source text.
I used ipdb.set_trace() somewhere in my Python code. Is it possible to ignore this break point using a IPDB command?
clear tells me that it cleared all break points, but IPDB stops again when it stumbles upon the line with ipdb.set_trace().
disable 1 tells me: No breakpoint numbered 1
ignore 1 says: Breakpoint index '1' is not valid
To clarify: Of course I could simply remove the break point from my source code. But this would require to quit the debugger and to start it again. Often it needs a lot of work to get somewhere and restarting the debugger makes life more difficult. Also if there is a huge loop and you want inspect objects in the loop, the easiest is to place a break point in the loop directly after the object. How could I then skip the loop (and all thousands of calls set_trace()) and step through the code after the loop using next?
Well, you CAN take advantage of the fact that anything in Python is an object. While in the debugger, you can do something like this:
def f(): pass
ipdb.set_trace = f
set_trace will still be called, but it won't do anything.
Of course, it's somewhat permanent, but you can just do
reload ipdb
and you'll get the original behaviour back.
(why would you do this? when you accidentally put a breakpoint in an often-called function that is usually called under a try/except. Once you realize you're stopping 1000 times in this function, you try to ctrl-c, but that gets caught by the try/except and you're back in ipdb again. So, if you're in low-level code, make sure your set_traces have some context:
if myvar in ['some', 'sentinel', 'values']:
ipdb.set_trace()
etc.
After learning from Corley
ipdb.set_trace = lambda: None
Works for me.
Based on Corley and GLaDOS answers, you can use this trick to set_trace for several loops without overwriting the ipdb.set_trace()
import ipdb
dbg1 = ipdb.set_trace # BREAKPOINT
for i in range(10):
my_var2 = 10 / 3
dbg1() # BREAKPOINT
dbg1 = lambda: None
print(my_var2)
dbg2 = ipdb.set_trace # BREAKPOINT
for i in range(10):
my_var2 = 20 / 3
dbg2() # BREAKPOINT
dbg2 = lambda: None
print(my_var2)
Works for me like a charm.
Running the program should also tell you exactly where you've set your idb.set_trace() when it's being hit (otherwise, try the where or bt commands). You can then remove that line from the file, and restart the program.
Otherwise, you might find this useful, if you feel more experimental.