Vladimir Zolotykh
Vladimir Zolotykh

Reputation: 529

Slices cross strings boundaries?

Please explain:

>>> [line.rstrip() for line in open('foo')]
[',' 'hello text file6', '', '', '', 'goodby text file7', '', 'bye', '']

>>> with open('foo') as f: [line.rstrip() for line in f if line.rstrip()[-1:].isdigit()]
... 
['hello text file6', 'goodby text file7']

[-1:] ignores empty strings while list comprehension above has them.So far I'm accustomed that slices work only within one single string. [-1:] slice seems crossed the boundaries of many strings.

Upvotes: 0

Views: 71

Answers (2)

cwallenpoole
cwallenpoole

Reputation: 82058

Breaking things down:

  • Slices ([::] syntax) will address all possible values in the range. That means all of these are true.

    • ['cat'][0:1] == ['cat']
    • ['cat'][1:2] == []
    • ['cat'][-1:2] == ['cat']
    • ['cat'][-10000:] == ['cat']
  • Accessing something by index on the other hand ([x] will fail if the index does not exist. That means these fail:

    • ['cat'][1]
    • ['cat'][-2]
  • Your comprehension means "take all lines that meet the following:

    • If you rstrip them they are not empty (remember an empty string is NOT a digit)
    • The substring representing the last character is a digit

You might want this instead:

 [line.rstrip() for line in f if not line.rstrip() or line.rstrip()[-1].isdigit()]

That will include your blank lines.


As a clarification, you are at no point getting values from outside of the string ''[-123:] will pass. ''[-123] (no colon) will fail.

Upvotes: 1

Norrius
Norrius

Reputation: 7920

There is no implicit concatenation, slices don't do that. Consider this example:

lines = ['', 'abc', 'xyz123']

for line in lines:
    print repr(line.rstrip()[-1:]),
    print line.rstrip()[-1:].isdigit()

Output:

'' False
'c' False
'3' True

The unexpected part might be how it handles the empty string. Any slice of the empty string will be an empty string because an out-of-bounds slice is an empty sequence. Then, str.isdigit is defined to return False on empty strings, so these are filtered out from your list.

Upvotes: 1

Related Questions