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
Copy file name to clipboardExpand all lines: README.md
+56-25Lines changed: 56 additions & 25 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -297,6 +297,10 @@ True
297
297
>>>b="wtf!"
298
298
>>> a is b
299
299
False
300
+
301
+
>>> a, b="wtf!", "wtf!"
302
+
>>> a is b
303
+
True
300
304
```
301
305
302
306
3\.
@@ -320,6 +324,7 @@ Makes sense, right?
320
324
* Strings are interned at compile time (`'wtf'` will be interned but `''.join(['w', 't', 'f']` will not be interned)
321
325
* 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. This optimization doesn't apply to 3.7.x versions of CPython (check this [issue](https://github.com/satwikkansal/wtfpython/issues/100) for more discussion).
323
328
+ The abrupt change in output of the third snippet is due to a [peephole optimization](https://en.wikipedia.org/wiki/Peephole_optimization) technique known as Constant folding. This means the expression `'a'*20`is replaced by `'aaaaaaaaaaaaaaaaaaaa'` during compilation to save a few clock cycles during runtime. Constant folding only occurs for strings 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.
324
329
+ Note: In Python 3.7, Constant folding was moved out from peephole optimizer to the new AST optimizer with some change in logic as well, so the third snippet doesn't work for Python 3.7. You can read more about the change [here](https://bugs.python.org/issue11549).
325
330
@@ -771,7 +776,8 @@ True
771
776
```
772
777
773
778
3\.
774
-
**Output (< Python 3.7)**
779
+
**Output**
780
+
775
781
```
776
782
>>> a, b=257, 257
777
783
True
@@ -781,7 +787,8 @@ True
781
787
True
782
788
```
783
789
784
-
**Output (Python 3.7)**
790
+
**Output (Python 3.7.x specifically)**
791
+
785
792
```
786
793
>>> a, b=257, 257
787
794
False
@@ -836,7 +843,8 @@ Similar optimization applies to other **immutable** objects like empty tuples as
836
843
837
844
**Both `a`and`b` refer to the same object when initialized with same value in the same line.**
838
845
839
-
**Output (< Python 3.7)**
846
+
**Output**
847
+
840
848
```py
841
849
>>> a, b = 257, 257
842
850
>>>id(a)
@@ -852,7 +860,17 @@ Similar optimization applies to other **immutable** objects like empty tuples as
852
860
```
853
861
854
862
* When a and b are set to `257`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 `257`as an object.
855
-
* It's a compiler optimization and specifically applies to the interactive environment. When you enter two lines in a live interpreter, they're compiled separately, therefore optimized separately. If you were to try this example in a `.py`file, you would not see the same behavior, because the fileis compiled all at once.
863
+
864
+
* It's a compiler optimization and specifically applies to the interactive environment. When you enter two lines in a live interpreter, they're compiled separately, therefore optimized separately. If you were to try this example in a `.py`file, you would not see the same behavior, because the fileis compiled all at once. This optimization isnot limited to integers, it works for other immutable data types like strings and floats as well.
865
+
866
+
```py
867
+
>>> a, b = 257.0, 257.0
868
+
>>> a is b
869
+
True
870
+
```
871
+
872
+
873
+
856
874
* Why didn't this work for Python 3.7? The abstract reason is because such compiler optimizations are implementation specific (i.e. may change with version, OS, etc). I'm still figuring out what exact implementation change cause the issue, you can check out this [issue](https://github.com/satwikkansal/wtfpython/issues/100) for updates.
857
875
858
876
---
@@ -1189,6 +1207,7 @@ Before Python 3.5, the boolean value for `datetime.time` object was considered t
1189
1207
### ▶ What's wrong with booleans?
1190
1208
<!-- Example ID: 0bba5fa7-9e6d-4cd2-8b94-952d061af5dd --->
1191
1209
1\.
1210
+
1192
1211
```py
1193
1212
# A simple example to count the number of booleans and
1194
1213
# integers in an iterable of mixed data types.
@@ -1222,15 +1241,33 @@ for item in mixed_list:
1222
1241
''
1223
1242
```
1224
1243
1244
+
3\.
1245
+
1246
+
```py
1247
+
True = False
1248
+
if True == False:
1249
+
print("I've lost faith in truth!")
1250
+
```
1251
+
1252
+
**Output (< 3.x):**
1253
+
1254
+
```
1255
+
I've lost faith in truth!
1256
+
```
1257
+
1258
+
1259
+
1225
1260
#### 💡 Explanation:
1226
1261
1227
1262
* `bool` is a subclass of `int` in Python
1263
+
1228
1264
```py
1229
1265
>>> issubclass(bool, int)
1230
1266
True
1231
1267
>>> issubclass(int, bool)
1232
1268
False
1233
1269
```
1270
+
1234
1271
* And thus, `True` and `False` are instances of `int`
1235
1272
```py
1236
1273
>>> isinstance(True, int)
@@ -1249,6 +1286,10 @@ for item in mixed_list:
1249
1286
1250
1287
* See this StackOverflow [answer](https://stackoverflow.com/a/8169049/4354153) for the rationale behind it.
1251
1288
1289
+
* Initially, Python used to have no `bool` type (people used 0 for false and non-zero value like 1 for true). `True`, `False`, and a `bool` type was added in 2.x versions, but, for backward compatibility, `True` and `False` couldn't be made constants. They just were built-in variables, and it was possible to reassign them
1290
+
1291
+
* Python 3 was backward-incompatible, the issue was finally fixed, and thus the last snippet won't work with Python 3.x!
1292
+
1252
1293
---
1253
1294
1254
1295
### ▶ Class attributes and instance attributes
@@ -1510,27 +1551,6 @@ NameError: name 'e' is not defined
1510
1551
1511
1552
---
1512
1553
1513
-
### ▶ When True is actually False
1514
-
<!-- Example ID: c8317047-48ae-4306-af5a-04c6d8b7c2b9 --->
1515
-
```py
1516
-
True = False
1517
-
if True == False:
1518
-
print("I've lost faith in truth!")
1519
-
```
1520
-
1521
-
**Output (< 3.x):**
1522
-
1523
-
```
1524
-
I've lost faith in truth!
1525
-
```
1526
-
1527
-
#### 💡 Explanation:
1528
-
1529
-
- Initially, Python used to have no `bool` type (people used 0 for false and non-zero value like 1 for true). Then they added `True`, `False`, and a `bool` type, but, for backward compatibility, they couldn't make `True` and `False` constants- they just were built-in variables.
1530
-
- Python 3 was backward-incompatible, so it was now finally possible to fix that, and so this example won't work with Python 3.x!
1531
-
1532
-
---
1533
-
1534
1554
### ▶ Yielding from... return!
1535
1555
1536
1556
1\.
@@ -3346,6 +3366,17 @@ f()
3346
3366
3347
3367
* `int('١٢٣٤٥٦٧٨٩')` returns `123456789` in Python 3. In Python, Decimal characters include digit characters, and all characters that can be used to form decimal-radix numbers, e.g. U+0660, ARABIC-INDIC DIGIT ZERO. Here's an [interesting story](http://chris.improbable.org/2014/8/25/adventures-in-unicode-digits/) related to this behavior of Python.
3348
3368
3369
+
* You can seperate numeric literals with underscores (for better readablity) from Python 3 onwards.
3370
+
3371
+
```py
3372
+
>>> six_million = 6_000_000
3373
+
>>> six_million
3374
+
6000000
3375
+
>>> hex_address = 0xF00D_CAFE
3376
+
>>> hex_address
3377
+
4027435774
3378
+
```
3379
+
3349
3380
* `'abc'.count('') == 4`. Here's an approximate implementation of `count` method, which would make the things more clear
0 commit comments