I'm new to coding and python so i'm doing an online free course. There's one task that i'm supposed to do that is not working properly, and apparently the problem is identation. Here's the code:
c = 0
while c < 5:
c += 1
if c == 3:
continue
print (c)
So the last line is aligned with the previous one, and the code only runs properly after I delete one identation from the last line. How do I configure this to be automatic so I won't have to delete it all the time?
TLDR: In general, no, you cannot configure this automatically. However, there are some specific cases where we can say a statement is definitely in the wrong scope with the help of a linter. The onus is still on the programmer to actually correct the program, though, even with the help of the linter.
General Case:
No programming language can know what scope you'd like a statement to be in. That is for you, the programmer, to express in the language. Python's scoping happens to be determined by whitespace, not curly braces, like in some other popular languages (namely C/C++/Java/Perl).
Consider:
if x:
do_y()
do_z()
vs.
if x:
do_y()
do_z()
Both are legal Python programs, and both are (potentially) logically correct, depending on the application. Maybe you only want to call do_z() if x is true (first example). Or maybe you always want to call do_z() regardless of x (second example). Only the application developer can decide which they want. And which one you want might actually change over time, depending on circumstance. So it should be very clear that this decision (in general) cannot be made automatically.
Using pylint:
However, sometimes what we can say is that some statement is definitely in the wrong scope (like in your example above, a statement immediately after a continue can never be reached).
You can use a linter (like pylint) to help with this:
In test.py I've placed your question code and gave it a quick pylint:
(so) URSA-MattM-MacBook:stackoverflow mmessersmith$ cat test.py
c = 0
while c < 5:
c += 1
if c == 3:
continue
print(c)
(so) URSA-MattM-MacBook:stackoverflow mmessersmith$ pylint test.py
************* Module test
test.py:1:0: C0111: Missing module docstring (missing-docstring)
test.py:1:0: C0103: Constant name "c" doesn't conform to UPPER_CASE naming style (invalid-name)
test.py:6:8: W0101: Unreachable code (unreachable)
------------------------------------------------------------------
Your code has been rated at 5.00/10 (previous run: 5.00/10, +0.00)
Note that this line: test.py:6:8: W0101: Unreachable code (unreachable). That's telling you that line 6 can never be executed, regardless of program state.
Furthermore, note that any linter still cannot automatically correct indent. There are two legal possibilities for where the print(c) statement should be indented:
c = 0
while c < 5:
c += 1
if c == 3:
continue
print (c)
and
c = 0
while c < 5:
c += 1
if c == 3:
continue
print (c)
Both are legal (and reasonable) Python programs! The first will print c in every iteration of the while loop, the second will only print c after the loop has finished. Only you, the programmer, can decide which one you'd like. All the linter can say is "you almost certainly didn't mean to put a statement immediately after a continue, since that code will never be executed".
Again, it is up to you where you'd like the statement. No automated tool can automatically place the statement for you, because it can't possibly know what you want to accomplish.
In your code, print(c) is after continue. But statements after continue is not executed. continue works as ignore the statements after it and go for the next iteration. So print(c) doesn't work. Your code should be like this :-
c = 0
while c < 5:
c += 1
if c == 3:
continue
print (c)
This will print
1
2
4
5
Related
I have to edit a python file such that after every if condition, i need to add a line which says
if condition_check:
if self.debug == 1: print "COVERAGE CONDITION #8.3 True (condition_check)"
#some other code
else:
if self.debug == 1: print "COVERAGE CONDITION #8.4 False (condition_check)"
#some other code
The number 8.4(generally y.x) refer to the fact that this if condition is in function number 8(y) (the functions are just sequentially numbers, nothing special about 8) and x is xth if condition in yth function.
and of course, the line that will be added will have to be added with proper indentation. The condition_check is the condition being checked.
For example:
if (self.order_in_cb):
self.ccu_process_crossing_buffer_order()
becomes:
if (self.order_in_cb):
if self.debug == 1: print "COVERAGE CONDITION #8.2 TRUE (self.order_in_cb)"
self.ccu_process_crossing_buffer_order()
How do i achieve this?
EXTRA BACKGROUND:
I have about 1200 lines of python code with about 180 if conditions - i need to see if every if condition is hit during the execution of 47 test cases.
In other words i need to do code coverage. The complication is - i am working with cocotb stimulus for RTL verification. As a result, there is no direct way to drive the stimulus, so i dont see an easy way to use the standard coverage.py way to test coverage.
Is there a way to check the coverage so other way? I feel i am missing something.
If you truly can't use coverage.py, then I would write a helper function that used inspect.stack to find the caller, then linecache to read the line of source, and log that way. Then you only have to change if something: to if condition(something): throughout your file, which should be fairly easy.
Here's a proof of concept:
import inspect
import linecache
import re
debug = True
def condition(label, cond):
if debug:
caller = inspect.stack()[1]
line = linecache.getline(caller.filename, caller.lineno)
condcode = re.search(r"if condition\(.*?,(.*)\):", line).group(1)
print("CONDITION {}: {}".format(label, condcode))
return cond
x = 1
y = 1
if condition(1.1, x + y == 2):
print("it's two!")
This prints:
CONDITION 1.1: x + y == 2
it's two!
I have about 1200 lines of python code with about 180 if conditions - i need to see if every if condition is hit during the execution of 47 test cases. In other words i need to do code coverage. The complication is - i am working with cocotb stimulus for RTL verification.
Cocotb has support for coverage built in (docs)
export COVERAGE=1
# run cocotb however you currently invoke it
I'm very unfamiliar with Python 2.x and I have some inherited code in many files where I need to count how many times some particular functions are called (to solve a particular problem).
To show what I mean, in another simple language I would do this
Add at the beginning of the code
counter_funcA = 0
counter_funcB = 0
...
In the beginning of function A
counter_funcA += 1
In the beginning of function B
counter_funcB += 1
And so on...
And at the end
print counter_funcA
...
So how would a python expert do this in a nice way?
I guess the operation += is quite atomic -- so there will not be any concurrency issues?
Just in recent times I went through one of my code (in Python) in which guard evaluation was badly missed. I shortened my code to make it a brief one
>>> x = 4
>>> y = 0
>>> x >= 1 and (x/y) > 2
Traceback (most recent call last):
File "<pyshell#16>", line 1, in <module>
x >= 2 and (x/y) > 2
ZeroDivisionError: integer division or modulo by zero
here we need to add guard
>>> x >= 1 and y != 0 and (x/y) > 2 # y!=0 is a guard
False
Now I have two questions:
I believe similar kind of scenario could have been best caught with
C++, as it compiles the code and will produce a warning at first. Let
me know if I am wrong here?
Other question is that we use py_compile.compile('file_name') and it
just verifies syntax. Don't we have any module in Python that can catch
these kind of misses?
Since python is a loosely typed language, thus it become difficult(impossible i believe) to analyze the code for the variable types. We can use pep8 or pylint to analyze the code. They can only inform us about the indenting and code writing as per PEP.
For below file guard_eval.py
sherry#Sherry-Linux:~$ cat guard_eval.py
x=6
y=0
if x >= 1 and (x/y) > 2:
print True
else:
print False
sherry#Sherry-Linux:~$ pep8 guard_eval.py
guard_eval.py:1:2: E225 missing whitespace around operator
guard_eval.py:2:2: E225 missing whitespace around operator
guard_eval.py:4:1: W191 indentation contains tabs
guard_eval.py:6:1: W191 indentation contains tabs
pylint provides code ratings as well :)
But in case of C++ we can modify the compiler to analyze code with the variable type and hint user to have guard expression for integer/integer division while compiling.
My IDE is warning me against a possible variable reference before assignment. But I'm having trouble spotting it. I'm ready to turn in a bug report, but maybe you can see what I'm not seeing.
The variable in question is a named check_dialog and the reference before assignment warning happens at the end of the following code snippet in the line I marked for you:
if dialog:
validate = None
string = False
if dialog == Prompt.YES | Prompt.NO:
check_dialog = lambda c: chr(c) in 'yn'
elif dialog == Prompt.CONTINUE | Prompt.QUIT:
check_dialog = lambda c: chr(c) in 'cq'
elif dialog == Prompt.YES | Prompt.NO | Prompt.QUIT:
check_dialog = lambda c: chr(c) in 'ynq'
else:
raise ValueError('Invalid dialog argument.')
answer = None
while not answer:
self.addstr(0, 1, prompt)
if string:
curses.curs_set(True)
curses.echo()
answer = self.getstr(1, 3)
curses.noecho()
curses.curs_set(False)
elif dialog:
while not check_dialog(answer): # warning here!
answer = self.getch()
else:
answer = self.getch()
Your IDE is not "thinking" about every possible value of your variables (in most cases, this would be impossible) and instead is using heuristics to prevent common mistakes. In this case, it has noticed that check_dialog is defined within an if condition, but not in every case. Yet it is used below this condition. That might be an UnboundLocalError!
As programmers, we can reason this out and see that the code paths it has noticed are protected. The else case raises a ValueError which will not be caught, and the usage is protected by (el)if dialog in both cases, so this will not be a problem.
It is not a bug in your IDE, because it is doing what it is supposed to. If it really bothers you and you can't otherwise silence the warning, you can unnecessarily define something like check_dialog = None over the top of the first if dialog, and it will shut up. However, it is also not a bug with your program/code, which as reasoned above will not cause an UnboundLocalError. This is safe to ignore, and because of how your IDE probably works a bug report would just be closed.
I have to evaluate (millions of) Python expressions e.g. (int(a) >> 8 == 4) and b
in my OCaml program. There is pycaml but I failed to get it working.
So I turned to another idea: control the input/output of Python interpreter directly.
Ideally I would like to intercept both the input/output of the interpreter itself.
By sending a = 3 b = 5 a > b to the interpreter, I would then be able to get the result False, as if I have done this by keyboard..
>>> a = 3
>>> b = 5
>>> a > b
False
>>>
However, my code doesn't working as expected (while the same code worked for some interactive program)
let (readme, writeme) = Unix.open_process "python -u";;
let _ = output_string writeme "3 + 5\n" in
let _ = flush writeme in
let result = input_line readme in
print_endline result;;
I tried changing 3 + 5\n to print 3\n, but it still hangs at input_line.
Is there any better way to do this? I would need to evaluate quite a lot of
expressions, so I don't really want to do this via a temp file. Any help appreciated,
Thanks.
I'm not going to comment on the weirdness of the entire concept (driving python to evaluate expressions from o'caml) but it seems like you might want to look into writing a python program that is an eval cycle that reads/writes a string from/to a pipe. Look up the eval command.
You can supply a command to the interpreter through the command line:
$ python -c 'a = 3; b = 5; print a > b'
False
Is that adequate for your needs?
If you're concerned about opening the interpreter repeatedly, you could generate and evaluate many expressions at once. I'm not sure what the upper limit is, but I was able to evaluate and print 200 concatenated copies of a = 3; b = 5; print a > b; without any problem.