Skip to content

Commit 28bcbfd

Browse files
committed
More changes to order and aesthetics
1 parent 82c37cc commit 28bcbfd

File tree

1 file changed

+103
-125
lines changed

1 file changed

+103
-125
lines changed

README.md

Lines changed: 103 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,7 +1303,7 @@ NameError: name 'e' is not defined
13031303
13041304
* Source: https://docs.python.org/3/reference/compound_stmts.html#except
13051305
1306-
When an exception has been assigned using `as` target, it is cleared at the end of the except clause. This is as if
1306+
When an exception has been assigned using `as` target, it is cleared at the end of the `except` clause. This is as if
13071307
13081308
```py
13091309
except E as N:
@@ -1378,8 +1378,75 @@ I've lost faith in truth!
13781378
13791379
---
13801380
1381+
### ▶ Yielding from... return!
1382+
1383+
1\.
1384+
1385+
```py
1386+
def some_func(x):
1387+
if x == 3:
1388+
return ["wtf"]
1389+
else:
1390+
yield from range(x)
1391+
```
1392+
1393+
**Output:**
1394+
1395+
```py
1396+
>>> list(some_func(3))
1397+
[]
1398+
```
1399+
1400+
Where did the `"wtf"` go? Is it due to some special effect of `yield from`? Let's validate that,
1401+
1402+
2\.
1403+
1404+
```py
1405+
def some_func(x):
1406+
if x == 3:
1407+
return ["wtf"]
1408+
else:
1409+
for i in range(x):
1410+
yield i
1411+
```
1412+
1413+
**Output (> 3.3):**
1414+
1415+
```py
1416+
>>> list(some_func(3))
1417+
[]
1418+
```
1419+
1420+
Same result, that didn't work either.
1421+
1422+
#### 💡 Explanation:
1423+
1424+
+ From Python 3.3 onwards, it became possible to use `return` statement with values inside generators (See [PEP380](https://www.python.org/dev/peps/pep-0380/)). The [official docs](https://www.python.org/dev/peps/pep-0380/#enhancements-to-stopiteration) say that,
1425+
1426+
> "... `return expr` in a generator causes `StopIteration(expr)` to be raised upon exit from the generator."
1427+
1428+
+ In case of `some_func(3)`, `StopIteration` is raised at the beginning because of `return` statement. The `StopIteration` exception is automatically catched inside the `list(...)` wrapper and the `for` loop. Therefore, the above two snippets result in an empty list.
1429+
1430+
+ To get `["wtf"]` from the generator `some_func` we need to catch the `StopIteration` exception,
1431+
1432+
```py
1433+
try:
1434+
next(some_func(3))
1435+
except StopIteration as e:
1436+
some_string = e.value
1437+
```
1438+
1439+
```py
1440+
>>> some_string
1441+
["wtf"]
1442+
```
1443+
1444+
---
1445+
13811446
### ▶ Lossy zip of iterators
1447+
13821448
<!-- Example ID: c28ed154-e59f-4070-8eb6-8967a4acac6d --->
1449+
13831450
```py
13841451
>>> numbers = list(range(7))
13851452
>>> numbers
@@ -1407,8 +1474,7 @@ Where did element `3` go from the `numbers` list?
14071474
result = []
14081475
for it in iterators:
14091476
elem = next(it, sentinel)
1410-
if elem is sentinel:
1411-
return
1477+
if elem is sentinel: return
14121478
result.append(elem)
14131479
yield tuple(result)
14141480
```
@@ -1605,7 +1671,9 @@ The built-in `ord()` function returns a character's Unicode [code point](https:/
16051671
---
16061672
16071673
### ▶ Teleportation
1674+
16081675
<!-- Example ID: edafe923-0c20-4315-b6e1-0c31abfc38f5 --->
1676+
16091677
```py
16101678
import numpy as np
16111679
@@ -1858,31 +1926,32 @@ print(x, ': x in global')
18581926
>>> x = 1
18591927
>>> print([x for x in range(5)])
18601928
[0, 1, 2, 3, 4]
1861-
>>> print(x, ': x in global')
1862-
(4, ': x in global')
1929+
>>> print(x)
1930+
4
18631931
```
18641932
18651933
**Output (Python 3.x):**
18661934
```
18671935
>>> x = 1
18681936
>>> print([x for x in range(5)])
18691937
[0, 1, 2, 3, 4]
1870-
>>> print(x, ': x in global')
1871-
1 : x in global
1938+
>>> print(x)
1939+
1
18721940
```
18731941
18741942
#### 💡 Explanation:
18751943
18761944
- In Python, for-loops use the scope they exist in and leave their defined loop-variable behind. This also applies if we explicitly defined the for-loop variable in the global namespace before. In this case, it will rebind the existing variable.
18771945
1878-
- The differences in the output of Python 2.x and Python 3.x interpreters for list comprehension example can be explained by following change documented in [What’s New In Python 3.0](https://docs.python.org/3/whatsnew/3.0.html) documentation:
1946+
- The differences in the output of Python 2.x and Python 3.x interpreters for list comprehension example can be explained by following change documented in [What’s New In Python 3.0](https://docs.python.org/3/whatsnew/3.0.html) change log:
18791947
18801948
> "List comprehensions no longer support the syntactic form `[... for var in item1, item2, ...]`. Use `[... for var in (item1, item2, ...)]` instead. Also, note that list comprehensions have different semantics: they are closer to syntactic sugar for a generator expression inside a `list()` constructor, and in particular the loop control variables are no longer leaked into the surrounding scope."
18811949
18821950
---
18831951
18841952
### ▶ Beware of default mutable arguments!
18851953
<!-- Example ID: 7d42dade-e20d-4a7b-9ed7-16fb58505fe9 --->
1954+
18861955
```py
18871956
def some_func(default_arg=[]):
18881957
default_arg.append("some_string")
@@ -2182,39 +2251,6 @@ class SomeClass:
21822251
21832252
---
21842253
2185-
### ▶ From full to None in one instruction
2186-
2187-
<!-- Example ID: 9a0d5335-efe5-4eae-af44-584d15233066 --->
2188-
2189-
```py
2190-
some_list = [1, 2, 3]
2191-
some_dict = {
2192-
"key_1": 1,
2193-
"key_2": 2,
2194-
"key_3": 3
2195-
}
2196-
2197-
some_list = some_list.append(4)
2198-
some_dict = some_dict.update({"key_4": 4})
2199-
```
2200-
2201-
**Output:**
2202-
2203-
```py
2204-
>>> print(some_list)
2205-
None
2206-
>>> print(some_dict)
2207-
None
2208-
```
2209-
2210-
#### 💡 Explanation
2211-
2212-
2213-
2214-
---
2215-
2216-
2217-
22182254
### ▶ Needles in a Haystack
22192255
22202256
<!-- Example ID: 52a199b1-989a-4b28-8910-dff562cebba9 --->
@@ -2235,6 +2271,7 @@ x, y = (0, 1) if True else None, None
22352271
```
22362272
22372273
2\.
2274+
22382275
```py
22392276
t = ('one', 'two')
22402277
for i in t:
@@ -2249,6 +2286,7 @@ print(t)
22492286
```
22502287
22512288
**Output:**
2289+
22522290
```py
22532291
one
22542292
two
@@ -2288,7 +2326,9 @@ ten_words_list = [
22882326
a = "python"
22892327
b = "javascript"
22902328
```
2329+
22912330
**Output:**
2331+
22922332
```py
22932333
# An assert statement with an assertion failure message.
22942334
>>> assert(a == b, "Both languages are different")
@@ -2329,97 +2369,35 @@ None
23292369
* `()` is a special token and denotes empty `tuple`.
23302370
23312371
* In 3, as you might have already figured out, there's a missing comma after 5th element (`"that"`) in the list. So by implicit string literal concatenation,
2332-
```py
2333-
>>> ten_words_list
2334-
['some', 'very', 'big', 'list', 'thatconsists', 'of', 'exactly', 'ten', 'words']
2335-
```
2336-
2337-
* No `AssertionError` was raised in 4th snippet because instead of asserting the individual expression `a == b`, we're asserting entire tuple. The following snippet will clear things up,
2338-
```py
2339-
>>> a = "python"
2340-
>>> b = "javascript"
2341-
>>> assert a == b
2342-
Traceback (most recent call last):
2343-
File "<stdin>", line 1, in <module>
2344-
AssertionError
2345-
2346-
>>> assert (a == b, "Values are not equal")
2347-
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
2348-
2349-
>>> assert a == b, "Values are not equal"
2350-
Traceback (most recent call last):
2351-
File "<stdin>", line 1, in <module>
2352-
AssertionError: Values aren not equal
2353-
```
2354-
2355-
* As for the last snippet, most methods that modify the items of sequence/mapping objects like `list.append`, `dict.update`, `list.sort`, etc. modify the objects in-place and return `None`. The rationale behind this is to improve performance by avoiding making a copy of the object if the operation can be done in-place (Referred from [here](http://docs.python.org/2/faq/design.html#why-doesn-t-list-sort-return-the-sorted-list)).
2356-
2357-
* Being aware of these knitpicks can save you hours of degugging effort in long run.
2358-
2359-
---
2360-
2361-
### ▶ Yielding from... return!
2362-
2363-
1\.
2364-
2365-
```py
2366-
def some_func(x):
2367-
if x == 3:
2368-
return ["wtf"]
2369-
else:
2370-
yield from range(x)
2371-
```
2372-
2373-
**Output:**
2374-
2375-
```py
2376-
>>> list(some_func(3))
2377-
[]
2378-
```
23792372
2380-
Where did the `"wtf"` go? Is it due to some special effect of `yield from`? Let's validate that,
2381-
2382-
2\.
2383-
2384-
```py
2385-
def some_func(x):
2386-
if x == 3:
2387-
return ["wtf"]
2388-
else:
2389-
for i in range(x):
2390-
yield i
2391-
```
2392-
2393-
**Output (> 3.3):**
2394-
2395-
```py
2396-
>>> list(some_func(3))
2397-
[]
2398-
```
2399-
2400-
Same result, that didn't work either.
2401-
2402-
#### 💡 Explanation:
2403-
2404-
+ From Python 3.3 onwards, it became possible to use `return` statement with values inside generators (See [PEP380](https://www.python.org/dev/peps/pep-0380/)). The [official docs](https://www.python.org/dev/peps/pep-0380/#enhancements-to-stopiteration) say that,
2405-
2406-
> "... `return expr` in a generator causes `StopIteration(expr)` to be raised upon exit from the generator."
2407-
2408-
+ In case of `some_func(3)`, `StopIteration` is raised at the beginning because of `return` statement. The `StopIteration` exception is automatically catched inside the `list(...)` wrapper and the `for` loop. Therefore, the above two snippets result in an empty list.
2409-
2410-
+ To get `["wtf"]` from the generator `some_func` we need to catch the `StopIteration` exception,
24112373
```py
2412-
try:
2413-
next(some_func(3))
2414-
except StopIteration as e:
2415-
some_string = e.value
2374+
>>> ten_words_list
2375+
['some', 'very', 'big', 'list', 'thatconsists', 'of', 'exactly', 'ten', 'words']
24162376
```
24172377
2378+
* No `AssertionError` was raised in 4th snippet because instead of asserting the individual expression `a == b`, we're asserting entire tuple. The following snippet will clear things up,
2379+
24182380
```py
2419-
>>> some_string
2420-
["wtf"]
2381+
>>> a = "python"
2382+
>>> b = "javascript"
2383+
>>> assert a == b
2384+
Traceback (most recent call last):
2385+
File "<stdin>", line 1, in <module>
2386+
AssertionError
2387+
2388+
>>> assert (a == b, "Values are not equal")
2389+
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
2390+
2391+
>>> assert a == b, "Values are not equal"
2392+
Traceback (most recent call last):
2393+
File "<stdin>", line 1, in <module>
2394+
AssertionError: Values aren not equal
24212395
```
24222396
2397+
* As for the last snippet, most methods that modify the items of sequence/mapping objects like `list.append`, `dict.update`, `list.sort`, etc. modify the objects in-place and return `None`. The rationale behind this is to improve performance by avoiding making a copy of the object if the operation can be done in-place (Referred from [here](http://docs.python.org/2/faq/design.html#why-doesn-t-list-sort-return-the-sorted-list)).
2398+
2399+
* Being aware of these knitpicks can save you hours of degugging effort in long run.
2400+
24232401
---
24242402
24252403
### ▶ Wild imports

0 commit comments

Comments
 (0)