georg
georg

Reputation: 214959

style, formatting the slice operator

PEP 8 doesn't mention the slice operator. From my understanding, unlike other operators, it should not be surrounded with whitespace

spam[3:5]   # OK
spam[3 : 5] # NOT OK

Does this hold when using complex expressions, that is, which one is considered better style

     1. spam[ham(66)//3:44+eggs()]
     2. spam[ham(66) // 3: 44 + eggs()]
     3. spam[ham(66) // 3 : 44 + eggs()]
     4. something else?

Upvotes: 15

Views: 4852

Answers (3)

Shawn Chin
Shawn Chin

Reputation: 86864

As you already mentioned, PEP8 doesn't explicitly mention the slice operator in that format, but spam[3:5] is definitely more common and IMHO more readable.

If pep8 checker is anything to go by, the space before : will be flagged up

[me@home]$ pep8  <(echo "spam[3:44]")   # no warnings
[me@home]$ pep8  <(echo "spam[3 : 44]")  
/dev/fd/63:1:7: E203 whitespace before ':'

... but that's only because of it assumes : to be the operator for defining a literal dict and no space is expected before the operator. spam[3: 44] passes for that reason, but that just doesn't seem right.

On that count, I'd stick to spam[3:44].


Nested arithmetic operations are a little trickier. Of your 3 examples, only the 2nd one passes PEP8 validation:

[me@home]$ pep8 <(echo "spam[ham(66)//3:44+eggs()]")
/dev/fd/63:1:13: E225 missing whitespace around operator

[me@home]$ pep8 <(echo "spam[ham(66) // 3:44 + eggs()]")  # OK

[me@home]$ pep8 <(echo "spam[ham(66) // 3 : 44 + eggs()]")
/dev/fd/63:1:18: E203 whitespace before ':'

However, I find all of the above difficult to parse by eye at first glance.

For readability and compliance with PEP8, I'd personally go for:

 spam[(ham(66) // 3):(44 + eggs())]

Or for more complication operations:

 s_from = ham(66) // 3 
 s_to = 44 + eggs()
 spam[s_from:s_to]

Upvotes: 14

agf
agf

Reputation: 176780

I do see slicing used in PEP8:

    - Use ''.startswith() and ''.endswith() instead of string slicing to check
      for prefixes or suffixes.

      startswith() and endswith() are cleaner and less error prone.  For
      example:

        Yes: if foo.startswith('bar'):

        No:  if foo[:3] == 'bar':

I wouldn't call that definitive but it backs up your (and my) understanding:

spam[3:5]   # OK

As far as which to use in the more complex situation, I'd use #3. I don't think the no-spaces-around-the-: method looks good in that case:

spam[ham(66) / 3:44 + eggs()]   # looks like it has a time in the middle. Bad.

If you want the : to stand out more, don't sacrifice operator spacing, add extra spaces to the ::

spam[ham(66) / 3  :  44 + eggs()]   # Wow, it's easy to read!

I would not use #1 because I like operator spacing, and #2 looks too much like the dictionary key: value syntax.

I also wouldn't call it an operator. It's special syntax for constructing a slice object -- you could also do

spam[slice(3, 5)]

Upvotes: 4

Manuel Ebert
Manuel Ebert

Reputation: 8519

I agree with your first example. For the latter one: PEP 20. Readability counts. The semantically most important part of your complex slice expression is the slice operator itself, it divides the expression into two parts that should be parsed (both by the human reader and the interpreter) separately. Therefore my intuition is that the consistency with PEP 8 should be sacrificed in order to highlight the : operator, ie. by surrounding it with whitespaces as in example 3. Question is if omitting the whitespaces within the two sides of the expression to increases readability or not:

1. spam[ham(66)/3 : 44+eggs()]

vs.

2. spam[ham(66) / 3 : 44 + eggs()]

I find 1. quicker to parse.

Upvotes: 3

Related Questions