You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Python, being a beautifully designed high-level and interpreter-based programming language, provides us with many features for the programmer's comfort. But sometimes, the outcomes of a Python snippet may not seem obvious to a regular user at first sight.
9
10
@@ -13,7 +14,7 @@ While some of the examples you see below may not be WTFs in the truest sense, bu
13
14
14
15
If you're an experienced Python programmer, you can take it as a challenge to get most of them right in first attempt. You may be already familiar with some of these examples, and I might be able to revive sweet old memories of yours being bitten by these gotchas :sweat_smile:
15
16
16
-
If you're a returning reader, you can learn about the new modifications [here](https://github.com/satwikkansal/wtfpython/releases/).
17
+
PS: If you're a returning reader, you can learn about the new modifications [here](https://github.com/satwikkansal/wtfpython/releases/).
17
18
18
19
So, here we go...
19
20
@@ -77,7 +78,7 @@ So, here we go...
77
78
-[▶ Yes, it exists!](#-yes-it-exists)
78
79
-[▶ Inpinity *](#-inpinity-)
79
80
-[▶ Mangling time! *](#-mangling-time-)
80
-
-[Section: Miscallaneous](#section-miscallaneous)
81
+
-[Section: Miscellaneous](#section-miscellaneous)
81
82
-[▶ `+=` is faster](#--is-faster)
82
83
-[▶ Let's make a giant string!](#-lets-make-a-giant-string)
83
84
-[▶ Explicit typecast of strings](#-explicit-typecast-of-strings)
@@ -97,22 +98,22 @@ All the examples are structured like below:
97
98
98
99
> ### ▶ Some fancy Title *
99
100
> The asterisk at the end of the title indicates the example was not present in the first release and has been recently added.
100
-
>
101
+
>
101
102
> ```py
102
103
># Setting up the code.
103
104
># Preparation for the magic...
104
105
>```
105
-
>
106
+
>
106
107
>**Output (Python version):**
107
108
>```py
108
109
>>>> triggering_statement
109
110
> Probably unexpected output
110
111
>```
111
112
> (Optional): One line describing the unexpected output.
112
-
>
113
-
>
113
+
>
114
+
>
114
115
>#### 💡 Explanation:
115
-
>
116
+
>
116
117
>* Brief explanation of what's happening and why is it happening.
117
118
>```py
118
119
> Setting up examples for clarification (if necessary)
@@ -200,10 +201,10 @@ Makes sense, right?
200
201
+ In the snippets above, strings are implicitly interned. The decision of when to implicitly intern a string is implementation dependent. There are some facts that can be used to guess if a string will be interned ornot:
201
202
* All length 0and length 1 strings are interned.
202
203
* Strings are interned at compile time (`'wtf'` will be interned but `''.join(['w', 't', 'f']` will not be interned)
203
-
* Strings that are not composed of ASCII letters, digits or underscores, are not interned. This explains why `'wtf!'` was not interned due to `!`.
204
+
* Strings that are not composed of ASCII letters, digits or underscores, are not interned. This explains why `'wtf!'` was not interned due to `!`. Cpython implementation of this rule can be found [here](https://github.com/python/cpython/blob/3.6/Objects/codeobject.c#L19)
+ When `a`and`b` are set to `"wtf!"`in the same line, the Python interpreter creates a new object, then references the second variable at the same time. If you do it on separate lines, it doesn't "know" that there's already `wtf!`as an object (because `"wtf!"`isnot implicitly interned as per the facts mentioned above). It's a compiler optimization and specifically applies to the interactive environment.
206
-
+ Constant folding is a technique for [peephole optimization](https://en.wikipedia.org/wiki/Peephole_optimization) in Python. This means the expression `'a'*20`is replaced by `'aaaaaaaaaaaaaaaaaaaa'` during compilation to reduce few clock cycles during runtime. But since the python bytecode generated after compilation is stored in`.pyc` files, the strings greater than length of 20 are discarded for peephole optimization (Why? Imagine the size of `.pyc`file generated as a result of the expression `'a'*10**10`)
207
+
+ Constant folding is a technique for [peephole optimization](https://en.wikipedia.org/wiki/Peephole_optimization) in Python. This means the expression `'a'*20`is replaced by `'aaaaaaaaaaaaaaaaaaaa'` during compilation to reduce few clock cycles during runtime. Constant folding only occurs forstrings having length less than 20. (Why? Imagine the size of `.pyc`file generated as a result of the expression `'a'*10**10`). [Here's](https://github.com/python/cpython/blob/3.6/Python/peephole.c#L288) the implementation source for the same.
207
208
208
209
209
210
---
@@ -241,7 +242,7 @@ some_dict[5] = "Python"
241
242
True
242
243
```
243
244
**Note:** Objects with different values may also have same hash (known ashash collision).
244
-
* When the statement `some_dict[5] = "Python"`is executed, the existing value "JavaScript"is overwritten with"Python" because Python recongnizes`5`and`5.0`as the same keys of the dictionary `some_dict`.
245
+
* When the statement `some_dict[5] = "Python"`is executed, the existing value "JavaScript"is overwritten with"Python" because Python recognizes`5`and`5.0`as the same keys of the dictionary `some_dict`.
245
246
* This StackOverflow [answer](https://stackoverflow.com/a/32211042/4354153) explains beautifully the rationale behind it.
246
247
247
248
---
@@ -296,16 +297,24 @@ True
296
297
* But why did the `is` operator evaluated to `False`? Let's see with this snippet.
297
298
```py
298
299
class WTF(object):
299
-
def__init__(self): print("I")
300
-
def__del__(self): print("D")
300
+
def__init__(self): print("I")
301
+
def__del__(self): print("D")
301
302
```
302
303
303
304
**Output:**
304
305
```py
305
306
>>> WTF() is WTF()
306
-
I I D D
307
+
I
308
+
I
309
+
D
310
+
D
311
+
False
307
312
>>>id(WTF()) ==id(WTF())
308
-
I D I D
313
+
I
314
+
D
315
+
I
316
+
D
317
+
True
309
318
```
310
319
As you may observe, the order in which the objects are destroyed is what made all the difference here.
311
320
@@ -530,7 +539,7 @@ And when the `board` is initialized by multiplying the `row`, this is what happe
530
539
We can avoid this scenario here by not using `row` variable to generate `board`. (Asked in [this](https://github.com/satwikkansal/wtfpython/issues/68) issue).
531
540
532
541
```py
533
-
>>>board= [(['']*3)*3] # board = = [['']*3 for _ in range(3)]
542
+
>>> board = [['']*3for _ inrange(3)]
534
543
>>> board[0][0] = "X"
535
544
>>> board
536
545
[['X', '', ''], ['', '', ''], ['', '', '']]
@@ -547,7 +556,7 @@ for x in range(7):
547
556
def some_func():
548
557
return x
549
558
funcs.append(some_func)
550
-
results.append(some_func())
559
+
results.append(some_func())# note the function call here
551
560
552
561
funcs_results = [func() for func in funcs]
553
562
```
@@ -766,10 +775,10 @@ for item in mixed_list:
766
775
767
776
**Output:**
768
777
```py
769
-
>>> booleans_found_so_far
770
-
0
771
778
>>> integers_found_so_far
772
779
4
780
+
>>> booleans_found_so_far
781
+
0
773
782
```
774
783
775
784
2\.
@@ -830,7 +839,7 @@ class C(A):
830
839
pass
831
840
```
832
841
833
-
**Ouptut:**
842
+
**Output:**
834
843
```py
835
844
>>> A.x, B.x, C.x
836
845
(1, 1, 1)
@@ -1135,7 +1144,7 @@ str
1135
1144
and type(other) is SomeClass
1136
1145
and super().__eq__(other)
1137
1146
)
1138
-
1147
+
1139
1148
# When we define a custom __eq__, Python stops automatically inheriting the
1140
1149
# __hash__ method, so we need to define it as well
1141
1150
__hash__ = str.__hash__
@@ -1148,7 +1157,7 @@ str
1148
1157
>>> s = SomeClass('s')
1149
1158
>>> some_dict[s] = 40
1150
1159
>>> some_dict
1151
-
{'s': 40}
1160
+
{'s': 40, 's': 42}
1152
1161
>>> keys = list(some_dict.keys())
1153
1162
>>> type(keys[0]), type(keys[1])
1154
1163
(__main__.SomeClass, str)
@@ -1313,7 +1322,7 @@ Shouldn't that be 100?
1313
1322
> First, tabs are replaced (from left to right) by one to eight spaces such that the total number of characters up to and including the replacement is a multiple of eight <...>
1314
1323
* So the "tab" at the last line of `square` function is replaced with eight spaces, and it gets into the loop.
1315
1324
* Python 3 is kind enough to throw an error for such cases automatically.
1316
-
1325
+
1317
1326
**Output (Python 3.x):**
1318
1327
```py
1319
1328
TabError: inconsistent use of tabs and spaces in indentation
@@ -1697,7 +1706,7 @@ a += [5, 6, 7, 8]
1697
1706
1698
1707
* The expression `a = a + [5,6,7,8]` generates a new list and sets `a`'s reference to that new list, leaving `b` unchanged.
1699
1708
1700
-
* The expression `a + =[5,6,7,8]` is actually mapped to an "extend" function that operates on the list such that `a` and `b` still point to the same list that has been modified in-place.
1709
+
* The expression `a += [5,6,7,8]` is actually mapped to an "extend" function that operates on the list such that `a` and `b` still point to the same list that has been modified in-place.
1701
1710
1702
1711
---
1703
1712
@@ -1731,7 +1740,7 @@ UnboundLocalError: local variable 'a' referenced before assignment
1731
1740
a += 1
1732
1741
return a
1733
1742
```
1734
-
1743
+
1735
1744
**Output:**
1736
1745
```py
1737
1746
>>> another_func()
@@ -1895,7 +1904,7 @@ Sshh.. It's a super secret.
1895
1904
#### 💡 Explanation:
1896
1905
+ `antigravity` module is one of the few easter eggs released by Python developers.
1897
1906
+ `import antigravity` opens up a web browser pointing to the [classic XKCD comic](http://xkcd.com/353/) about Python.
1898
-
+ Well, there's more to it. There's **another easter egg inside the easter egg**. If look at the [code](https://github.com/python/cpython/blob/master/Lib/antigravity.py#L7-L17), there's a function defined that purports to implement the [XKCD's geohashing algorithm](https://xkcd.com/426/).
1907
+
+ Well, there's more to it. There's **another easter egg inside the easter egg**. If you look at the [code](https://github.com/python/cpython/blob/master/Lib/antigravity.py#L7-L17), there's a function defined that purports to implement the [XKCD's geohashing algorithm](https://xkcd.com/426/).
1899
1908
1900
1909
---
1901
1910
@@ -2115,7 +2124,7 @@ AttributeError: 'Yo' object has no attribute '__honey'
2115
2124
True
2116
2125
```
2117
2126
2118
-
Why did `Yo()._Yo__honey` worked? Only Indian readers would understand.
2127
+
Why did `Yo()._Yo__honey` work? Only Indian readers would understand.
2119
2128
2120
2129
#### 💡 Explanation:
2121
2130
@@ -2127,7 +2136,7 @@ Why did `Yo()._Yo__honey` worked? Only Indian readers would understand.
2127
2136
2128
2137
---
2129
2138
2130
-
## Section: Miscallaneous
2139
+
## Section: Miscellaneous
2131
2140
2132
2141
2133
2142
### ▶ `+=` is faster
@@ -2272,7 +2281,7 @@ nan
2272
2281
### ▶ Minor Ones
2273
2282
2274
2283
* `join()` is a string operation instead of list operation. (sort of counter-intuitive at first usage)
2275
-
2284
+
2276
2285
**💡 Explanation:**
2277
2286
If `join()` is a method on a string then it can operate on any iterable (list, tuple, iterators). If it were a method on a list, it'd have to be implemented separately by every type. Also, it doesn't make much sense to put a string-specific method on a generic `list` object API.
2278
2287
@@ -2350,7 +2359,7 @@ The idea and design for this collection were initially inspired by Denys Dovhan'
0 commit comments