Update content.md

This commit is contained in:
Satwik Kansal 2019-06-07 23:48:51 +05:30 committed by Satwik
parent 810dbe1582
commit f8a7d38b70
1 changed files with 44 additions and 35 deletions

View File

@ -1,9 +1,10 @@
<p align="center"><img src="/images/logo.png" alt=""></p> <p align="center"><img src="/images/logo.png" alt=""></p>
<h1 align="center"> What the f*ck Python! 🐍 </h1> <h1 align="center">What the f*ck Python! 🐍</h1>
<p align="center"> An interesting collection of surprising snippets and lesser-known Python features.</p> <p align="center">An interesting collection of surprising snippets and lesser-known Python features.</p>
[![WTFPL 2.0][license-image]][license-url] [![WTFPL 2.0][license-image]][license-url]
Translations: [Chinese 中文](https://github.com/leisurelicht/wtfpython-cn)
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. 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.
@ -13,7 +14,7 @@ While some of the examples you see below may not be WTFs in the truest sense, bu
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: 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:
If you're a returning reader, you can learn about the new modifications [here](https://github.com/satwikkansal/wtfpython/releases/). PS: If you're a returning reader, you can learn about the new modifications [here](https://github.com/satwikkansal/wtfpython/releases/).
So, here we go... So, here we go...
@ -77,7 +78,7 @@ So, here we go...
- [▶ Yes, it exists!](#-yes-it-exists) - [▶ Yes, it exists!](#-yes-it-exists)
- [▶ Inpinity *](#-inpinity-) - [▶ Inpinity *](#-inpinity-)
- [▶ Mangling time! *](#-mangling-time-) - [▶ Mangling time! *](#-mangling-time-)
- [Section: Miscallaneous](#section-miscallaneous) - [Section: Miscellaneous](#section-miscellaneous)
- [▶ `+=` is faster](#--is-faster) - [▶ `+=` is faster](#--is-faster)
- [▶ Let's make a giant string!](#-lets-make-a-giant-string) - [▶ Let's make a giant string!](#-lets-make-a-giant-string)
- [▶ Explicit typecast of strings](#-explicit-typecast-of-strings) - [▶ Explicit typecast of strings](#-explicit-typecast-of-strings)
@ -97,22 +98,22 @@ All the examples are structured like below:
> ### ▶ Some fancy Title * > ### ▶ Some fancy Title *
> The asterisk at the end of the title indicates the example was not present in the first release and has been recently added. > The asterisk at the end of the title indicates the example was not present in the first release and has been recently added.
> >
> ```py > ```py
> # Setting up the code. > # Setting up the code.
> # Preparation for the magic... > # Preparation for the magic...
> ``` > ```
> >
> **Output (Python version):** > **Output (Python version):**
> ```py > ```py
> >>> triggering_statement > >>> triggering_statement
> Probably unexpected output > Probably unexpected output
> ``` > ```
> (Optional): One line describing the unexpected output. > (Optional): One line describing the unexpected output.
> >
> >
> #### 💡 Explanation: > #### 💡 Explanation:
> >
> * Brief explanation of what's happening and why is it happening. > * Brief explanation of what's happening and why is it happening.
> ```py > ```py
> Setting up examples for clarification (if necessary) > Setting up examples for clarification (if necessary)
@ -200,10 +201,10 @@ Makes sense, right?
+ 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 or not: + 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 or not:
* All length 0 and length 1 strings are interned. * All length 0 and length 1 strings are interned.
* Strings are interned at compile time (`'wtf'` will be interned but `''.join(['w', 't', 'f']` will not be interned) * Strings are interned at compile time (`'wtf'` will be interned but `''.join(['w', 't', 'f']` will not be interned)
* Strings that are not composed of ASCII letters, digits or underscores, are not interned. This explains why `'wtf!'` was not interned due to `!`. * 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)
<img src="/images/string-intern/string_intern.png" alt=""> <img src="/images/string-intern/string_intern.png" alt="">
+ 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!"` is not implicitly interned as per the facts mentioned above). It's a compiler optimization and specifically applies to the interactive environment. + 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!"` is not implicitly interned as per the facts mentioned above). It's a compiler optimization and specifically applies to the interactive environment.
+ 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`) + 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 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.
--- ---
@ -241,7 +242,7 @@ some_dict[5] = "Python"
True True
``` ```
**Note:** Objects with different values may also have same hash (known as hash collision). **Note:** Objects with different values may also have same hash (known as hash collision).
* 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`. * 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`.
* This StackOverflow [answer](https://stackoverflow.com/a/32211042/4354153) explains beautifully the rationale behind it. * This StackOverflow [answer](https://stackoverflow.com/a/32211042/4354153) explains beautifully the rationale behind it.
--- ---
@ -296,16 +297,24 @@ True
* But why did the `is` operator evaluated to `False`? Let's see with this snippet. * But why did the `is` operator evaluated to `False`? Let's see with this snippet.
```py ```py
class WTF(object): class WTF(object):
def __init__(self): print("I ") def __init__(self): print("I")
def __del__(self): print("D ") def __del__(self): print("D")
``` ```
**Output:** **Output:**
```py ```py
>>> WTF() is WTF() >>> WTF() is WTF()
I I D D I
I
D
D
False
>>> id(WTF()) == id(WTF()) >>> id(WTF()) == id(WTF())
I D I D I
D
I
D
True
``` ```
As you may observe, the order in which the objects are destroyed is what made all the difference here. As you may observe, the order in which the objects are destroyed is what made all the difference here.
@ -530,7 +539,7 @@ And when the `board` is initialized by multiplying the `row`, this is what happe
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). 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).
```py ```py
>>> board = [(['']*3)*3] # board = = [['']*3 for _ in range(3)] >>> board = [['']*3 for _ in range(3)]
>>> board[0][0] = "X" >>> board[0][0] = "X"
>>> board >>> board
[['X', '', ''], ['', '', ''], ['', '', '']] [['X', '', ''], ['', '', ''], ['', '', '']]
@ -547,7 +556,7 @@ for x in range(7):
def some_func(): def some_func():
return x return x
funcs.append(some_func) funcs.append(some_func)
results.append(some_func()) results.append(some_func()) # note the function call here
funcs_results = [func() for func in funcs] funcs_results = [func() for func in funcs]
``` ```
@ -766,10 +775,10 @@ for item in mixed_list:
**Output:** **Output:**
```py ```py
>>> booleans_found_so_far
0
>>> integers_found_so_far >>> integers_found_so_far
4 4
>>> booleans_found_so_far
0
``` ```
2\. 2\.
@ -830,7 +839,7 @@ class C(A):
pass pass
``` ```
**Ouptut:** **Output:**
```py ```py
>>> A.x, B.x, C.x >>> A.x, B.x, C.x
(1, 1, 1) (1, 1, 1)
@ -1135,7 +1144,7 @@ str
and type(other) is SomeClass and type(other) is SomeClass
and super().__eq__(other) and super().__eq__(other)
) )
# When we define a custom __eq__, Python stops automatically inheriting the # When we define a custom __eq__, Python stops automatically inheriting the
# __hash__ method, so we need to define it as well # __hash__ method, so we need to define it as well
__hash__ = str.__hash__ __hash__ = str.__hash__
@ -1148,7 +1157,7 @@ str
>>> s = SomeClass('s') >>> s = SomeClass('s')
>>> some_dict[s] = 40 >>> some_dict[s] = 40
>>> some_dict >>> some_dict
{'s': 40} {'s': 40, 's': 42}
>>> keys = list(some_dict.keys()) >>> keys = list(some_dict.keys())
>>> type(keys[0]), type(keys[1]) >>> type(keys[0]), type(keys[1])
(__main__.SomeClass, str) (__main__.SomeClass, str)
@ -1313,7 +1322,7 @@ Shouldn't that be 100?
> 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 <...> > 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 <...>
* So the "tab" at the last line of `square` function is replaced with eight spaces, and it gets into the loop. * So the "tab" at the last line of `square` function is replaced with eight spaces, and it gets into the loop.
* Python 3 is kind enough to throw an error for such cases automatically. * Python 3 is kind enough to throw an error for such cases automatically.
**Output (Python 3.x):** **Output (Python 3.x):**
```py ```py
TabError: inconsistent use of tabs and spaces in indentation TabError: inconsistent use of tabs and spaces in indentation
@ -1697,7 +1706,7 @@ a += [5, 6, 7, 8]
* The expression `a = a + [5,6,7,8]` generates a new list and sets `a`'s reference to that new list, leaving `b` unchanged. * The expression `a = a + [5,6,7,8]` generates a new list and sets `a`'s reference to that new list, leaving `b` unchanged.
* 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. * 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.
--- ---
@ -1731,7 +1740,7 @@ UnboundLocalError: local variable 'a' referenced before assignment
a += 1 a += 1
return a return a
``` ```
**Output:** **Output:**
```py ```py
>>> another_func() >>> another_func()
@ -1895,7 +1904,7 @@ Sshh.. It's a super secret.
#### 💡 Explanation: #### 💡 Explanation:
+ `antigravity` module is one of the few easter eggs released by Python developers. + `antigravity` module is one of the few easter eggs released by Python developers.
+ `import antigravity` opens up a web browser pointing to the [classic XKCD comic](http://xkcd.com/353/) about Python. + `import antigravity` opens up a web browser pointing to the [classic XKCD comic](http://xkcd.com/353/) about Python.
+ 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/). + 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/).
--- ---
@ -2115,7 +2124,7 @@ AttributeError: 'Yo' object has no attribute '__honey'
True True
``` ```
Why did `Yo()._Yo__honey` worked? Only Indian readers would understand. Why did `Yo()._Yo__honey` work? Only Indian readers would understand.
#### 💡 Explanation: #### 💡 Explanation:
@ -2127,7 +2136,7 @@ Why did `Yo()._Yo__honey` worked? Only Indian readers would understand.
--- ---
## Section: Miscallaneous ## Section: Miscellaneous
### ▶ `+=` is faster ### ▶ `+=` is faster
@ -2272,7 +2281,7 @@ nan
### ▶ Minor Ones ### ▶ Minor Ones
* `join()` is a string operation instead of list operation. (sort of counter-intuitive at first usage) * `join()` is a string operation instead of list operation. (sort of counter-intuitive at first usage)
**💡 Explanation:** **💡 Explanation:**
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. 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.
@ -2350,7 +2359,7 @@ The idea and design for this collection were initially inspired by Denys Dovhan'
* https://stackoverflow.com/questions/530530/python-2-x-gotchas-and-landmines * https://stackoverflow.com/questions/530530/python-2-x-gotchas-and-landmines
* https://stackoverflow.com/questions/1011431/common-pitfalls-in-python * https://stackoverflow.com/questions/1011431/common-pitfalls-in-python
* https://www.python.org/doc/humor/ * https://www.python.org/doc/humor/
* https://www.satwikkansal.xyz/archives/posts/python/My-Python-archives/ * https://www.codementor.io/satwikkansal/python-practices-for-efficient-code-performance-memory-and-usability-aze6oiq65
# 🎓 License # 🎓 License
@ -2365,12 +2374,12 @@ The idea and design for this collection were initially inspired by Denys Dovhan'
If you have any wtfs, ideas or suggestions, please share. If you have any wtfs, ideas or suggestions, please share.
## Want to share wtfpython with friends? ## Surprise your geeky pythonist friends?
You can use these quick links for Twitter and Linkedin. You can use these quick links to recommend wtfpython to your friends,
[Twitter](https://twitter.com/intent/tweet?url=https://github.com/satwikkansal/wtfpython&hastags=python,wtfpython) | [Twitter](https://twitter.com/intent/tweet?url=https://github.com/satwikkansal/wtfpython&hastags=python,wtfpython)
[Linkedin](https://www.linkedin.com/shareArticle?url=https://github.com/satwikkansal&title=What%20the%20f*ck%20Python!&summary=An%20interesting%20collection%20of%20subtle%20and%20tricky%20Python%20snippets.) | [Linkedin](https://www.linkedin.com/shareArticle?url=https://github.com/satwikkansal&title=What%20the%20f*ck%20Python!&summary=An%20interesting%20collection%20of%20subtle%20and%20tricky%20Python%20snippets.)
## Need a pdf version? ## Need a pdf version?