How to break a long with statement in python - python

I have a line of code in python like this:
with long_name_function(p) as a, other_long_name_function():
and I want to break it in multiple lines, because is too long, I could use backslashes, but they are considered a bad practice. I also could use contextlib.nested, but is deprecated, is there any other alternative?

This disregards the premise of the question but I would actually recommend using backslashes in this case:
with really_really_long_name_function(p) as f1, \
other_really_really_long_name_function() as f2:
pass
As #JonClements said, you can't use brackets or commas in this case, there's no alternative so backslashes are the way to go and the code looks pretty clean IMO.

If you want to avoid backslashes, you can alias the long names:
lnf = long_name_function
olnf = other_long_name_function
with lnf(p) as a, olnf():
# ...
or you could nest the statements:
with long_name_function(p) as a:
with other_long_name_function():
pass
You do not want to use contextlib.nested(); there are several problems with it that directly led to its deprecation. Earlier context managers are not covered for problems with later context managers in the nesting, for example.

Related

Proper way of breaking line accessing dictionary

I am try to conform to pep8 directives and therefore to break the following line:
config_data_dict['foo']['bar']['foobarfoo'] \
['barfoobar'] = something_else
However I am getting the following warning now just after the ['foobarfoo'] section
whitespace before '[' pep8(E211)
How should I properly break a line as the above (assuming I cannot brake it around =)?
Parentheses seem to work:
(config_data_dict['foo']['bar']['foobarfoo']
['barfoobar']) = something_else
This also seems to be the recommended style according to PEP8:
The preferred way of wrapping long lines is by using Python's implied line continuation inside parentheses, brackets and braces. 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.
You could break inside the [...] (though I'm not really sure which would be considered more readable: breaking after the [, or before the ], or both):
config_data_dict[
'foo'][
'bar'][
'foobarfoo'][
'barfoobar'] = something_else
As a general rule, either put all the keys on the same line, or put each key on a separate line. This applies to the explicit parenthesization used in other answers, for example,
(config_data_dict
['foo']
['bar']
['foobarfoo']
['barfoobar']) = something_else
However, I would just use one or more temporary variables:
d = config_data_dict['foo']['bar']['foobarfoo']
d['barfoobar'] = something_else
You have lots of ways you can do this but here’s my opinion on the 2 “best” ways. (I say best loosely as opinion and context do apply)
Using operator.setitem. (this is almost the same as described in this answer but to me looks much more readable as it doesn’t have the leading parentheses)
setitem(config_data_dict
['foo']['bar']['foobarfoo'],
'barfoobar', something_else)
Or some prefer the reduce method with operator.getitem. (also alike this answer the reduce approach could be easier on the eyes if you’re getting REALLY deeply nested but I prefer the later as it’s not adding yet another somewhat unnecessary function into the mix)
path = ['foo','bar','foobarfoo']
reduce(getitem, path, config_data_dict)['barfoobar'] = something_else
Or to allow for more nice indenting use setitem here too
setitem(reduce(getitem, path, config_data_dict),
'barfoobar', something_else)
All of that being said, you could use shorter variable names, for instance config_data_dict really doesn’t need the dict at the end. It does make the variable more descriptive although I’m sure most should easily be able to discern that it’s a dict by how you’re accessing it.

How should I break this long Python line?

I'm formatting my code that is going to be included in the appendices of a report, so respecting 80 characters lines is more than a PEP8 fanatism, since if the lines are too long they continue past the width of the paper.
Usually, breaking long lines using PEP8 recommendations and some logic, things are pretty easy, but I encountered this 90 characters long line, which is indented 3 times :
valleys.append(data.index(min(data[frontieres[f*2+1]:frontieres[f*2+2]])))
How should I break it, without changing variables name if possible?
I don't like the idea I advice you that, because good practise would be to rewrite that line into something more readable. However, if you have to for grater good format existing code into scientific report, then here you have my suggestion:
valleys.append(
data.index(
min(
data[frontieres[f*2+1]:frontieres[f*2+2]]
)))
Python allows to split lines between brackets without any additional trickery.
More correct way would be:
valleys.append(
data.index(
min(
data[frontieres[f*2+1]:frontieres[f*2+2]]
)
)
)
In fact you can split your indexes this way as well.
There are two ways to break the line.
Using \:
You can insert it anywhere (even between variables) and take that down from there:
valleys.append(data.index(min(data[frontieres[f*2+1]\
:frontieres[f*2+2]])))
Breaking from (:
Any function can take argument on the other line
valleys.append(data.index(min(
data[frontieres[f*2+1]:frontieres[f*2+2]]
)))
I prefer the later one for the sake of readability.
Just use variables:
some_data = data[frontieres[f*2+1]:frontieres[f*2+2]]
min_some_data = min(some_data)
data_index = data.index(min_some_datan)
valleys.append(data_index)
data_range = data[frontieres[f*2+1]:frontieres[f*2+2]]
data_min = min(data_range)
index_min = data.index(data_min)
valleys.append(index_min)
Obviously you may inline any of introduces variables.

Python - How to style this line of code?

First of, I'm not sure if SO is the right place for this question, so feel free to move it somewhere more appropriate if necessary.
cmd_folder = os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( inspect.currentframe() ))[0]))
I have this line of code. The Python PEP 8 document recommends limiting lines to 79 characters to preserve readability on smaller screens.
What is the most elegant way to style this line of code to fit the PEP recommendations?
cmd_folder = os.path.realpath(os.path.abspath(os.path.split
(inspect.getfile
( inspect.currentframe() ))[0]))
Is this the most appropriate way for is there a better one that I have not thought of?
I would say in the case of your example code, it would be more appropriate to split them up into individual operation, as opposed to making the code harder to read.
aFile = inspect.getfile(inspect.currentframe())
cmd_folder = os.path.realpath(os.path.abspath(os.path.split(aFile)[0]))
It should not be such a chore to trace the start and close of all those parenthesis to figure out what is happening with each temp variable. Variable names can help with clarity, by naming the intention/type of the results.
If it is two, maybe 3, nested calls I might do the act of newlines in one call, but definitely not when you have a ton of parenthesis, and list indexing squished in between. But normally I am only more inclined to do that with chained calls like foo.bar().biz().baz() since it flows left to right.
Always assume some poor random developer will have to read your code tomorrow.
I am in general with the answer provided by jdi (split into several expressions). But I would like to show another aspect of this issue.
In general, if just trying to properly break and indent this line, you should also follow PEP8 rules on indentation:
Use 4 spaces per indentation level.
For really old code that you don't want to mess up, you can continue to use 8-space tabs.
Continuation lines should align wrapped elements either vertically using Python's implicit line joining inside parentheses, brackets and braces, or using a hanging indent. When using a hanging indent the following considerations should be applied; there should be no arguments on the first line and further indentation should be used to clearly distinguish itself as a continuation line.
[several examples follow]
So in your case it could look like this:
#---------------------------------------------------------79th-column-mark--->|
cmd_folder = os.path.realpath(
os.path.abspath(os.path.split(inspect.getfile(inspect.currentframe()))[0]))
But as I mentioned at the beginning, and as PEP20 (The Zen of Python) mentions:
Flat is better than nested.
Sparse is better than dense.
Readability counts.
thus you should definitely split your code into few expressions, as jdi notes.
I tend to do it like this:
cmd_folder = os.path.realpath(os.path.abspath(os.path.split(
inspect.getfile(inspect.currentframe()))[0]))
Open-parens at the end of the first line, and indention on continuation lines. Ultimately it boils down to what you think is more aesthetic.
There's also no shame in doing part of the computation and saving the result in a variable, like this:
f = inspect.getfile(inspect.currentframe())
cmd_folder = os.path.realpath(os.path.abspath(os.path.split(f)[0]))
If you really insist on keeping it one expression, I'd go with an "extreme" simply because it actually looks nice:
cmd_folder = os.path.realpath(
os.path.abspath(
os.path.split(
inspect.getfile(
inspect.currentframe()
))[0]
))

