Why not python implicit line continuation on period? - python

Is there any reason Python does not allow implicit line continuations after (or before) periods? That is
data.where(lambda d: e.name == 'Obama').
count()
data.where(lambda d: e.name == 'Obama')
.count()
Does this conflict with some feature of Python? With the rise of method chaining APIs this seems like a nice feature.

Both of those situations can lead to valid, complete constructs, so continuing on them would complicate the parser.
print 3.
1415926
print 'Hello, world'
.lower()

Python allow line continuations within parentheticals (), so you might try:
(data.where(lambda d: e.name == 'Obama').
count())
I know that's not answering your question ("why?"), but maybe it's helpful.

Use a '\' at the end. (looks ugly though)
data.where(lambda d: e.name == 'Obama').\
count()

Not sure about after periods, but in your example the newline before a period leads to the first line being a valid statement on its own. Then Python would have to look ahead to the second line to know whether the first line was a statement or not.
One of the goals when defining the language syntax was to be able to parse it without having ambiguities that require looking ahead like that.
It'd get annoying in the interactive interpreter if you had to press enter twice after every single line just so Python knew you'd finished your statement and weren't going to put a .foo() after it.

In the cases where a period could be leading in to a method call, it will always(?) be a syntax error for it to just occur at the end of a line by itself. So it would be unambiguous to read it as starting a continuation.
However, Python generally speaking doesn't continue a line just because there's an incomplete binary operator there. For instance, the following is not valid:
2 +
4
In the second example, the first line is valid by itself and it would be really inconsistent for Python to look for a following line "just in case" there is one.
I would just break after the opening paren of the method call.

{Because python uses line breaks to end statements, not depending on braces or semi-colins;}

Related

How to tell if the next line should be indented when parsing python

I am writing a simple templating engine in python, and it involves mixing python with other languages, and I need to determine the indentation level of any given line of python code.
I was wondering if it's accurate to say that a new indentation level is always indicated by a colon (:) at the end of the line.
Here's a line of python:
if my_boolean:
Since there is a colon at the end of this line, I would determine that the next line of python should be an indented block. Is this always accurate? Are there cases when I need to indent when a colon is not present?
A colon at the end of the line is the most prevalent example of an indicator that the following line is indented. The other one is any line that has more opening parentheses, braces, or brackets than closing ones. The latter case is more complicated because the order of the brackets matters very much, and also because the following indentation is arbitrary.
Another thing to consider is that you don't have any indication that wether a given line is expected to be unindented until you get to it.
The moral of the story is that you're better off using the existing machinery exposed by the ast module rather than reinventing the wheel. It's an awfully complicated wheel sometimes.

How to tell if a single line of python is syntactically valid?

