How should I break this long Python line? - python

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.

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.

What is the linter rule called when trying to left-align long list items?

Bad:
my_result = MyObject.my_method(first_parameter, second_parameter,
MyOtherObject.other_method(first, second))
Very quickly hits the line length limit, especially when there are nested calls/lists.
Have to change the indentation of line 2 onward if anything is renamed.
Have to add a bunch of indentation for every new parameter.
In general does not align with a multiple of the default indentation.
Slower to find the Nth parameter because I have to scan both vertically and horizontally.
Good:
my_result = MyObject.my_method(
first_parameter,
second_parameter,
MyOtherObject.other_method(first, second),
)
Very slightly easier to scan than the code above because the first parameter is more separated from the method name.
Easier to find the Nth parameter.
Trailing comma means the diff when adding a new parameter is just a single line.
In other words:
Only put multiple parameters on the same line if all the parameters fit on the same line as the method call.
Try to minimize the diff complexity of any change.
Is there a name for this pattern?
(The use case is that I'd like to find a linter which will check this, but first I need to know what it's called.)
In terms of lint formatters you could take a look at Black (not very customizable but the hint is in its name :-).
In the Black README your left-alignment is referred to as "vertical whitespace". In the yapf README it is controlled by CONTINUATION_ALIGN_STYLE.
I suspect each linter/formatter has its own name for that type of indentation it will do when wrapping a line and programming the rules around what makes a line "bad" and in need of reflowing can be very complicated.

Pretty-print Lisp using Python

Is there a way to pretty-print Lisp-style code string (in other words, a bunch of balanced parentheses and text within) in Python without re-inventing a wheel?
Short answer
I think a reasonable approach, if you can, is to generate Python lists or custom objects instead of strings and use the pprint module, as suggested by #saulspatz.
Long answer
The whole question look like an instance of an XY-problem. Why? because you are using Python (why not Lisp?) to manipulate strings (why not data-structures?) representing generated Lisp-style code, where Lisp-style is defined as "a bunch of parentheses and text within".
To the question "how to pretty-print?", I would thus respond "I wouldn't start from here!".
The best way to not reinvent the wheel in your case, apart from using existing wheels, is to stick to a simple output format.
But first of all all, why do you need to pretty-print? who will look at the resulting code?
Depending on the exact Lisp dialect you are using and the intended usage of the code, you could format your code very differently. Think about newlines, indentation and maximum width of your text, for example. The Common Lisp pretty-printer is particulary evolved and I doubt you want to have the same level of configurability.
If you used Lisp, a simple call to pprint would solve your problem, but you are using Python, so stick with the most reasonable output for the moment because pretty-printing is a can of worms.
If your code is intended for human readers, please:
don't put closing parenthesis on their own lines
don't vertically align open and close parenthesis
don't add spaces between opening parenthesis
This is ugly:
( * ( + 3 x )
(f
x
y
)
)
This is better:
(* (+ 3 x)
(f x y))
Or simply:
(* (+ 3 x) (f x y))
See here for more details.
But before printing, you have to parse your input string and make sure it is well-formed. Maybe you are sure it is well-formed, due to how you generate your forms, but I'd argue that the printer should ignore that and not make too many assumptions. If you passed the pretty-printer an AST represented by Python objects instead of just strings, this would be easier, as suggested in comments. You could build a data-structure or custom classes and use the pprint (python) module. That, as said above, seems to be the way to go in your case, if you can change how you generate your Lisp-style code.
With strings, you are supposed to handle any possible input and reject invalid ones.
This means checking that parenthesis and quotes are balanced (beware of escape characters), etc.
Actually, you don't need to really build an intermediate tree for printing (though it would probably help for other parts of your program), because Lisp-style code is made of forms that are easily nested and use a prefix notation: you can scan your input string from left-to-right and print as required when seeing parenthesis (open parenthesis: recurse; close parenthesis, return from recursion). When you first encounter an unescaped double-quote ", read until the next one ", ...
This, coupled with a simple printing method, could be sufficient for your needs.
I think the easiest method would be to use triple quotations. If you say:
print """
(((This is some lisp code))) """
It should work.
You can format your code any way you like within the triple quotes and it will come out the way you want it to.
Best of luck and happy coding!
I made this rudimentary pretty printer once for prettifying CLIPS, which is based on Lisp. Might help:
def clips_pprint(clips_str: str) -> str:
"""Pretty-prints a CLIPS string.
Indents a CLIPS string for easier visual confirmation during development
and verification.
Assumes the CLIPS string is valid CLIPS, i.e. braces are paired.
"""
LB = "("
RB = ")"
TAB = " " * 4
formatted_clips_str = ""
tab_count = 0
for c in clips_str:
if c == LB:
formatted_clips_str += os.linesep
for _i in range(tab_count):
formatted_clips_str += TAB
tab_count += 1
elif c == RB:
tab_count -= 1
formatted_clips_str += c
return formatted_clips_str.strip()

