Is there a way to avoid "expected indent block" errors in Python without adding pass to a function?
def exclamation(s):
# s += "!!!"
# return s
print exclamation("The indented horror")
The above code results in an error on line 5. Yes, remove the comments and the code works fine. However, in debugging stuff I often find myself in a similar situation. Is this just a hang-up of the off-side rule and something I need to get used to or are there ways around this?
There has to be something within your function definition to avoid a SyntaxError.
The issue is that the interpreter will effectively ignore comments during parsing, and so while to a human it might look like something is there, to the parser it is empty.
As jonrsharpe has pointed out in a comment, you can use docstrings to "comment out" your code and have it still work. This is because the docstring is, in effect, a normal string. As such this will be parsed and won't cause a SyntaxError. To take your example code it would look like:
def exclamation(s):
'''s += "!!!"
return s'''
# This should print None as nothing is now returned from the func
print(exclamation("The indented horror"))
Related
Basically I am curious about why this throws a syntax error and what is the pythonic way to 'comment out' portions of my code that I am not using, for example during a debugging session.
'''
def foo():
'''does nothing'''
'''
You can use triple double quotes to comment out triple single quotes:
"""
def foo():
'''does nothing'''
"""
Python is interpreting your code like this:
First comment:
'''
def foo():
'''
Second comment:
'''
'''
Therefore, the "does nothing" is outside the comment, and python tries to interpret it, but the syntax is invalid, so it gives an error.
The Pythonic way is to understand the difference between a multi-line string and a comment and use them appropriately.
Python does not have multi-line comments, but many python aware editors and IDE's have ways to automatically comment out selected multiple lines, (and the reverse). You might want to search for that useful functionality.
Python has never used braces to define code blocks, it relies on indentation instead; this is one of the defining features of the language. There's even a little cookie that CPython gives you to show how strongly they feel about this:
>>> from __future__ import braces
SyntaxError: not a chance
When I saw this little snippet posted to a forum (since deleted) I thought it cannot possibly work. But it does!
>>> def hi(): {
print('Hello')
}
>>> hi()
Hello
Why does this code work, when it appears to violate the language syntax?
The braces aren't defining a code block as they would in other languages - they're defining a set. The print function is being evaluated and its return value (None) is being placed in the set. Once the set is created it is immediately discarded since it isn't being assigned to anything.
There are a couple of Python syntax features that are being exploited here. First, Python allows a single-statement code block to come immediately after a :. Second, an expression is allowed to span multiple lines under certain circumstances.
This code wouldn't have worked if the body of the block were more than one line, or if an assignment or statement other than a function call were attempted.
Here's a redoing of the function to make it clearer what's happening:
>>> def hi2(): print(
{ print('Hello') }
)
>>> hi2()
Hello
{None}
I need to execute a line of python code that is entered by the user.
If it is a statement I want to execute it, but if it is an expression, I want the result to be returned and do some fancy stuff with it.
The problem is that python has two different functions for that, namely exec and eval.
Currently I just try to evaluate the string that the user entered.
If that raises a SyntaxError, this may indicate that the string is an statement instead, so I try to execute it.
try:
result = eval(command, scope)
except SyntaxError:
# Probably command is a statement, not an expression
try:
exec(command, scope)
except Exception as e:
return command + ' : ' + str(e)
except Exception as e:
return command + ' : ' + str(e)
else:
pass # Some fancy stuff
This feels rather hacky. Is there a neater, more pythonic way to do this?
While I think your existing code is probably reasonably Pythonic (under the doctrine that it's "easier to ask forgiveness than permission"), I suspect the best alternative approach is to use the ast module to inspect the code in your string:
tree = ast.parse(some_input_string)
if len(tree.body) == 1 and isinstance(tree.body[0], ast.Expr):
result = eval(some_input_string, scope)
else:
exec(some_input_string, scope)
result = None
Note that some common statements are really "expression statements". So, an input string like 'do_stuff("args")' will use the eval branch of the code above, rather than the exec branch. I don't think this will have any adverse consequences, but you never know.
It is also possible to compile the tree that has been parsed and then pass the result into the eval or exec calls later. I found it rather fiddly to get right though (you need to wrap the ast.Expr's value attribute in an ast.Expression in the top branch) and so I went with the simpler (to read and understand) alternative of just passing in the string and letting Python parse it again.
You can refactor the try-except a bit. There's no real context in your example, but assuming you want to be able to execute a=1 and then evaluate a afterwards and get 1, then you could do something like...
from code import InteractiveConsole
interpreter = InteractiveConsole()
def run(code):
try: return eval(code.strip(), interpreter.locals)
except: pass
try: interpreter.runcode(code)
except Exception as error: return error
This should work for more than one line of code too.
Without knowing a bit more about your objective it's difficult to say how to do it best, but what you have is fine in principle, it just needs tidying up. This similar answer includes a minimal version of the same try-except logic again, with a focus on mimicking the interpreter more faithfully.
you missed one, actually there are three functions related to executing code, and the one you missed is compile().
compile() takes three required arguments, the code to be compiled, the name of the module being compiled, which will appear in tracebacks originating from that code, and a "mode". The mode argument should be one of "exec", for compiling whole modules, "eval" for compiling simple expressions, and "single", which should be a single line of interactive input!
In all three cases, you pass the returned code object to eval, with the desired context:
>>> c = compile("if 1 < 2:\n print(3)", "<string>", "single")
>>> eval(c)
3
>>>
I have recently noticed that some people mark the end of indented code blocks with the pass keyword, such as:
def f():
for i in range(10):
do_something(i)
pass
pass
I don't understand why. Are there any advantages?
I know the pass keyword does nothing and it is the equivalent of { } in other languages. My question is more related to a convention. For example, maybe people like to have something marking the end of a long code block.
Do you think Python's indention-sensitive grammar is harmful?
If your answer is "no",
then using pass to mark an end does nothing but clutter the cleanness
brought in by Python's indention sensitive grammar.
If your answer is "yes",
then using pass to mark an end is a workaround for the ambiguity
brought in by Python's indention sensitive grammar.
In Python, there is no {} and end, but semantic white spaces.
For example, consider the following Ruby code:
def f
for i in 0...10
i = i * 2
print(i)
end
end
And the equivalent Python code:
def f():
for i in range(10):
i = i * 2
print(i)
With one wrong keystroke (TAB):
def f():
for i in range(10):
i = i * 2
print(i)
The above code is also valid.
To avoid this kind of mistakes, we can use pass for end in Python:
def f():
for i in range(10):
i = i * 2
print(i)
pass
pass
With one wrong keystroke (TAB):
def f():
for i in range(10):
i = i * 2
print(i)
pass
pass
Python will refuse to work:
IndentationError: unexpected indent
However, python will not always catch unintended indentation even with pass.
Suppose we intend to write:
def g():
for i in range(10):
i = i * 2
pass
print(i)
pass
With one wrong keystroke (TAB):
def g():
for i in range(10):
i = i * 2
pass
print(i)
pass
Python will not refuse to work.
But using pass still has two advantages:
It still provides visual hint.
If you think pass as the last clause of an indented block,
print(i) looks weird to you in the above code.
A decent editor/IDE will indent correctly if you typed pass.
For the second pass,
if f() is a top-level function,
and your code adheres to PEP8:
Surround top-level function and class definitions with two blank lines.
You may omit the second pass.
But PEP8 also said:
Extra blank lines may be used (sparingly)
to separate groups of related functions.
Thus I prefer pass.
There is no advantage. If the function has a body at all, adding pass does nothing. It doesn't even do anything if there is no body, except to help the parser know that the empty body was intentional.
In real-world code, it's usually better to use a docstring than pass to denote deliberately-empty code:
class MyExtraException(Exception):
"""Just another exception"""
Is there any advantages?
No.
Placing pass at the end of non-empty code blocks like that just wastes lines. Remember that pass is a do-nothing placeholder in Python; it should only be used when you need to fill in an empty code block.
If you would like some examples of when to use pass, see this SO question as well as this one.
I was working with generator functions and private functions of a class. I am wondering
Why when yielding (which in my one case was by accident) in __someFunc that this function just appears not to be called from within __someGenerator. Also what is the terminology I want to use when referring to these aspects of the language?
Can the python interpreter warn of such instances?
Below is an example snippet of my scenario.
class someClass():
def __init__(self):
pass
#Copy and paste mistake where yield ended up in a regular function
def __someFunc(self):
print "hello"
#yield True #if yielding in this function it isn't called
def __someGenerator (self):
for i in range(0, 10):
self.__someFunc()
yield True
yield False
def someMethod(self):
func = self.__someGenerator()
while func.next():
print "next"
sc = someClass()
sc.someMethod()
I got burned on this and spent some time trying to figure out why a function just wasn't getting called. I finally discovered I was yielding in function I didn't want to in.
A "generator" isn't so much a language feature, as a name for functions that "yield." Yielding is pretty much always legal. There's not really any way for Python to know that you didn't "mean" to yield from some function.
This PEP http://www.python.org/dev/peps/pep-0255/ talks about generators, and may help you understand the background better.
I sympathize with your experience, but compilers can't figure out what you "meant for them to do", only what you actually told them to do.
I'll try to answer the first of your questions.
A regular function, when called like this:
val = func()
executes its inside statements until it ends or a return statement is reached. Then the return value of the function is assigned to val.
If a compiler recognizes the function to actually be a generator and not a regular function (it does that by looking for yield statements inside the function -- if there's at least one, it's a generator), the scenario when calling it the same way as above has different consequences. Upon calling func(), no code inside the function is executed, and a special <generator> value is assigned to val. Then, the first time you call val.next(), the actual statements of func are being executed until a yield or return is encountered, upon which the execution of the function stops, value yielded is returned and generator waits for another call to val.next().
That's why, in your example, function __someFunc didn't print "hello" -- its statements were not executed, because you haven't called self.__someFunc().next(), but only self.__someFunc().
Unfortunately, I'm pretty sure there's no built-in warning mechanism for programming errors like yours.
Python doesn't know whether you want to create a generator object for later iteration or call a function. But python isn't your only tool for seeing what's going on with your code. If you're using an editor or IDE that allows customized syntax highlighting, you can tell it to give the yield keyword a different color, or even a bright background, which will help you find your errors more quickly, at least. In vim, for example, you might do:
:syntax keyword Yield yield
:highlight yield ctermbg=yellow guibg=yellow ctermfg=blue guifg=blue
Those are horrendous colors, by the way. I recommend picking something better. Another option, if your editor or IDE won't cooperate, is to set up a custom rule in a code checker like pylint. An example from pylint's source tarball:
from pylint.interfaces import IRawChecker
from pylint.checkers import BaseChecker
class MyRawChecker(BaseChecker):
"""check for line continuations with '\' instead of using triple
quoted string or parenthesis
"""
__implements__ = IRawChecker
name = 'custom_raw'
msgs = {'W9901': ('use \\ for line continuation',
('Used when a \\ is used for a line continuation instead'
' of using triple quoted string or parenthesis.')),
}
options = ()
def process_module(self, stream):
"""process a module
the module's content is accessible via the stream object
"""
for (lineno, line) in enumerate(stream):
if line.rstrip().endswith('\\'):
self.add_message('W9901', line=lineno)
def register(linter):
"""required method to auto register this checker"""
linter.register_checker(MyRawChecker(linter))
The pylint manual is available here: http://www.logilab.org/card/pylint_manual
And vim's syntax documentation is here: http://www.vim.org/htmldoc/syntax.html
Because the return keyword is applicable in both generator functions and regular functions, there's nothing you could possibly check (as #Christopher mentions). The return keyword in a generator indicates that a StopIteration exception should be raised.
If you try to return with a value from within a generator (which doesn't make sense, since return just means "stop iteration"), the compiler will complain at compile-time -- this may catch some copy-and-paste mistakes:
>>> def foo():
... yield 12
... return 15
...
File "<stdin>", line 3
SyntaxError: 'return' with argument inside generator
I personally just advise against copy and paste programming. :-)
From the PEP:
Note that return means "I'm done, and have nothing interesting to
return", for both generator functions and non-generator functions.
We do this.
Generators have names with "generate" or "gen" in their name. It will have a yield statement in the body. Pretty easy to check visually, since no method is much over 20 lines of code.
Other methods don't have "gen" in their name.
Also, we do not every use __ (double underscore) names under any circumstances. 32,000 lines of code. Non __ names.
The "generator vs. non-generator" method function is entirely a design question. What did the programmer "intend" to happen. The compiler can't easily validate your intent, it can only validate what you actually typed.