It is very similar to this:
How to tell if a string contains valid Python code
The only difference being instead of the entire program being given altogether, I am interested in a single line of code at a time.
Formally, we say a line of python is "syntactically valid" if there exists any syntactically valid python program that uses that particular line.
For instance, I would like to identify these as syntactically valid lines:
for i in range(10):
x = 1
Because one can use these lines in some syntactically valid python programs.
I would like to identify these lines as syntactically invalid lines:
for j in range(10 in range(10(
x =++-+ 1+-
Because no syntactically correct python programs could ever use these lines
The check does not need to be too strict, it just need to be good enough to filter out obviously bogus statements (like the ones shown above). The line is given as a string, of course.
This uses codeop.compile_command to attempt to compile the code. This is the same logic that the code module does to determine whether to ask for another line or immediately fail with a syntax error.
import codeop
def is_valid_code(line):
try:
codeop.compile_command(line)
except SyntaxError:
return False
else:
return True
It can be used as follows:
>>> is_valid_code('for i in range(10):')
True
>>> is_valid_code('')
True
>>> is_valid_code('x = 1')
True
>>> is_valid_code('for j in range(10 in range(10(')
True
>>> is_valid_code('x = ++-+ 1+-')
False
I'm sure at this point, you're saying "what gives? for j in range(10 in range(10( was supposed to be invalid!" The problem with this line is that 10() is technically syntactically valid, at least according to the Python interpreter. In the REPL, you get this:
>>> 10()
Traceback (most recent call last):
File "<pyshell#22>", line 1, in <module>
10()
TypeError: 'int' object is not callable
Notice how this is a TypeError, not a SyntaxError. ast.parse says it is valid as well, and just treats it as a call with the function being an ast.Num.
These kinds of things can't easily be caught until they actually run.
If some kind of monster managed to modify the value of the cached 10 value (which would technically be possible), you might be able to do 10(). It's still allowed by the syntax.
What about the unbalanced parentheses? This fits the same bill as for i in range(10):. This line is invalid on its own, but may be the first line in a multi-line expression. For example, see the following:
>>> is_valid_code('if x ==')
False
>>> is_valid_code('if (x ==')
True
The second line is True because the expression could continue like this:
if (x ==
3):
print('x is 3!')
and the expression would be complete. In fact, codeop.compile_command distinguishes between these different situations by returning a code object if it's a valid self-contained line, None if the line is expected to continue for a full expression, and throwing a SyntaxError on an invalid line.
However, you can also get into a much more complicated problem than initially stated. For example, consider the line ). If it's the start of the module, or the previous line is {, then it's invalid. However, if the previous line is (1,2,, it's completely valid.
The solution given here will work if you only work forward, and append previous lines as context, which is what the code module does for an interactive session. Creating something that can always accurately identify whether a single line could possibly exist in a Python file without considering surrounding lines is going to be extremely difficult, as the Python grammar interacts with newlines in non-trivial ways. This answer responds with whether a given line could be at the beginning of a module and continue on to the next line without failing.
It would be better to identify what the purpose of recognizing single lines is and solve that problem in a different way than trying to solve this for every case.
I am just suggesting, not sure if going to work... But maybe something with exec and try-except?
code_line += "\n" + ("\t" if code_line[-1] == ":" else "") + "pass"
try:
exec code_line
except SyntaxError:
print "Oops! Wrong syntax..."
except:
print "Syntax all right"
else:
print "Syntax all right"
Simple lines should cause an appropriate answer

Ending a comment in Python

I have already read this: Why doesn't Python have multiline comments?
So in my IDLE , I wrote a comment:
Hello#World
Anything after the d of world is also a part of the comment.In c++ , I am aware of a way to close the comment like:
/*Mycomment*/
Is there a way to end a comment in Python?
NOTE: I would not prefer not to use the triple quotes.
You've already read there are no multiline comments, only single line. Comments cause Python to ignore everything until the end of the line. You "close" them with a newline!
I don't particularly like it, but some people use multiline strings as comments. Since you're just throwing away the value, you can approximate a comment this way. The only time it's really doing anything is when it's the first line in a function or class block, in which case it is treated as a docstring.
Also, this may be more of a shell scripting convention, but what's so bad about using multiple single line comments?
#####################################################################
# It is perfectly fine and natural to write "multi-line" comments #
# using multiple single line comments. Some people even draw boxes #
# with them! #
#####################################################################
You can't close a comment in python other than by ending the line.
There are number of things you can do to provide a comment in the middle of an expression or statement, if that's really what you want to do.
First, with functions you annotate arguments -- an annotation can be anything:
def func(arg0: "arg0 should be a str or int", arg1: (tuple, list)):
...
If you start an expression with ( the expression continues beyond newlines until a matching ) is encountered. Thus
assert (
str
# some comment
.
# another comment
join
) == str.join
You can emulate comments by using strings. They are not exactly comments, since they execute, but they don't return anything.
print("Hello", end = " ");"Comment";print("World!")
if you start with triple quotes, end with triple quotes

Python style for `chained` function calls

More and more we use chained function calls:
value = get_row_data(original_parameters).refine_data(leval=3).transfer_to_style_c()
It can be long. To save long line in code, which is prefered?
value = get_row_data(
original_parameters).refine_data(
leval=3).transfer_to_style_c()
or:
value = get_row_data(original_parameters)\
.refine_data(leval=3)\
.transfer_to_style_c()
I feel it good to use backslash \, and put .function to new line. This makes each function call has it own line, it's easy to read. But this sounds not preferred by many. And when code makes subtle errors, when it's hard to debug, I always start to worry it might be a space or something after the backslash (\).
To quote from the Python style guide:
Long lines can be broken over multiple lines by wrapping expressions
in parentheses. These should be used in preference to using a
backslash for line continuation. Make sure to indent the continued
line appropriately. The preferred place to break around a binary
operator is after the operator, not before it.
I tend to prefer the following, which eschews the non-recommended \ at the end of a line, thanks to an opening parenthesis:
value = (get_row_data(original_parameters)
.refine_data(level=3)
.transfer_to_style_c())
One advantage of this syntax is that each method call is on its own line.
A similar kind of \-less structure is also often useful with string literals, so that they don't go beyond the recommended 79 character per line limit:
message = ("This is a very long"
" one-line message put on many"
" source lines.")
This is a single string literal, which is created efficiently by the Python interpreter (this is much better than summing strings, which creates multiple strings in memory and copies them multiple times until the final string is obtained).
Python's code formatting is nice.
What about this option:
value = get_row_data(original_parameters,
).refine_data(leval=3,
).transfer_to_style_c()
Note that commas are redundant if there are no other parameters but I keep them to maintain consistency.
The not quoting my own preference (although see comments on your question:)) or alternatives answer to this is:
Stick to the style guidelines on any project you have already - if not stated, then keep as consistent as you can with the rest of the code base in style.
Otherwise, pick a style you like and stick with that - and let others know somehow that's how you'd appreciate chained function calls to be written if not reasonably readable on one-line (or however you wish to describe it).

Learning Python else syntax error

Hi I am learning python by doing the practice problems for Open course at MIT 6.00 Intro to Computer Science.
I am Trying to do practice problem 1 part 2 create a recursive function to count the instance of key in target. My code so far...
from string import *
def countSubStringMatchRecursive (target, key,x,s):
if (find(target,key)==find(target,key,s)) and (find(target,key)==find(target,key,(find(target,key)))):#if first and last
return (1)
elif (find(target,key)==find(target,key,s))and (find(target,key)!=find(target,key,(find(target,key)))):#if first but not last
x=1
s= find(target,key)
return (countSubStringMatchRecursive(target,key,s,x)
elif (find(target,key,s))==-1 and (find(target,key)!=find(target,key,s)):#if last but not first
return (x+1)
elif:(find(target,key,s))!=-1 and (find(target,key)!=find(target,key,s)):#if not last and not first
x=x+1
s= find(target,key,s)
return (countSubStringMatchRecursive(target,key,s,x)
I getting a syntax error at line 8. I would just like to know what I did wrong there. Dont worry about the other mistakes I should be able to get those sorted out. I just Stuck on this. Thanks.
You're missing a closing parenthesis in line 8 and in the last line. Actually, the corresponding opening parenthesis is unnecessary, you might as well rewrite those line as this:
return countSubStringMatchRecursive(target,key,s,x)
Also, as pointed by #rodion in the comments, the last elif has a misplaced :, remove the one right before the opening parenthesis.
And talking about parenthesis: in Python you don't have to place the conditions of an if ... elif ... else statement inside parenthesis, you should drop them.
You have an unmatched paren on line 8. Add another close paren at the end
return (countSubStringMatchRecursive(target,key,s,x))
Same thing applies to your final return statement.
You have a mismatched parenthesis. Remove the ( near the beginning of the line or add a ) to the end.
return (countSubStringMatchRecursive(target,key,s,x)
You're missing a closing ). But you didn't need the opening one either; the syntax of a return statement is return <expr>, so anything that's a valid expression can directly follow return. Anything that's a valid expression is still a valid expression meaning exactly the same thing if you surround it with parentheses, but mostly that just adds noise when it's not needed.
There are several problems:
You are missing a closing paren on line 8
the body of your function needs to be indented. (update: has been fixed)
Also, your last elif has a : right after it, that needs to be
deleted. I.e.,
elif: expression:
should be
elif expression:
Your last statement is also missing a closing paren
return (countSubStringMatchRecursive(target,key,s,x)
should be
return (countSubStringMatchRecursive(target,key,s,x))
Finally #drewk's recommendation about taking a look at the PEP 8 is a good one. I periodically go back and review it myself.
Also, you have a number of unnecessary ()s .. they don't do any harm, but they are not needed and may reduce the readability of your code.

Categories