IronPython: Is there an alternative to significant whitespace?

For rapidly changing business rules, I'm storing IronPython fragments in XML files. So far this has been working out well, but I'm starting to get to the point where I need more that just one-line expressions.
The problem is that XML and significant whilespace don't play well together. Before I abandon it for another language, I would like to know if IronPython has an alternative syntax.
IronPython doesn't have an alternate syntax. It's an implementation of Python, and Python uses significant indentation (all languages use significant whitespace, not sure why we talk about whitespace when it's only indentation that's unusual in the Python case).
>>> from __future__ import braces
File "<stdin>", line 1
from __future__ import braces
^
SyntaxError: not a chance
All I want is something that will let my users write code like
Ummm... Don't do this. You don't actually want this. In the long run, this will cause endless little issues because you're trying to force too much content into an attribute.
Do this.
<Rule Name="Markup">
<Formula>(Account.PricingLevel + 1) * .05</Formula>
</Rule>
You should try not to have significant, meaningful stuff in attributes. As a general XML design policy, you should use tags and save attributes for names and ID's and the like. When you look at well-done XSD's and DTD's, you see that attributes are used minimally.
Having the body of the rule in a separate tag (not an attribute) saves much pain. And it allows a tool to provide correct CDATA sections. Use a tool like Altova's XML Spy to assure that your tags have space preserved properly.
I think you can set the xml:space="preserve" attribute or use a <![CDATA[ to avoid other issues, with for example quotes and greater equal signs.
Apart from the already mentioned CDATA sections, there's pindent.py which can, among others, fix broken indentation based on comments a la #end if - to quote the linked file:
When called as "pindent -r" it assumes its input is a Python program with block-closing comments but with its indentation messed up, and outputs a properly indented version.
...
A "block-closing comment" is a comment of the form '# end <keyword>' where is the keyword that opened the block. If the opening keyword is 'def' or 'class', the function or class name may be repeated in the block-closing comment as well. Here is an example of a program fully augmented with block-closing comments:
def foobar(a, b):
if a == b:
a = a+1
elif a < b:
b = b-1
if b > a: a = a-1
# end if
else:
print 'oops!'
# end if
# end def foobar
It's bundeled with CPython, but if IronPython doesn't have it, just grab it from the repository.

Problem with list of strings in python

Why on Earth doesn't the interpreter raise SyntaxError everytime I do this:
my_abc = ['a',
'b',
'c'
'd',]
I just wanted to add 'c' to the list of strings, and forgot to append the comma. I would expect this to cause some kind of error, as it's cleary incorrect.
Instead, what I got:
>>> my_abc
['a', 'b', 'cd']
And this is never what I want.
Why is it automatically concatenated? I can hardly count how many times I got bitten by this behavior.
Is there anything I can do with it?
Just to clarify*: I don't actually mind auto-concatenation, my problem has to do ONLY with lists of strings, because they often do much more than just carry text, they're used to control flow, to pass field names and many other things.
Is called "Implicit String Concatenation" and a PEP that proposed its removal was rejected: http://www.python.org/dev/peps/pep-3126/
It's by design. It allows, for example, writing long string literals in several lines without using +.
As others said, it's by design.
Why is it so ? Mostly for historical reasons : C also does it.
In some cases it's handy because it reduce syntaxic noise and avoid adding unwanted spaces (inline SQL queries, complexes regexpes, etc).
What you can do about it ? Not much, but if it really happens often for you, try one of the following tricks.
indent your list with coma at the beginning of the line. It's weird, but if you do so the missing comas become obvious.
assign strings to variables and use variables list whenever you can (and it's often a good idea for other reasons, like avoiding duplicate strings).
split your list: for list of words you can put the whole list inside only one string and split it like below. For more than 5 elements it's also shorter.
'a b c d e'.split(' ').
Because two string literals side-by-side, delimited by whitespace, are concatenated. Since the strings are within a list, they are 'side-by-side'.
See: http://docs.python.org/reference/lexical_analysis.html#string-literal-concatenation
Because often people want to do something like this:
line = ("Here's a very long line, with no line breaks,"
" which should be displayed to the user (perhaps"
" as an error message or question box).")
It's easier to write this without having to manually concatenate strings. C, C++, and (I believe) Java and C# also have this behavior.

Categories

Resources