diff --git a/wtfpython-pypi/content.md b/wtfpython-pypi/content.md index 3fd8a13..486a98e 100644 --- a/wtfpython-pypi/content.md +++ b/wtfpython-pypi/content.md @@ -1,17 +1,19 @@
An interesting collection of tricky Python snippets and lesser known features.
+An interesting collection of surprising snippets and lesser-known Python features.
[![WTFPL 2.0][license-image]][license-url] 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. -Here is a fun project attempting to collect such classic & tricky examples of unexpected behaviors and lesser known features in Python, and discuss what exactly is happening under the hood! +Here is a fun project to collect such tricky & counter-intuitive examples and lesser-known features in Python, attempting to discuss what exactly is happening under the hood! While some of the examples you see below may not be WTFs in the truest sense, but they'll reveal some of the interesting parts of Python that you might be unaware of. I find it a nice way to learn the internals of a programming language, and I think you'll find them interesting as well! -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: And if you're a returning reader, you can learn about the new modifications [here](https://github.com/satwikkansal/wtfpython/releases/). +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/). So, here we go... @@ -24,19 +26,6 @@ So, here we go... - [Structure of the Examples](#structure-of-the-examples) - [Usage](#usage) - [š Examples](#-examples) - - [Section: Appearances are deceptive!](#section-appearances-are-deceptive) - - [ā¶ Skipping lines?](#-skipping-lines) - - [ā¶ Teleportation *](#-teleportation-) - - [ā¶ Well, something is fishy...](#-well-something-is-fishy) - - [Section: The Hidden treasures!](#section-the-hidden-treasures) - - [ā¶ Okay Python, Can you make me fly? *](#-okay-python-can-you-make-me-fly-) - - [ā¶ `goto`, but why? *](#-goto-but-why-) - - [ā¶ Brace yourself! *](#-brace-yourself-) - - [ā¶ Let's meet Friendly Language Uncle For Life *](#-lets-meet-friendly-language-uncle-for-life-) - - [ā¶ Even Python understands that love is complicated *](#-even-python-understands-that-love-is-complicated-) - - [ā¶ Yes, it exists!](#-yes-it-exists) - - [ā¶ Inpinity *](#-inpinity-) - - [ā¶ Mangling time! *](#-mangling-time-) - [Section: Strain your brain!](#section-strain-your-brain) - [ā¶ Strings can be tricky sometimes *](#-strings-can-be-tricky-sometimes-) - [ā¶ Time for some hash brownies!](#-time-for-some-hash-brownies) @@ -63,6 +52,10 @@ So, here we go... - [ā¶ Subclass relationships *](#-subclass-relationships-) - [ā¶ The mysterious key type conversion *](#-the-mysterious-key-type-conversion-) - [ā¶ Let's see if you can guess this?](#-lets-see-if-you-can-guess-this) + - [Section: Appearances are deceptive!](#section-appearances-are-deceptive) + - [ā¶ Skipping lines?](#-skipping-lines) + - [ā¶ Teleportation *](#-teleportation-) + - [ā¶ Well, something is fishy...](#-well-something-is-fishy) - [Section: Watch out for the landmines!](#section-watch-out-for-the-landmines) - [ā¶ Modifying a dictionary while iterating over it](#-modifying-a-dictionary-while-iterating-over-it) - [ā¶ Stubborn `del` operator *](#-stubborn-del-operator-) @@ -75,6 +68,15 @@ So, here we go... - [ā¶ Be careful with chained operations](#-be-careful-with-chained-operations) - [ā¶ Name resolution ignoring class scope](#-name-resolution-ignoring-class-scope) - [ā¶ Needle in a Haystack](#-needle-in-a-haystack) + - [Section: The Hidden treasures!](#section-the-hidden-treasures) + - [ā¶ Okay Python, Can you make me fly? *](#-okay-python-can-you-make-me-fly-) + - [ā¶ `goto`, but why? *](#-goto-but-why-) + - [ā¶ Brace yourself! *](#-brace-yourself-) + - [ā¶ Let's meet Friendly Language Uncle For Life *](#-lets-meet-friendly-language-uncle-for-life-) + - [ā¶ Even Python understands that love is complicated *](#-even-python-understands-that-love-is-complicated-) + - [ā¶ Yes, it exists!](#-yes-it-exists) + - [ā¶ Inpinity *](#-inpinity-) + - [ā¶ Mangling time! *](#-mangling-time-) - [Section: Miscallaneous](#section-miscallaneous) - [ā¶ `+=` is faster](#--is-faster) - [ā¶ Let's make a giant string!](#-lets-make-a-giant-string) @@ -83,8 +85,8 @@ So, here we go... - [Contributing](#contributing) - [Acknowledgements](#acknowledgements) - [š License](#-license) -- [Help](#help) - - [Want to share WTFpython with friends?](#want-to-share-wtfpython-with-friends) + - [Help](#help) + - [Want to share wtfpython with friends?](#want-to-share-wtfpython-with-friends) - [Need a pdf version?](#need-a-pdf-version) @@ -151,371 +153,9 @@ Now, just run `wtfpython` at the command line which will open this collection in # š Examples -## Section: Appearances are deceptive! - -This section is a gentle warm up before we focus on real Python concepts. - -### ā¶ Skipping lines? - -**Output:** -```py ->>> value = 11 ->>> valuе = 32 ->>> value -11 -``` - -Wut? - -**Note:** The easiest way to reproduce this is to simply copy the statements from the above snippet and paste them into your file/shell. - -#### š” Explanation - -Some non-Western characters look identical to letters in the English alphabet but are considered distinct by the interpreter. - -```py ->>> ord('е') # cyrillic 'e' (Ye) -1077 ->>> ord('e') # latin 'e', as used in English and typed using standard keyboard -101 ->>> 'е' == 'e' -False - ->>> value = 42 # latin e ->>> valuе = 23 # cyrillic 'e', Python 2.x interpreter would raise a `SyntaxError` here ->>> value -42 -``` - -The built-in `ord()` function returns a character's Unicode [code point](https://en.wikipedia.org/wiki/Code_point), and different code positions of Cyrillic 'e' and Latin 'e' justify the behavior of the above example. - ---- - -### ā¶ Teleportation * - -```py -import numpy as np - -def energy_send(x): - # Initializing a numpy array - np.array([float(x)]) - -def energy_receive(): - # Return an empty numpy array - return np.empty((), dtype=np.float).tolist() -``` - -**Output:** -```py ->>> energy_send(123.456) ->>> energy_receive() -123.456 -``` - -Where's the Nobel Prize? - -#### š” Explanation: - -* Notice that the numpy array created in the `energy_send` function is not returned, so that memory space is free to reallocate. -* `numpy.empty()` returns the next free memory slot without reinitializing it. This memory spot just happens to be the same one that was just freed (usually, but not always). - ---- - -### ā¶ Well, something is fishy... - -```py -def square(x): - """ - A simple function to calculate the square of a number by addition. - """ - sum_so_far = 0 - for counter in range(x): - sum_so_far = sum_so_far + x - return sum_so_far -``` - -**Output (Python 2.x):** - -```py ->>> square(10) -10 -``` - -Shouldn't that be 100? - -**Note:** If you're not able to reproduce this, try running the file [mixed_tabs_and_spaces.py](/mixed_tabs_and_spaces.py) via the shell. - -#### š” Explanation - -* **Don't mix tabs and spaces!** The character just preceding return is a "tab", and the code is indented by multiple of "4 spaces" elsewhere in the example. -* This is how Python handles tabs: - > 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. -* Python 3 is kind enough to throw an error for such cases automatically. - - **Output (Python 3.x):** - ```py - TabError: inconsistent use of tabs and spaces in indentation - ``` - ---- - ---- - -## Section: The Hidden treasures! - -This section contains few of the lesser-known interesting things about Python that most beginners like me are unaware of (well, not anymore). - -### ā¶ Okay Python, Can you make me fly? * - -Well, here you go - -```py -import antigravity -``` - -**Output:** -Sshh.. It's a super secret. - -#### š” Explanation: -+ `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. -+ 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/). - ---- - -### ā¶ `goto`, but why? * - -```py -from goto import goto, label -for i in range(9): - for j in range(9): - for k in range(9): - print("I'm trapped, please rescue!") - if k == 2: - goto .breakout # breaking out from a deeply nested loop -label .breakout -print("Freedom!") -``` - -**Output (Python 2.3):** -```py -I'm trapped, please rescue! -I'm trapped, please rescue! -Freedom! -``` - -#### š” Explanation: -- A working version of `goto` in Python was [announced](https://mail.python.org/pipermail/python-announce-list/2004-April/002982.html) as an April Fool's joke on 1st April 2004. -- Current versions of Python do not have this module. -- Although it works, but please don't use it. Here's the [reason](https://docs.python.org/3/faq/design.html#why-is-there-no-goto) to why `goto` is not present in Python. - ---- - -### ā¶ Brace yourself! * - -If you are one of the people who doesn't like using whitespace in Python to denote scopes, you can use the C-style {} by importing, - -```py -from __future__ import braces -``` - -**Output:** -```py - File "some_file.py", line 1 - from __future__ import braces -SyntaxError: not a chance -``` - -Braces? No way! If you think that's disappointing, use Java. - -#### š” Explanation: -+ The `__future__` module is normally used to provide features from future versions of Python. The "future" here is however ironic. -+ This is an easter egg concerned with the community's feelings on this issue. - ---- - -### ā¶ Let's meet Friendly Language Uncle For Life * - -**Output (Python 3.x)** -```py ->>> from __future__ import barry_as_FLUFL ->>> "Ruby" != "Python" # there's no doubt about it - File "some_file.py", line 1 - "Ruby" != "Python" - ^ -SyntaxError: invalid syntax - ->>> "Ruby" <> "Python" -True -``` - -There we go. - -#### š” Explanation: -- This is relevant to [PEP-401](https://www.python.org/dev/peps/pep-0401/) released on April 1, 2009 (now you know, what it means). -- Quoting from the PEP-401 - Recognized that the != inequality operator in Python 3.0 was a horrible, finger pain inducing mistake, the FLUFL reinstates the <> diamond operator as the sole spelling. -- There were more things that Uncle Barry had to share in the PEP; you can read them [here](https://www.python.org/dev/peps/pep-0401/). - ---- - -### ā¶ Even Python understands that love is complicated * - -```py -import this -``` - -Wait, what's **this**? `this` is love :heart: - -**Output:** -``` -The Zen of Python, by Tim Peters - -Beautiful is better than ugly. -Explicit is better than implicit. -Simple is better than complex. -Complex is better than complicated. -Flat is better than nested. -Sparse is better than dense. -Readability counts. -Special cases aren't special enough to break the rules. -Although practicality beats purity. -Errors should never pass silently. -Unless explicitly silenced. -In the face of ambiguity, refuse the temptation to guess. -There should be one-- and preferably only one --obvious way to do it. -Although that way may not be obvious at first unless you're Dutch. -Now is better than never. -Although never is often better than *right* now. -If the implementation is hard to explain, it's a bad idea. -If the implementation is easy to explain, it may be a good idea. -Namespaces are one honking great idea -- let's do more of those! -``` - -It's the Zen of Python! - -```py ->>> love = this ->>> this is love -True ->>> love is True -False ->>> love is False -False ->>> love is not True or False -True ->>> love is not True or False; love is love # Love is complicated -True -``` - -#### š” Explanation: - -* `this` module in Python is an easter egg for The Zen Of Python ([PEP 20](https://www.python.org/dev/peps/pep-0020)). -* And if you think that's already interesting enough, check out the implementation of [this.py](https://hg.python.org/cpython/file/c3896275c0f6/Lib/this.py). Interestingly, the code for the Zen violates itself (and that's probably the only place where this happens). -* Regarding the statement `love is not True or False; love is love`, ironic but it's self-explanatory. - ---- - -### ā¶ Yes, it exists! - -**The `else` clause for loops.** One typical example might be: - -```py - def does_exists_num(l, to_find): - for num in l: - if num == to_find: - print("Exists!") - break - else: - print("Does not exist") -``` - -**Output:** -```py ->>> some_list = [1, 2, 3, 4, 5] ->>> does_exists_num(some_list, 4) -Exists! ->>> does_exists_num(some_list, -1) -Does not exist -``` - -**The `else` clause in exception handling.** An example, - -```py -try: - pass -except: - print("Exception occurred!!!") -else: - print("Try block executed successfully...") -``` - -**Output:** -```py -Try block executed successfully... -``` - -#### š” Explanation: -- The `else` clause after a loop is executed only when there's no explicit `break` after all the iterations. -- `else` clause after try block is also called "completion clause" as reaching the `else` clause in a `try` statement means that the try block actually completed successfully. - ---- - -### ā¶ Inpinity * - -The spelling is intended. Please, don't submit a patch for this. - -**Output (Python 3.x):** -```py ->>> infinity = float('infinity') ->>> hash(infinity) -314159 ->>> hash(float('-inf')) --314159 -``` - -#### š” Explanation: -- Hash of infinity is 10āµ x Ļ. -- Interestingly, the hash of `float('-inf')` is "-10āµ x Ļ" in Python 3, whereas "-10āµ x e" in Python 2. - ---- - -### ā¶ Mangling time! * - -```py -class Yo(object): - def __init__(self): - self.__honey = True - self.bitch = True -``` - -**Output:** -```py ->>> Yo().bitch -True ->>> Yo().__honey -AttributeError: 'Yo' object has no attribute '__honey' ->>> Yo()._Yo__honey -True -``` - -Why did `Yo()._Yo__honey` worked? Only Indian readers would understand. - -#### š” Explanation: - -* [Name Mangling](https://en.wikipedia.org/wiki/Name_mangling) is used to avoid naming collisions between different namespaces. -* In Python, the interpreter modifies (mangles) the class member names starting with `__` (double underscore) and not ending with more than one trailing underscore by adding `_NameOfTheClass` in front. -* So, to access `__honey` attribute, we are required to append `_Yo` to the front which would prevent conflicts with the same name attribute defined in any other class. - ---- - ---- ## Section: Strain your brain! -Alright, it's time to strain your brain and test your understanding of Python concepts. All the best! - ### ā¶ Strings can be tricky sometimes * 1\. @@ -563,6 +203,8 @@ Makes sense, right? * Strings that are not composed of ASCII letters, digits or underscores, are not interned. This explains why `'wtf!'` was not interned due to `!`.