Proper way of breaking line accessing dictionary - python

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.

Related

What Python syntax rule allows a space between a period and method call? [duplicate]

Does anyone know why python allows you to put an unlimited amount of spaces between an object and the name of the method being called the "." ?
Here are some examples:
>>> x = []
>>> x. insert(0, 'hi')
>>> print x
['hi']
Another example:
>>> d = {}
>>> d ['hi'] = 'there'
>>> print d
{'hi': 'there'}
It is the same for classes as well.
>>> myClass = type('hi', (), {'there': 'hello'})
>>> myClass. there
'hello'
I am using python 2.7
I tried doing some google searches and looking at the python source code, but I cannot find any reason why this is allowed.
The . acts like an operator. You can do obj . attr the same way you can do this + that or this * that or the like. The language reference says:
Except at the beginning of a logical line or in string literals, the whitespace characters space, tab and formfeed can be used interchangeably to separate tokens.
Because this rule is so general, I would assume the code that does it is very early in the parsing process. It's nothing specific to .. It just ignores all whitespace everywhere except at the beginning of the line or inside a string.
An explanation of how/why it works this way had been given elsewhere, but no mention is made regarding any benefits for doing so.
An interesting benefit of this might occur when methods return an instance of the class. For example, many of the methods on a string return an instance of a string. Therefore, you can string multiple method calls together. Like this:
escaped_html = text.replace('&', '&').replace('<', '<').replace('>'. '>')
However, sometimes, the arguments passed in might be rather long and it would be nice to wrap the calls on multiple lines. Perhaps like this:
fooinstance \
.bar('a really long argument is passed in here') \
.baz('and another long argument is passed in here')
Of course, the newline escapes \ are needed for that to work, which is not ideal. Nevertheless, that is a potentially useful reason for the feature. In fact, in some other languages (where all/most whitespace is insignificant), is is quite common to see code formatted that way.
For comparison, in Python we would generally see this instead:
fooinstance = fooinstance.bar('a really long argument is passed in here')
fooinstance = fooinstance.baz('and another long argument is passed in here')
Each has their place.
Because it would be obnoxious to disallow it. The initial stage of an interpreter or compiler is a tokenizer (aka "lexer"), which chunks a program's flat text into meaningful units. In modern programming languages (C and beyond, for discussion's sake), in order to be nice to programmers, whitespace between tokens is generally ignored. In Python, of course, whitespace at the beginning of lines is very significant; but elsewhere, within lines and multiline expressions, it isn't. [Yes, these are very broad statements, but modulo corner-case counterexamples, they're true.]
Besides, sometimes it's desirable -- e.g.:
obj.deeply.\
nested.\
chain.of.\
attributes
Backslash, the continuation character, wipes out newlines, but the whitespace preceding e.g. nested remains, so it immediately follows the . after deeply.
In expressions with deeper nesting, a little extra whitespace can yield a big gain in readability:
Compare:
x = your_map[my_func(some_big_expr[17])]
vs
x = your_map[ my_func( some_big_expr[17]) ]
Caveats: If your employer, client, team, or professor has style rules or guidelines, you should adhere to them. The second example above doesn't comply with Python's style guide, PEP8, which most Python shops adopt or adapt. But that document is a collection of guidelines, not religious or civil edicts.

Why does python allow spaces between an object and the method name after the "."

Does anyone know why python allows you to put an unlimited amount of spaces between an object and the name of the method being called the "." ?
Here are some examples:
>>> x = []
>>> x. insert(0, 'hi')
>>> print x
['hi']
Another example:
>>> d = {}
>>> d ['hi'] = 'there'
>>> print d
{'hi': 'there'}
It is the same for classes as well.
>>> myClass = type('hi', (), {'there': 'hello'})
>>> myClass. there
'hello'
I am using python 2.7
I tried doing some google searches and looking at the python source code, but I cannot find any reason why this is allowed.
The . acts like an operator. You can do obj . attr the same way you can do this + that or this * that or the like. The language reference says:
Except at the beginning of a logical line or in string literals, the whitespace characters space, tab and formfeed can be used interchangeably to separate tokens.
Because this rule is so general, I would assume the code that does it is very early in the parsing process. It's nothing specific to .. It just ignores all whitespace everywhere except at the beginning of the line or inside a string.
An explanation of how/why it works this way had been given elsewhere, but no mention is made regarding any benefits for doing so.
An interesting benefit of this might occur when methods return an instance of the class. For example, many of the methods on a string return an instance of a string. Therefore, you can string multiple method calls together. Like this:
escaped_html = text.replace('&', '&').replace('<', '<').replace('>'. '>')
However, sometimes, the arguments passed in might be rather long and it would be nice to wrap the calls on multiple lines. Perhaps like this:
fooinstance \
.bar('a really long argument is passed in here') \
.baz('and another long argument is passed in here')
Of course, the newline escapes \ are needed for that to work, which is not ideal. Nevertheless, that is a potentially useful reason for the feature. In fact, in some other languages (where all/most whitespace is insignificant), is is quite common to see code formatted that way.
For comparison, in Python we would generally see this instead:
fooinstance = fooinstance.bar('a really long argument is passed in here')
fooinstance = fooinstance.baz('and another long argument is passed in here')
Each has their place.
Because it would be obnoxious to disallow it. The initial stage of an interpreter or compiler is a tokenizer (aka "lexer"), which chunks a program's flat text into meaningful units. In modern programming languages (C and beyond, for discussion's sake), in order to be nice to programmers, whitespace between tokens is generally ignored. In Python, of course, whitespace at the beginning of lines is very significant; but elsewhere, within lines and multiline expressions, it isn't. [Yes, these are very broad statements, but modulo corner-case counterexamples, they're true.]
Besides, sometimes it's desirable -- e.g.:
obj.deeply.\
nested.\
chain.of.\
attributes
Backslash, the continuation character, wipes out newlines, but the whitespace preceding e.g. nested remains, so it immediately follows the . after deeply.
In expressions with deeper nesting, a little extra whitespace can yield a big gain in readability:
Compare:
x = your_map[my_func(some_big_expr[17])]
vs
x = your_map[ my_func( some_big_expr[17]) ]
Caveats: If your employer, client, team, or professor has style rules or guidelines, you should adhere to them. The second example above doesn't comply with Python's style guide, PEP8, which most Python shops adopt or adapt. But that document is a collection of guidelines, not religious or civil edicts.

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.

How to break a long with statement in 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.

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