Skip to content

Commit 7f70007

Browse files
Master slice in python (#26)
* [ADD] Blog post discussing the reasons for returning an empty list instead of raising an IndexError from slice function.
1 parent 7fb08dd commit 7f70007

File tree

3 files changed

+200
-38
lines changed

3 files changed

+200
-38
lines changed

Gemfile.lock

Lines changed: 45 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,34 @@
11
GEM
22
remote: https://rubygems.org/
33
specs:
4-
activesupport (5.1.0)
4+
activesupport (5.2.1)
55
concurrent-ruby (~> 1.0, >= 1.0.2)
6-
i18n (~> 0.7)
6+
i18n (>= 0.7, < 2)
77
minitest (~> 5.1)
88
tzinfo (~> 1.1)
9-
addressable (2.5.0)
10-
public_suffix (~> 2.0, >= 2.0.2)
9+
addressable (2.5.2)
10+
public_suffix (>= 2.0.2, < 4.0)
1111
colorator (1.1.0)
12-
colored (1.2)
12+
colorize (0.8.1)
1313
concurrent-ruby (1.0.5)
1414
cssminify2 (2.0.1)
15-
ethon (0.10.1)
15+
ethon (0.11.0)
1616
ffi (>= 1.3.0)
1717
execjs (2.7.0)
18-
ffi (1.9.14)
18+
ffi (1.9.25)
1919
forwardable-extended (2.6.0)
20-
html-proofer (3.6.0)
20+
html-proofer (3.9.2)
2121
activesupport (>= 4.2, < 6.0)
2222
addressable (~> 2.3)
23-
colored (~> 1.2)
23+
colorize (~> 0.8)
2424
mercenary (~> 0.3.2)
25-
nokogiri (~> 1.5)
25+
nokogiri (~> 1.8.1)
2626
parallel (~> 1.3)
27-
typhoeus (~> 0.7)
27+
typhoeus (~> 1.3)
2828
yell (~> 2.0)
29-
htmlcompressor (0.3.1)
30-
i18n (0.8.1)
29+
htmlcompressor (0.4.0)
30+
i18n (1.1.0)
31+
concurrent-ruby (~> 1.0)
3132
jekyll (3.3.1)
3233
addressable (~> 2.4)
3334
colorator (~> 1.0)
@@ -39,48 +40,54 @@ GEM
3940
pathutil (~> 0.9)
4041
rouge (~> 1.7)
4142
safe_yaml (~> 1.0)
42-
jekyll-feed (0.8.0)
43+
jekyll-feed (0.11.0)
4344
jekyll (~> 3.3)
4445
jekyll-minifier (0.1.2)
4546
cssminify2 (~> 2.0)
4647
htmlcompressor (~> 0.3)
4748
jekyll (~> 3.0)
4849
uglifier (~> 2.7)
49-
jekyll-sass-converter (1.5.0)
50+
jekyll-sass-converter (1.5.2)
5051
sass (~> 3.4)
51-
jekyll-seo-tag (2.2.3)
52+
jekyll-seo-tag (2.5.0)
5253
jekyll (~> 3.3)
53-
jekyll-sitemap (1.1.1)
54+
jekyll-sitemap (1.2.0)
5455
jekyll (~> 3.3)
55-
jekyll-watch (1.5.0)
56-
listen (~> 3.0, < 3.1)
56+
jekyll-watch (1.5.1)
57+
listen (~> 3.0)
5758
json (2.1.0)
58-
kramdown (1.13.1)
59+
kramdown (1.17.0)
5960
liquid (3.0.6)
60-
listen (3.0.8)
61+
listen (3.1.5)
6162
rb-fsevent (~> 0.9, >= 0.9.4)
6263
rb-inotify (~> 0.9, >= 0.9.7)
64+
ruby_dep (~> 1.2)
6365
mercenary (0.3.6)
64-
mini_portile2 (2.1.0)
65-
minima (2.1.0)
66+
mini_portile2 (2.3.0)
67+
minima (2.1.1)
6668
jekyll (~> 3.3)
67-
minitest (5.10.1)
68-
nokogiri (1.7.1)
69-
mini_portile2 (~> 2.1.0)
70-
parallel (1.11.2)
71-
pathutil (0.14.0)
69+
minitest (5.11.3)
70+
nokogiri (1.8.4)
71+
mini_portile2 (~> 2.3.0)
72+
parallel (1.12.1)
73+
pathutil (0.16.1)
7274
forwardable-extended (~> 2.6)
73-
public_suffix (2.0.4)
74-
rb-fsevent (0.9.8)
75-
rb-inotify (0.9.7)
76-
ffi (>= 0.5.0)
75+
public_suffix (3.0.3)
76+
rb-fsevent (0.10.3)
77+
rb-inotify (0.9.10)
78+
ffi (>= 0.5.0, < 2)
7779
rouge (1.11.1)
80+
ruby_dep (1.5.0)
7881
safe_yaml (1.0.4)
79-
sass (3.4.23)
82+
sass (3.6.0)
83+
sass-listen (~> 4.0.0)
84+
sass-listen (4.0.0)
85+
rb-fsevent (~> 0.9, >= 0.9.4)
86+
rb-inotify (~> 0.9, >= 0.9.7)
8087
thread_safe (0.3.6)
81-
typhoeus (0.8.0)
82-
ethon (>= 0.8.0)
83-
tzinfo (1.2.3)
88+
typhoeus (1.3.0)
89+
ethon (>= 0.9.0)
90+
tzinfo (1.2.5)
8491
thread_safe (~> 0.1)
8592
uglifier (2.7.2)
8693
execjs (>= 0.3.0)
@@ -100,7 +107,7 @@ DEPENDENCIES
100107
minima (~> 2.0)
101108

102109
RUBY VERSION
103-
ruby 2.3.1p112
110+
ruby 2.3.7p456
104111

105112
BUNDLED WITH
106-
1.13.7
113+
1.16.5
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
---
2+
layout: post
3+
title: "Analyzing the behaviour of Python function slice"
4+
date: "2018-09-29 10:17:46 +0530"
5+
tag:
6+
- python
7+
- slice
8+
- python trick questions
9+
---
10+
11+
12+
![Title Image](/assets/images/python_slice_function/title_image.jpg)
13+
14+
Last Friday, I was sitting in one of the good coffee shops in Bangalore with my
15+
friend. Coffee and discussion is the best combination to release stress. It was
16+
looking like a perfect Friday evening until my friend was struck by an idea of
17+
asking me a question.
18+
19+
“Let me conduct a quiz.” he said, interrupting our conversation.
20+
21+
“A quiz? Quiz on what?”, I asked.
22+
23+
“On programming”, he said
24+
25+
“What is the level of difficulty then?” I said.
26+
27+
Asking the level of difficulty is important. I never invest my efforts in
28+
solving something easy. If he had said easy, I would have ignored to answer, but
29+
he said “It is a bit difficult, but not that difficult. I gave a wrong answer to
30+
this question in my last interview.”
31+
32+
There was no reason to go back from here. Taking some deep breaths I said,
33+
“Please go ahead.”
34+
35+
He stood up, took a tissue paper from a nearby counter and scratched below code
36+
on it. [^1] And he asked me by pointing towards that code, “What will be the output
37+
of this code?”
38+
39+
```python
40+
def my_function():
41+
l = [0, 1, 2]
42+
print(l[30:])
43+
44+
my_function()
45+
```
46+
47+
Now it was my turn to give the answer. I looked at the code and tried parsing it
48+
in my head --- line by line. In my mind, I observed the first line. It was
49+
defining a function which seems to be correct. I moved my eyes to the next line.
50+
It was defining a variable `l` of type `list` and assigning values ranging from
51+
`0` to `2`. Even this wasn’t looking problematic. So I forwarded to the next
52+
line where it was trying to print that variable `l` by slicing it from starting
53+
value `30` to the infinity.
54+
55+
“Well, the start value is `30` which is greater than the length of the list.
56+
This should raise an `IndexError`” I said in my mind. I was about to speak an
57+
answer, but suddenly Devil of me flashed.
58+
59+
“It is less than [a banana job][4] my dear,” the Devil said to me, “You should
60+
take a little advantage of this opportunity my boy.”
61+
62+
Because things were looking in my control, I shook my hands with the Devil.
63+
64+
I said to my friend, “How about betting for some real values?”
65+
66+
Going closer I spoke, “If I answer correctly, You will pay the bill and If I am
67+
wrong, This will be a treat from my side.”
68+
69+
He thought for a while and nodded. Now it was my turn to unveil the cards.
70+
71+
I said in a strong voice, “It will raise an `IndexError`.” And shifted my focus
72+
towards the chocolate.
73+
74+
He starred my face for a second and spoke, “Okay. Are you sure about this?”.
75+
76+
This was the hint he gave. I should have taken another shot here. What happens
77+
next become a lesson for me.
78+
79+
I said with a flat face, “Yes I am.”
80+
81+
With my answer, he instantly opened his backpack, took his Laptop out and typed
82+
the code which he wrote on that tissue.
83+
84+
When I stopped hearing a sound of typing I yelled, “So did I win?”
85+
86+
He turned his laptop towards me and exclaimed, “Not at all!”
87+
88+
When I focused on the screen, the interpreter was printing `[]`. Damn! I lost
89+
the bet. Why the hell `slice` is returning an empty `list` even when we are
90+
trying to slice it with a value which is greater than the length of it! It was
91+
surely looking unpythonic behavior. I paid whatever the bill amount was. Entire
92+
evening this question was all roaming my mind. After coming home, I decided to
93+
justify reasons for returning an empty list instead of raising an `IndexError`
94+
from a `slice`.
95+
96+
Below are a few reasons justifying such behavior of slice function. I am sharing
97+
this with you so that you don’t lose a bet with your friend :) For those who
98+
haven’t used slice anytime in their life, I advise to read [this][1] tutorial.
99+
Reading [this][2] guide for understanding how a slice function converts the
100+
input values. Especially rule number 3 and 4 referenced there.
101+
102+
* **Reason number one:**
103+
104+
Python lists are more commonly used in iterations. Consider below example:
105+
106+
```python
107+
numbers = [0, 1, 2, 3]
108+
for number in numbers[30:]:
109+
print(number)
110+
```
111+
112+
If `slice` was raising an `IndexError`, then the above code would have to
113+
written like this
114+
115+
written like like this
116+
117+
```python
118+
numbers = [0, 1, 2, 3]
119+
try:
120+
for number in numbers[30:]:
121+
print(numbers)
122+
except IndexError:
123+
pass
124+
```
125+
126+
Or in another way below is also looking reasonable
127+
128+
```python
129+
numbers = [0, 1, 2, 3]
130+
start = 30
131+
if start < len(numbers):
132+
for number in numbers[start:]:
133+
print(number)
134+
```
135+
136+
Both the approaches are looking little lengthy by an obvious reason. And that
137+
reason is to prevent executing loop if there are no elements in it. When we
138+
observe the behavior of `slice` called at `for in`, it makes sense to return
139+
an empty list instead of raising an `IndexError`.
140+
141+
I am not able to find further reasons to return an empty list instead of raising
142+
the `IndexError`. But I am sure, there will be. If you know any other potential
143+
reasons for such behavior of `slice`, please drop me a mail at **jaysinhp** at
144+
**gmail** dot **com** or contact me over Twitter [@jaysinhp][3]. I will update
145+
the reasons at this post and give credits to you. Thanks for reading this post.
146+
147+
148+
###### Proofreaders: [Geoffrey Sneddon](https://github.com/gsnedders), [Elijah](https://mailto:[email protected]), [Mahendra Yadav](mailto:[email protected]), [Dhavan Vaidya](http://codingquark.com/),
149+
150+
[1]: https://docs.python.org/3.7/tutorial/introduction.html#lists
151+
[2]: https://docs.python.org/3.7/library/stdtypes.html#sequence-types-list-tuple-range
152+
[3]: https://twitter.com/jaysinhp
153+
[4]: http://catb.org/jargon/html/O/one-banana-problem.html
154+
155+
[^1]: I am using the word "Scratch" because that tissue paper was such a thin that writing by a ballpen torn it.
Loading

0 commit comments

Comments
 (0)