How to write an inline-comment in Python

Is there a method of ending single line comments in Python?
Something like
/* This is my comment */ some more code here...
No, there are no inline comments in Python.
From the documentation:
A comment starts with a hash character (#) that is not part of a
string literal, and ends at the end of the physical line. A comment
signifies the end of the logical line unless the implicit line joining
rules are invoked. Comments are ignored by the syntax; they are not
tokens.
Whitespace in Python is too important to allow any other kind of comment besides the # comment that goes to the end of the line. Take this code:
x = 1
for i in range(10):
x = x + 1
/* Print. */ print x
Because indentation determines scope, the parser has no good way of knowing the control flow. It can't reasonably eliminate the comment and then execute the code after it. (It also makes the code less readable for humans.) So no inline comments.
You can insert inline comment.
Like this
x=1; """ Comment """; x+=1; print(x);
And my python version is "3.6.9"
No, there are no inline-block comments in Python.
But you can place your comment (inline) on the right.
That's allows you to use syntax and comments on the same line.
Anyway, making comments to the left of your code turn reading difficult, so...
Ex:
x = 1 # My variable
This is pretty hideous, but you can take any text convert it into a string and then take then length of that string then multiply by zero, or turn it into any kind of invalid code.
example
history = model.fit_generator(train_generator,steps_per_epoch=8,epochs=15+0*len(", validation_data=validation_generator"), validation_steps=8,verbose=2)
I miss inline-comments mainly to temporarily comment out parameters in functions or elements in list/dicts. Like it is possible in other languages:
afunc(x, /*log=True*/, whatever=True)
alist = [1,2,3]
The only workaround, i guess, is to but them on separate lines like:
afunc(
x,
# log=True,
whatever=True,
)
alist = [
1,
# 2,
3,
]
However, as python is often used as rapid prototyping language and functions (due to no overloading) often have lots of optional parameters, this solution does not fell very "pythonic"...
Update
I meanwhile really like the "workaround" and changed my opinion about being not pythonic. Also, some formatters like Black will automatically arrange arguments or elements of an array/dict on seperate lines if you add a comment at the end. This is called Magic Trailing Comma
If you're doing something like a sed operation on code and really need to insert plain text without interfering with the rest of the line, you can try something like:
("This is my comment", some more code here...)[1]
Eg.,
my_variable = obsolete_thing + 100
could be transformed with sed -e 's/obsolete_thing/("replacement for &", 1345)[1]/' giving:
my_variable = ("replacement for obsolete_thing", 1234)[1] + 100
The octaves of a Piano are numbered and note frequencies known
(see wikipedia).
I wanted to inline comment the notes in a list of frequencies
while maintaining standard Human readable sequencing of notes.
Here is how I did it; showing a couple of octaves.
def A(octave, frequency):
"Octave numbering for twelve-tone equal temperament"
return frequency
NOTE=[
155.5635 , 164.8138, 174.6141, 184.9972, 195.9977, 207.6523,
A(3,220.0000), 233.0819, 246.9417, 261.6256, 277.1826, 293.6648,
311.1270 , 329.6276, 349.2282, 369.9944, 391.9954, 415.3047,
A(4,440.0000), 466.1638, 493.8833, 523.2511, 554.3653, 587.3295]
Of course, adjust setup.cfg and comment to satisfy pycodestyle,
pyflakes, and pylint.
I argue that maintaining columns and annotating A4 as A(4,440)
is superior to enforcing rigid style rules.
A function ignoring a formal argument is run once
at list initialization.
This is not a significant cost.
Inline commenting is possible in python.
You just have to be willing to bend style rules.

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]
))

Categories

Resources