Can I write intentionally "mis-indented" Python code? - python

In free-form languages, sometimes I use indentation to represent some implicit structure in my statements. In the following example, I'm just doing a sequence of prints but the indentation indicates that the first and fourth print statements are "bracketing" the two in the middle.
print("<div>")
print("hello")
print("world")
print("</div>")
Is there a way to do something similar in Python without triggering an IndentationError: unexpected indent?
So far, the best I could think is to use a vacuous if statement to introduce a new indentation level.
print("<div>")
if True:
print("hello")
print("world")
print("</div>")

I, too, remember sometimes wanting such structure. This is what comes to mind (in C code that allows this mis-indentation):
glBegin(GL_TRIANGLES);
drawVertices();
glEnd();
Note that we have a begin and an end, and from here on I'm going to assume that the same happens in your case: you want to denote the beginning and ending of something. Another situation would be opening and closing a file, or even the example in your question. Python has a specific feature for this: context managers. Python's documentation even has an example with exactly this:
(this is not recommended as a real way of generating HTML!):
from contextlib import contextmanager
#contextmanager
def tag(name):
print("<%s>" % name)
yield
print("</%s>" % name)
>>> with tag("h1"):
... print("foo")
...
<h1>
foo
</h1>
I have to mention that context managers aren't simply a way to restructure your code, they can actually act on exceptions raised from the enclosed code, and execute some code regardless of the exception (e.g. to ensure that a file is closed). With the simple examples using #contextmanager this does not happen because its default behavior is to simply re-raise the exception so no surprises happen.
Other than this, the people you work with will not be happy about the false indentation. If you insist on it, sure, if True is an option.

In general, no, indentation is significant in Python.
Some alternatives that you can use are comments and line spacing:
print("start")
print("middle1")
print("middle2")
print("end")
or
# Header
print("start")
# Middle
print("middle1")
print("middle2")
# End
print("end")
You could also consider breaking your code up into sub-functions, if it makes sense to do so.
def printMiddle():
print("middle1")
print("middle2")
print("start")
printMiddle()
print("end")
However, for the specific use-case of generating nested output (like HTML), I'd suggest using a templating library instead; writing raw HTML via string manipulation can lead to both hassle and bugs (especially when things like escaping of values is involved).

Related

Why does Python ignore comment indentation?

Apparently, this:
def f():
pass
# maybe the function is over
pass # oh wait, it's not
f()
is valid syntax, whereas this is not:
def f():
pass
''' maybe the function is over '''
pass # oh wait, it's not
f()
That comes as a huge surprise to me. So my questions are:
Why? Why does Python not consider the first version to be a syntax error?
Is there anything in PEP8 recommending that this not be done?
Yes the first one is valid because it starts with # which defined in the language to be a comment line so it's ignored and its indentation won't end functions or start new ones.
The latter is different, it's a string evaluated but its value is never used, you could use that to achieve multi line comments but still the interpreter will try to evaluate that string as code, so the indentation of this string matter to the interpreter and it could end scopes.
for the second one writing something like
'''comment''''
is as much code to the interpreter as this
my_var = '''comment'''
But this
# comment
is ignored and is not code to the interpreter.

Using pass on a non necessary else statement

