I'm attempting to keep my code to 80 chars or less nowadays as I think it looks more aesthetically pleasing, for the most part. Sometimes, though, the code ends up looking worse if I have to put line breaks in weird places.
One thing I haven't figured out how to handle very nicely yet is long strings. For example:
#0.........1........2........3........4.........5.........6.........7.........8xxxxxxxxx9xxxxxx
def foo():
if conditional():
logger.info("<Conditional's meaning> happened, so we're not setting up the interface.")
return
#.....
It's over! Putting it on the next line won't help either:
#0.........1........2........3........4.........5.........6.........7.........8xxxxxxxxx9xxxxxx
def foo():
if conditional():
logger.info(
"<Conditional's meaning> happened, so we're not setting up the interface.")
return
#.....
I could use line breaks but that looks awful:
#0.........1........2........3........4.........5.........6.........7.........8
def foo():
if conditional():
logger.info(
"<Conditional's meaning> happened, so we're not setting \
up the interface.")
return
#.....
What to do? Shortening the string is one option but I don't want the readability of my messages to be affected by something as arbitrary as how many indentation levels the code happened to have at that point.
You can split the string into two:
def foo():
if conditional():
logger.info("<Conditional's meaning> happened, so we're not "
"setting up the interface.")
Multiple consecutive strings within the same expression are automatically concatenated into one, at compile time:
>>> def foo():
... if conditional():
... logger.info("<Conditional's meaning> happened, so we're not "
... "setting up the interface.")
...
>>> import dis
>>> dis.dis(foo)
2 0 LOAD_GLOBAL 0 (conditional)
3 CALL_FUNCTION 0
6 POP_JUMP_IF_FALSE 25
3 9 LOAD_GLOBAL 1 (logger)
12 LOAD_ATTR 2 (info)
15 LOAD_CONST 1 ("<Conditional's meaning> happened, so we're not setting up the interface.")
18 CALL_FUNCTION 1
21 POP_TOP
22 JUMP_FORWARD 0 (to 25)
>> 25 LOAD_CONST 0 (None)
28 RETURN_VALUE
Note the LOAD_CONST
for line 3, the bytecode for the function contains one string, already concatenated.
If you were to add a +
to the expression, two separate constants are created:
>>> def foo():
... if conditional():
... logger.info("<Conditional's meaning> happened, so we're not " +
... "setting up the interface.")
...
>>> dis.dis(foo)
2 0 LOAD_GLOBAL 0 (conditional)
3 CALL_FUNCTION 0
6 POP_JUMP_IF_FALSE 29
3 9 LOAD_GLOBAL 1 (logger)
12 LOAD_ATTR 2 (info)
15 LOAD_CONST 1 ("<Conditional's meaning> happened, so we're not ")
4 18 LOAD_CONST 2 ('setting up the interface.')
21 BINARY_ADD
22 CALL_FUNCTION 1
25 POP_TOP
26 JUMP_FORWARD 0 (to 29)
>> 29 LOAD_CONST 0 (None)
32 RETURN_VALUE
Python does fold binary operations on constants at compile time (so +
, *
, -
etc.), in the peephole optimizations for the byte compiler. So for certain string concatenations the compiler may also replace +
string concatenation of constants with the concatenated result. See peephole.c
, for sequences (including strings) this optimization is only applied if the result is limited to 20 items (characters) or fewer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With