Based on PEP8 documentation, I was not able to find any reference regarding if I should use pass for aesthetic reasons on code. Based on the example below, should I keep those else or can I erase them? Until now, the main reason I'm keeping it is based on the mantra "Explicit is better than implicit."
if fields:
for i in foo:
if i == 'something':
print "something"
else:
pass
else:
pass
Yes, you can/should remove them because they do nothing.
The Python community teaches "explicit is better than implicit" as long as the explicit code does something useful. Those else: pass's however contribute nothing positive to the code. Instead, all they do is pointlessly consume two lines each.
You can safely remove those as there's no point in keeping code around that serves no purpose:
if fields:
for i in foo:
if i == 'something':
print "something"
An else pass is dead code, you should remove it, as it adds unnecessary noise to the code and anyway the code will be clearer and easier to understand without it.
I can think of few cases where pass may be useful - the latter two are temporarily stubs:
When you want to do ignore an acceptable exception
When you need to insert a breakpoint at the end of function when debugging.
As a filler in a function whose implementation you want to postpone
I cannot imagine any other case where I will use pass
EDIT:
In some cases, when implementing if-elif-else chain, and you have some common condition that requires no action - along with rare conditions that do require specific actions - for the sake of execution efficiency, you may use pass after the first if:
if <some common condition>:
pass
elif <rare condition>:
<do something>
elif <another rare condition>:
<do something else>
else:
<do another stuff>
The thing about else is that they are not just a part of the if statements; it appears in try statements and for loops too. You don't see else being used (in this context) in those areas, do you?
try:
raw_input("say my name")
except:
print "Heisenberg"
# Meh, this is not needed.
else:
pass
If we are looping over something and checking for some condition (with the if), then an else would add unnecessary lines.
Here's a loop for finding a folder:
for path in pathlist
if os.path.isdir(path):
print "Found a folder, yay!"
break
else:
continue
Clearly, else is executed in every loop and is pointless. This could be avoided as implied in the PEP 8 itself:
But most importantly: know when to be inconsistent -- sometimes the style guide just doesn't apply. When in doubt, use your best judgment.
Look at other examples and decide what looks best. And don't hesitate
to ask! When applying the guideline would make the code less readable, even for someone who is used to reading code that follows this PEP.

Hot swapping python code (duck type functions?)

I've been thinking about this far too long and haven't gotten any idea, maybe some of you can help.
I have a folder of python scripts, all of which have the same surrounding body (literally, I generated it from a shell script), but have one chunk that's different than all of them. In other words:
Top piece of code (always the same)
Middle piece of code (changes from file to file)
Bottom piece of code (always the same)
And I realized today that this is a bad idea, for example, if I want to change something from the top or bottom sections, I need to write a shell script to do it. (Not that that's hard, it just seems like it's very bad code wise).
So what I want to do, is have one outer python script that is like this:
Top piece of code
Dynamic function that calls the middle piece of code (based on a parameter)
Bottom piece of code
And then every other python file in the folder can simply be the middle piece of code. However, normal module wouldn't work here (unless I'm mistaken), because I would get the code I need to execute from the arguement, which would be a string, and thus I wouldn't know which function to run until runtime.
So I thought up two more solutions:
I could write up a bunch of if statements, one to run each script based on a certain parameter. I rejected this, as it's even worse than the previous design.
I could use:
os.command(sys.argv[0] scriptName.py)
which would run the script, but calling python to call python doesn't seem very elegant to me.
So does anyone have any other ideas? Thank you.
If you know the name of the function as a string and the name of module as a string, then you can do
mod = __import__(module_name)
fn = getattr(mod, fn_name)
fn()
Another possible solution is to have each of your repetitive files import the functionality from the main file
from topAndBottom import top, bottom
top()
# do middle stuff
bottom()
In addition to the several answers already posted, consider the Template Method design pattern: make an abstract class such as
class Base(object):
def top(self): ...
def bottom(self): ...
def middle(self): raise NotImplementedError
def doit(self):
self.top()
self.middle()
self.bottom()
Every pluggable module then makes a class which inherits from this Base and must override middle with the relevant code.
Perhaps not warranted for this simple case (you do still have to import the right module in order to instantiate its class and call doit on it), but still worth keeping in mind (together with its many Pythonic variations, which I have amply explained in many tech talks now available on youtube) for cases where the number or complexity of "pluggable pieces" keeps growing -- Template Method (despite its horrid name;-) is a solid, well-proven and highly scalable pattern [[sometimes a tad too rigid, but that's exactly what I address in those many tech talks -- and that problem doesn't apply to this specific use case]].
However, normal module wouldn't work here (unless I'm mistaken), because I would get the code I need to execute from the arguement, which would be a string, and thus I wouldn't know which function to run until runtime.
It will work just fine - use __import__ builtin or, if you have very complex layout, imp module to import your script. And then you can get the function by module.__dict__[funcname] for example.
Importing a module (as explained in other answers) is definitely the cleaner way to do this, but if for some reason that doesn't work, as long as you're not doing anything too weird you can use exec. It basically runs the content of another file as if it were included in the current file at the point where exec is called. It's the closest thing Python has to a source statement of the kind included in many shells. As a bare minimum, something like this should work:
exec(open(filename).read(None))
How about this?
function do_thing_one():
pass
function do_thing_two():
pass
dispatch = { "one" : do_thing_one,
"two" : do_thing_two,
}
# do something to get your string from the command line (optparse, argv, whatever)
# and put it in variable "mystring"
# do top thing
f = dispatch[mystring]
f()
# do bottom thing

What tricks do you use to avoid being tripped up by python whitespace syntax?

I'm an experienced programmer, but still a little green at python. I just got caught by an error in indentation, which cost me a significant amount of debugging time. I was wondering what experienced python programmers do to avoid creating such problems in the first place.
Here's the code (Part of a much larger program) :
class Wizvar():
def select(self):
self.selected = True
def unselect(self):
self.selected = False
value = None
The problem is that 'value = None' should be outdented one level. As it is, the variable gets clobbered every time the unselect method is called, rather than once only. I stared at this many times without seeing what was wrong.
Put all the class attributes (e.g. value) up at the top, right under the class Wizvar declaration (below the doc string, but above all method definitions). If you always place class attributes in the same place, you may not run into this particular error as often.
Notice that if you follow the above convention and had written:
class Wizvar():
value = None
def select(self):
self.selected = True
def unselect(self):
self.selected = False
then Python would have raised an IndentationError:
% test.py
File "/home/unutbu/pybin/test.py", line 7
def select(self):
^
IndentationError: unindent does not match any outer indentation level
In general: a lot of unit testing. Code reviews also help a lot.
This specific error seems like an easy one to identify since if value was supposed to be outdented once it would have been a class variable, proper unit testing would have spotted that it isn't in this case.
Tools like PyDev do a good job at finding some other common mistakes so you might want to consider those.
I don't have such problems ;) At least I have them less often than a superfluous, missing or misplaces brace or the classic:
if (foo)
bar();
baz();
in language that use braces.
That being said, certain coding styles help. For example, I always list class variables at the top of the class body, so if I accidentally the indentation, I'll get an IndentationError instead of creating an unused local variable. By the way, I've always seen it like this. Consistent indentation (I'm with PEP 8 and use 4 spaces) also helps, some people use only one space for some blocks - that's really easy to overlook.
Static code analysis (like PyLint) may point such errors out, but I don't have much experience with these. As I wrote, it just works most of the time.

Python comments: # vs. strings

Regarding the "standard" way to put comments inside Python source code:
def func():
"Func doc"
... <code>
'TODO: fix this'
#badFunc()
... <more code>
def func():
"Func doc"
... <code>
#TODO: fix this
#badFunc()
... <more code>
I prefer to write general comments as strings instead of prefixing #'s.
The official Python style guide doesn't mention using strings as comments (If I didn't miss it while reading it).
I like it that way mainly because I think the # character looks ugly with comment blocks. As far as I know these strings don't do anything.
Are there disadvantages in doing this?
Don't misuse strings (no-op statements) as comments. Docstrings, e.g. the first string in a module, class or function, are special and definitely recommended.
Note that docstrings are documentation, and documentation and comments are two different things!
Documentation is important to understand what the code does.
Comments explain how the code does it.
Documentation is read by people who use your code, comments by people who want to understand your code, e.g. to maintain it.
Using strings for commentation has the following (potential) disadvantages:
It confuses people who don't know that the string does nothing.
Comments and string literals are highlighted differently in code editors, so your style may make your code harder to read.
It might affect performance and/or memory usage (if the strings are not removed during bytecode compilation, removing comments is done on the scanner level so it's definitively cheaper)
Most important for Python programmers: It is not pythonic:
There should be one—and preferably only one—obvious way to do it.
Stick to the standards, use comments.
I think that only the first string literal in a definition (or class) is "special", i.e. gets stored by the interpreter into the defined object's (or class') docstring.
Any other string literals you place in the code will, at the worst, mean the interpreter will build the string value at run-time, and then just throw it away. This means that doing "comments" by littering the code with string constants might cost, performance-wise.
Of course, I have not benchmarked this, and also don't know the Python interpreter well enough to say for sure.
The disadvantage, of course, is that someone else reading it will find that the code strings and comment strings are interleaved, which could be confusing.

Categories

Resources