From cbd13885fc1a7903be433277791ff9d1868be752 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Fri, 6 Aug 2021 19:51:22 -0300 Subject: [PATCH 01/66] updates to ch.14 --- 14-inheritance/README.rst | 2 +- 14-inheritance/diamond.py | 65 +++++++++++++++----- 14-inheritance/diamond2.py | 67 ++++++++++++++++++++ 14-inheritance/uppermixin.py | 115 +++++++++++++++++++++++++++++++++++ 4 files changed, 233 insertions(+), 16 deletions(-) create mode 100644 14-inheritance/diamond2.py create mode 100644 14-inheritance/uppermixin.py diff --git a/14-inheritance/README.rst b/14-inheritance/README.rst index 2f7426c..496ffb2 100644 --- a/14-inheritance/README.rst +++ b/14-inheritance/README.rst @@ -1,4 +1,4 @@ -Sample code for Chapter 14 - "Inheritance: for good or for worse" +Sample code for Chapter 14 - "Inheritance: for better or for worse" From the book "Fluent Python, Second Edition" by Luciano Ramalho (O'Reilly, 2021) https://learning.oreilly.com/library/view/fluent-python-2nd/9781492056348/ diff --git a/14-inheritance/diamond.py b/14-inheritance/diamond.py index 5aaac18..1df747b 100644 --- a/14-inheritance/diamond.py +++ b/14-inheritance/diamond.py @@ -1,27 +1,62 @@ -class A: - def ping(self): - print('ping:', self) +""" +diamond1.py: Demo of diamond-shaped class graph. +# tag::LEAF_MRO[] +>>> Leaf.__mro__ # doctest:+NORMALIZE_WHITESPACE + (, , , + , ) -class B(A): - def pong(self): - print('pong:', self) +# end::LEAF_MRO[] + +# tag::DIAMOND_CALLS[] + >>> leaf1 = Leaf() # <1> + >>> leaf1.ping() # <2> + .ping() in Leaf + .ping() in A + .ping() in B + .ping() in Root + >>> leaf1.pong() # <3> + .pong() in A + .pong() in B + +# end::DIAMOND_CALLS[] +""" + +# tag::DIAMOND_CLASSES[] +class Root: # <1> + def ping(self): + print(f'{self}.ping() in Root') -class C(A): def pong(self): - print('PONG:', self) + print(f'{self}.pong() in Root') + def __repr__(self): + cls_name = type(self).__name__ + return f'' -class D(B, C): +class A(Root): # <2> def ping(self): + print(f'{self}.ping() in A') super().ping() - print('post-ping:', self) - def pingpong(self): - self.ping() - super().ping() - self.pong() + def pong(self): + print(f'{self}.pong() in A') super().pong() - C.pong(self) + + +class B(Root): # <3> + def ping(self): + print(f'{self}.ping() in B') + super().ping() + + def pong(self): + print(f'{self}.pong() in B') + + +class Leaf(A, B): # <4> + def ping(self): + print(f'{self}.ping() in Leaf') + super().ping() +# end::DIAMOND_CLASSES[] diff --git a/14-inheritance/diamond2.py b/14-inheritance/diamond2.py new file mode 100644 index 0000000..d92db69 --- /dev/null +++ b/14-inheritance/diamond2.py @@ -0,0 +1,67 @@ +""" +unrelated.py: examples with ``super()`` in a sibling class. + +``U`` is unrelated (does not subclass ``Root``) + +Calling ``ping`` on an instance of ``U`` fails:: + +# tag::UNRELATED_DEMO_1[] + >>> u = U() + >>> u.ping() + Traceback (most recent call last): + ... + AttributeError: 'super' object has no attribute 'ping' + +# end::UNRELATED_DEMO_1[] + + +But if ``U`` is part of a cooperative arrangement of base classes, +its ``ping`` method works:: + +# tag::UNRELATED_DEMO_2[] + + >>> leaf2 = LeafUA() + >>> leaf2.ping() + .ping() in LeafUA + .ping() in U + .ping() in A + .ping() in Root + >>> LeafUA.__mro__ # doctest:+NORMALIZE_WHITESPACE + (, , + , , ) + +# end::UNRELATED_DEMO_2[] + + +Here ``U.ping`` is never called because ``Root.ping`` does not call ``super``. + + >>> o6 = LeafAU() + >>> o6.ping() + .ping() in LeafAU + .ping() in A + .ping() in Root + >>> LeafAU.__mro__ # doctest:+NORMALIZE_WHITESPACE + (, , , + , ) + +""" + +# tag::DIAMOND_CLASSES[] +from diamond import A # <1> + +class U(): # <2> + def ping(self): + print(f'{self}.ping() in U') + super().ping() # <3> + +class LeafUA(U, A): # <4> + def ping(self): + print(f'{self}.ping() in LeafUA') + super().ping() +# end::DIAMOND_CLASSES[] + +class LeafAU(A, U): + def ping(self): + print(f'{self}.ping() in LeafAU') + super().ping() + diff --git a/14-inheritance/uppermixin.py b/14-inheritance/uppermixin.py new file mode 100644 index 0000000..d86ecea --- /dev/null +++ b/14-inheritance/uppermixin.py @@ -0,0 +1,115 @@ +"""UpperDict uppercases all string keys. + +Test for initializer. `str` keys are uppercased:: + + >>> d = UpperDict([('a', 'letter A'), ('B', 'letter B'), (2, 'digit two')]) + >>> list(d.keys()) + ['A', 'B', 2] + +Tests for item retrieval using `d[key]` notation:: + + >>> d['A'] + 'letter A' + >>> d['b'] + 'letter B' + >>> d[2] + 'digit two' + + +Tests for missing key:: + + >>> d['z'] + Traceback (most recent call last): + ... + KeyError: 'Z' + >>> d[99] + Traceback (most recent call last): + ... + KeyError: 99 + + +Tests for item retrieval using `d.get(key)` notation:: + + >>> d.get('a') + 'letter A' + >>> d.get('B') + 'letter B' + >>> d.get(2) + 'digit two' + >>> d.get('z', '(not found)') + '(not found)' + +Tests for the `in` operator:: + + >>> ('a' in d, 'B' in d, 'z' in d) + (True, True, False) + +Test for item assignment using lowercase key:: + + >>> d['c'] = 'letter C' + >>> d['C'] + 'letter C' + +Tests for update using a `dict` or a sequence of pairs:: + + >>> d.update({'D': 'letter D', 'e': 'letter E'}) + >>> list(d.keys()) + ['A', 'B', 2, 'C', 'D', 'E'] + >>> d.update([('f', 'letter F'), ('G', 'letter G')]) + >>> list(d.keys()) + ['A', 'B', 2, 'C', 'D', 'E', 'F', 'G'] + >>> d # doctest:+NORMALIZE_WHITESPACE + {'A': 'letter A', 'B': 'letter B', 2: 'digit two', + 'C': 'letter C', 'D': 'letter D', 'E': 'letter E', + 'F': 'letter F', 'G': 'letter G'} + +UpperCounter uppercases all `str` keys. + +Test for initializer: keys are uppercased. + + >>> d = UpperCounter('AbracAdaBrA') + >>> sorted(d.keys()) + ['A', 'B', 'C', 'D', 'R'] + +Tests for count retrieval using `d[key]` notation:: + + >>> d['a'] + 5 + >>> d['z'] + 0 + +""" +# tag::UPPERCASE_MIXIN[] +import collections + + +def _upper(key): # <1> + try: + return key.upper() + except AttributeError: + return key + + +class UpperCaseMixin: # <2> + def __setitem__(self, key, item): + super().__setitem__(_upper(key), item) + + def __getitem__(self, key): + return super().__getitem__(_upper(key)) + + def get(self, key, default=None): + return super().get(_upper(key), default) + + def __contains__(self, key): + return super().__contains__(_upper(key)) +# end::UPPERCASE_MIXIN[] + +# tag::UPPERDICT[] +class UpperDict(UpperCaseMixin, collections.UserDict): # <1> + pass + + +class UpperCounter(UpperCaseMixin, collections.Counter): # <2> + """Specialized 'Counter' that uppercases string keys""" # <3> + +# end::UPPERDICT[] From 01e717b60a9a14bc1bca4bffd915f7ed2c637e5e Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Sat, 7 Aug 2021 00:44:01 -0300 Subject: [PATCH 02/66] updated from Atlas --- 02-array-seq/lispy/README.md | 10 ++ 04-text-byte/charfinder/README.rst | 2 +- 04-text-byte/charfinder/cf.py | 6 +- 05-data-classes/dataclass/club.py | 2 - 05-data-classes/dataclass/club_wrong.py | 1 - 05-data-classes/dataclass/hackerclub.py | 2 - .../dataclass/hackerclub_annotated.py | 2 - 05-data-classes/dataclass/resource.py | 2 +- 05-data-classes/meaning/demo_dc.py | 1 - 05-data-classes/meaning/demo_nt.py | 1 - 05-data-classes/meaning/demo_plain.py | 1 - .../typing_namedtuple/coordinates.py | 1 - .../typing_namedtuple/coordinates2.py | 3 +- .../typing_namedtuple/nocheck_demo.py | 1 - 07-1class-func/clip.py | 48 --------- 07-1class-func/clip_introspection.rst | 9 -- 07-1class-func/clip_signature.rst | 12 --- 08-def-type-hints/RPN_calc/calc.py | 67 ------------ 08-def-type-hints/RPN_calc/calc_test.py | 51 --------- 08-def-type-hints/charindex.py | 6 +- 08-def-type-hints/colors.py | 6 +- 08-def-type-hints/columnize.py | 4 +- 08-def-type-hints/columnize2.py | 35 ------ 08-def-type-hints/columnize_alias.py | 26 ----- 08-def-type-hints/comparable/top.py | 9 +- 08-def-type-hints/comparable/top_test.py | 25 +++-- 08-def-type-hints/coordinates/coordinates.py | 4 +- .../coordinates/coordinates_named.py | 13 ++- 08-def-type-hints/list.py | 10 -- .../messages/hints_1/messages.py | 11 +- .../messages/hints_1/messages_test.py | 4 +- .../messages/hints_2/messages.py | 19 ++-- .../messages/hints_2/messages_test.py | 10 +- .../messages/no_hints/messages.py | 11 +- .../messages/no_hints/messages_test.py | 2 +- 08-def-type-hints/mode/mode_T.py | 26 ----- 08-def-type-hints/mode/mode_float.py | 4 +- 08-def-type-hints/mode/mode_hashable.py | 3 +- 08-def-type-hints/mode/mode_hashable_wrong.py | 24 ----- 08-def-type-hints/mode/mode_number.py | 26 ----- .../{messages/hints_1 => }/mypy.ini | 4 +- 08-def-type-hints/passdrill.py | 101 ------------------ 08-def-type-hints/replacer.py | 4 +- 08-def-type-hints/replacer2.py | 39 ------- 08-def-type-hints/reveal_array.py | 8 -- 08-def-type-hints/sample.py | 5 +- 08-def-type-hints/typevar_bounded.py | 11 ++ 08-def-type-hints/typevars_constrained.py | 4 +- 09-closure-deco/{ => clock}/clockdeco.py | 0 09-closure-deco/{ => clock}/clockdeco0.py | 0 09-closure-deco/{ => clock}/clockdeco_cls.py | 0 09-closure-deco/{ => clock}/clockdeco_demo.py | 5 +- .../{ => clock}/clockdeco_param.py | 0 .../{ => clock}/clockdeco_param_demo1.py | 0 .../{ => clock}/clockdeco_param_demo2.py | 0 10-dp-1class-func/classic_strategy.py | 82 +++++++------- 10-dp-1class-func/classic_strategy_test.py | 44 ++++---- .../monkeytype/classic_strategy.py | 4 +- 10-dp-1class-func/promotions.py | 21 ++-- 10-dp-1class-func/pytypes/classic_strategy.py | 4 +- 10-dp-1class-func/requirements.txt | 15 +-- 10-dp-1class-func/strategy.py | 82 +++++++------- 10-dp-1class-func/strategy_best.py | 24 +++-- 10-dp-1class-func/strategy_best2.py | 99 ++++------------- 10-dp-1class-func/strategy_best3.py | 67 +++--------- 10-dp-1class-func/strategy_best4.py | 101 ++++++------------ 10-dp-1class-func/strategy_param.py | 4 +- 10-dp-1class-func/strategy_param_test.py | 2 +- 10-dp-1class-func/strategy_test.py | 45 ++++---- 10-dp-1class-func/untyped/classic_strategy.py | 4 +- 10-dp-1class-func/untyped/strategy.py | 4 +- 10-dp-1class-func/untyped/strategy_best.py | 6 +- 10-dp-1class-func/untyped/strategy_best2.py | 6 +- 10-dp-1class-func/untyped/strategy_best3.py | 6 +- 10-dp-1class-func/untyped/strategy_best4.py | 6 +- 10-dp-1class-func/untyped/strategy_param.py | 4 +- 10-dp-1class-func/untyped/strategy_param2.py | 4 +- 11-pythonic-obj/mem_test.py | 15 ++- 11-pythonic-obj/patterns.py | 53 +++++++++ 11-pythonic-obj/slots.rst | 52 +++++++++ 11-pythonic-obj/vector2d_v3.py | 4 +- 11-pythonic-obj/vector2d_v3_prophash.py | 4 +- 11-pythonic-obj/vector2d_v3_slots.py | 7 +- 12-seq-hacking/vector_v3.py | 20 ++-- 12-seq-hacking/vector_v4.py | 12 ++- 12-seq-hacking/vector_v5.py | 12 ++- 13-protocol-abc/frenchdeck2.py | 6 +- 13-protocol-abc/typing/randompick_test.py | 8 +- 13-protocol-abc/typing/vector2d_v4.py | 2 +- 13-protocol-abc/typing/vector2d_v5.py | 2 +- 14-inheritance/uppermixin.py | 41 +++++-- 15-more-types/protocol/abs_demo.py | 2 + 16-op-overloading/vector2d_v3.py | 8 +- 16-op-overloading/vector_v6.py | 12 ++- 16-op-overloading/vector_v7.py | 12 ++- 16-op-overloading/vector_v8.py | 12 ++- 96 files changed, 579 insertions(+), 1020 deletions(-) delete mode 100644 07-1class-func/clip.py delete mode 100644 07-1class-func/clip_introspection.rst delete mode 100644 07-1class-func/clip_signature.rst delete mode 100755 08-def-type-hints/RPN_calc/calc.py delete mode 100644 08-def-type-hints/RPN_calc/calc_test.py delete mode 100644 08-def-type-hints/columnize2.py delete mode 100644 08-def-type-hints/columnize_alias.py delete mode 100644 08-def-type-hints/list.py delete mode 100644 08-def-type-hints/mode/mode_T.py delete mode 100644 08-def-type-hints/mode/mode_hashable_wrong.py delete mode 100644 08-def-type-hints/mode/mode_number.py rename 08-def-type-hints/{messages/hints_1 => }/mypy.ini (50%) delete mode 100755 08-def-type-hints/passdrill.py delete mode 100644 08-def-type-hints/replacer2.py delete mode 100644 08-def-type-hints/reveal_array.py create mode 100644 08-def-type-hints/typevar_bounded.py rename 09-closure-deco/{ => clock}/clockdeco.py (100%) rename 09-closure-deco/{ => clock}/clockdeco0.py (100%) rename 09-closure-deco/{ => clock}/clockdeco_cls.py (100%) rename 09-closure-deco/{ => clock}/clockdeco_demo.py (90%) rename 09-closure-deco/{ => clock}/clockdeco_param.py (100%) rename 09-closure-deco/{ => clock}/clockdeco_param_demo1.py (100%) rename 09-closure-deco/{ => clock}/clockdeco_param_demo2.py (100%) create mode 100644 11-pythonic-obj/patterns.py create mode 100644 11-pythonic-obj/slots.rst diff --git a/02-array-seq/lispy/README.md b/02-array-seq/lispy/README.md index 9ac6f56..38458bb 100644 --- a/02-array-seq/lispy/README.md +++ b/02-array-seq/lispy/README.md @@ -23,4 +23,14 @@ The copyright holder is Peter Norvig and the code is licensed under the [MIT license](https://github.com/norvig/pytudes/blob/60168bce8cdfacf57c92a5b2979f0b2e95367753/LICENSE). +## Changes to Norvig's code + +I made small changes to the programs in `original/`: + +* In `lis.py`: + * The `Procedure` class accepts a list of expressions as the `body`, and `__call__` evaluates those expressions in order, and returns the value of the last. This is consistent with Scheme's `lambda` syntax and provided a useful example for pattern matching. + * In the `elif` block for `'lambda'`, I added the `*` in front of the `*body` variable in the tuple unpacking to capture the expressions as a list, before calling the `Procedure` constructor. + +* In `lispy.py` I made [changes and a pull request](https://github.com/norvig/pytudes/pull/106) to make it run on Python 3. + _Luciano Ramalho
June 29, 2021_ diff --git a/04-text-byte/charfinder/README.rst b/04-text-byte/charfinder/README.rst index 46a5d70..15a613d 100644 --- a/04-text-byte/charfinder/README.rst +++ b/04-text-byte/charfinder/README.rst @@ -58,7 +58,7 @@ Test ``find`` with single result:: Test ``find`` with two results:: - >>> find('chess', 'queen', last=0xFFFF) # doctest:+NORMALIZE_WHITESPACE + >>> find('chess', 'queen', end=0xFFFF) # doctest:+NORMALIZE_WHITESPACE U+2655 ♕ WHITE CHESS QUEEN U+265B ♛ BLACK CHESS QUEEN diff --git a/04-text-byte/charfinder/cf.py b/04-text-byte/charfinder/cf.py index 28f20d0..db982bc 100755 --- a/04-text-byte/charfinder/cf.py +++ b/04-text-byte/charfinder/cf.py @@ -2,11 +2,11 @@ import sys import unicodedata -FIRST, LAST = ord(' '), sys.maxunicode # <1> +START, END = ord(' '), sys.maxunicode + 1 # <1> -def find(*query_words, first=FIRST, last=LAST): # <2> +def find(*query_words, start=START, end=END): # <2> query = {w.upper() for w in query_words} # <3> - for code in range(first, last + 1): + for code in range(start, end): char = chr(code) # <4> name = unicodedata.name(char, None) # <5> if name and query.issubset(name.split()): # <6> diff --git a/05-data-classes/dataclass/club.py b/05-data-classes/dataclass/club.py index cd8ff46..7af49c8 100644 --- a/05-data-classes/dataclass/club.py +++ b/05-data-classes/dataclass/club.py @@ -1,9 +1,7 @@ from dataclasses import dataclass, field - @dataclass class ClubMember: - name: str guests: list = field(default_factory=list) diff --git a/05-data-classes/dataclass/club_wrong.py b/05-data-classes/dataclass/club_wrong.py index 3d73d6a..8521a9d 100644 --- a/05-data-classes/dataclass/club_wrong.py +++ b/05-data-classes/dataclass/club_wrong.py @@ -3,7 +3,6 @@ # tag::CLUBMEMBER[] @dataclass class ClubMember: - name: str guests: list = [] # end::CLUBMEMBER[] diff --git a/05-data-classes/dataclass/hackerclub.py b/05-data-classes/dataclass/hackerclub.py index 4d9112e..762c2cd 100644 --- a/05-data-classes/dataclass/hackerclub.py +++ b/05-data-classes/dataclass/hackerclub.py @@ -34,9 +34,7 @@ @dataclass class HackerClubMember(ClubMember): # <1> - all_handles = set() # <2> - handle: str = '' # <3> def __post_init__(self): diff --git a/05-data-classes/dataclass/hackerclub_annotated.py b/05-data-classes/dataclass/hackerclub_annotated.py index 5cf90fc..2394796 100644 --- a/05-data-classes/dataclass/hackerclub_annotated.py +++ b/05-data-classes/dataclass/hackerclub_annotated.py @@ -35,9 +35,7 @@ @dataclass class HackerClubMember(ClubMember): - all_handles: ClassVar[set[str]] = set() - handle: str = '' def __post_init__(self): diff --git a/05-data-classes/dataclass/resource.py b/05-data-classes/dataclass/resource.py index 5190055..f332a11 100644 --- a/05-data-classes/dataclass/resource.py +++ b/05-data-classes/dataclass/resource.py @@ -32,7 +32,7 @@ from datetime import date -class ResourceType(Enum): # <1> +class ResourceType(Enum): # <1> BOOK = auto() EBOOK = auto() VIDEO = auto() diff --git a/05-data-classes/meaning/demo_dc.py b/05-data-classes/meaning/demo_dc.py index 3cc45ce..fa45bb8 100644 --- a/05-data-classes/meaning/demo_dc.py +++ b/05-data-classes/meaning/demo_dc.py @@ -2,7 +2,6 @@ @dataclass class DemoDataClass: - a: int # <1> b: float = 1.1 # <2> c = 'spam' # <3> diff --git a/05-data-classes/meaning/demo_nt.py b/05-data-classes/meaning/demo_nt.py index 317fb82..8f52354 100644 --- a/05-data-classes/meaning/demo_nt.py +++ b/05-data-classes/meaning/demo_nt.py @@ -1,7 +1,6 @@ import typing class DemoNTClass(typing.NamedTuple): - a: int # <1> b: float = 1.1 # <2> c = 'spam' # <3> diff --git a/05-data-classes/meaning/demo_plain.py b/05-data-classes/meaning/demo_plain.py index 6376959..98c3e40 100644 --- a/05-data-classes/meaning/demo_plain.py +++ b/05-data-classes/meaning/demo_plain.py @@ -1,5 +1,4 @@ class DemoPlainClass: - a: int # <1> b: float = 1.1 # <2> c = 'spam' # <3> diff --git a/05-data-classes/typing_namedtuple/coordinates.py b/05-data-classes/typing_namedtuple/coordinates.py index 378a430..5e4d879 100644 --- a/05-data-classes/typing_namedtuple/coordinates.py +++ b/05-data-classes/typing_namedtuple/coordinates.py @@ -11,7 +11,6 @@ from typing import NamedTuple class Coordinate(NamedTuple): - lat: float lon: float diff --git a/05-data-classes/typing_namedtuple/coordinates2.py b/05-data-classes/typing_namedtuple/coordinates2.py index 2032311..efcd6be 100644 --- a/05-data-classes/typing_namedtuple/coordinates2.py +++ b/05-data-classes/typing_namedtuple/coordinates2.py @@ -13,8 +13,7 @@ from typing import NamedTuple class Coordinate(NamedTuple): - lat: float # <1> lon: float reference: str = 'WGS84' # <2> -# end::COORDINATE[] \ No newline at end of file +# end::COORDINATE[] diff --git a/05-data-classes/typing_namedtuple/nocheck_demo.py b/05-data-classes/typing_namedtuple/nocheck_demo.py index 8ca5dc1..43c1b96 100644 --- a/05-data-classes/typing_namedtuple/nocheck_demo.py +++ b/05-data-classes/typing_namedtuple/nocheck_demo.py @@ -1,7 +1,6 @@ import typing class Coordinate(typing.NamedTuple): - lat: float lon: float diff --git a/07-1class-func/clip.py b/07-1class-func/clip.py deleted file mode 100644 index 2f97c66..0000000 --- a/07-1class-func/clip.py +++ /dev/null @@ -1,48 +0,0 @@ -""" - >>> clip('banana split', 5) - 'banana' - >>> clip('banana split', 6) - 'banana' - >>> clip('banana split', 7) - 'banana' - >>> clip('banana split', 8) - 'banana' - >>> clip('banana split', 11) - 'banana' - >>> clip('banana split', 12) - 'banana split' - >>> clip('banana-split', 3) - 'banana-split' - -Jess' tests: - - >>> text = 'The quick brown fox jumps over the lazy dog.' - >>> clip14 = clip(text, max_len=14) - >>> clip14 - 'The quick' - >>> len(clip14) - 9 - >>> clip15 = clip(text, max_len=15) - >>> clip15 - 'The quick brown' - >>> len(clip15) - 15 - -""" - -# tag::CLIP[] -def clip(text, max_len=80): - """Return max_len characters clipped at space if possible""" - text = text.rstrip() - if len(text) <= max_len or ' ' not in text: - return text - end = len(text) - space_at = text.rfind(' ', 0, max_len + 1) - if space_at >= 0: - end = space_at - else: - space_at = text.find(' ', max_len) - if space_at >= 0: - end = space_at - return text[:end].rstrip() -# end::CLIP[] diff --git a/07-1class-func/clip_introspection.rst b/07-1class-func/clip_introspection.rst deleted file mode 100644 index 0b4334d..0000000 --- a/07-1class-func/clip_introspection.rst +++ /dev/null @@ -1,9 +0,0 @@ ->>> from clip import clip ->>> clip.__defaults__ -(80,) ->>> clip.__code__ # doctest: +ELLIPSIS - ->>> clip.__code__.co_varnames -('text', 'max_len', 'end', 'space_at') ->>> clip.__code__.co_argcount -2 diff --git a/07-1class-func/clip_signature.rst b/07-1class-func/clip_signature.rst deleted file mode 100644 index 9bc2dee..0000000 --- a/07-1class-func/clip_signature.rst +++ /dev/null @@ -1,12 +0,0 @@ ->>> from clip import clip ->>> from inspect import signature ->>> sig = signature(clip) ->>> sig - ->>> str(sig) -'(text, max_len=80)' ->>> for name, param in sig.parameters.items(): -... print(param.kind, ':', name, '=', param.default) -... -POSITIONAL_OR_KEYWORD : text = -POSITIONAL_OR_KEYWORD : max_len = 80 diff --git a/08-def-type-hints/RPN_calc/calc.py b/08-def-type-hints/RPN_calc/calc.py deleted file mode 100755 index 967b094..0000000 --- a/08-def-type-hints/RPN_calc/calc.py +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env python3 - -import sys -from array import array -from typing import Mapping, MutableSequence, Callable, Iterable, Union, Any - - -OPERATORS: Mapping[str, Callable[[float, float], float]] = { - '+': lambda a, b: a + b, - '-': lambda a, b: a - b, - '*': lambda a, b: a * b, - '/': lambda a, b: a / b, - '^': lambda a, b: a ** b, -} - - -Stack = MutableSequence[float] - - -def parse_token(token: str) -> Union[str, float]: - try: - return float(token) - except ValueError: - return token - - -def evaluate(tokens: Iterable[str], stack: Stack) -> None: - for token in tokens: - atom = parse_token(token) - if isinstance(atom, float): - stack.append(atom) - else: # not float, must be operator - op = OPERATORS[atom] - x, y = stack.pop(), stack.pop() - result = op(y, x) - stack.append(result) - - -def display(s: Stack) -> str: - items = (repr(n) for n in s) - return ' │ '.join(items) + ' →' - - -def repl(input_fn: Callable[[Any], str] = input) -> None: - """Read-Eval-Print-Loop""" - - print('Use CTRL+C to quit.', file=sys.stderr) - stack: Stack = array('d') - - while True: - try: - line = input_fn('> ') # Read - except (EOFError, KeyboardInterrupt): - break - try: - evaluate(line.split(), stack) # Eval - except IndexError: - print('*** Not enough arguments.', file=sys.stderr) - except KeyError as exc: - print('*** Unknown operator:', exc.args[0], file=sys.stderr) - print(display(stack)) # Print - - print() - - -if __name__ == '__main__': - repl() diff --git a/08-def-type-hints/RPN_calc/calc_test.py b/08-def-type-hints/RPN_calc/calc_test.py deleted file mode 100644 index c2d144c..0000000 --- a/08-def-type-hints/RPN_calc/calc_test.py +++ /dev/null @@ -1,51 +0,0 @@ -from pytest import mark, approx # type: ignore - -from dialogue import Dialogue # type: ignore - -from calc import evaluate, repl, display, Stack - -TOLERANCE = .0001 - -@mark.parametrize("source, want", [ - ('2', 2), - ('2 3 +', 5), - ('5 3 -', 2), - ('3 5 * 2 +', 17), - ('2 3 4 5 * * *', 120), - ('1.1 1.1 1.1 + +', approx(3.3, TOLERANCE)), - ('100 32 - 5 * 9 /', approx(37.78, TOLERANCE)), -]) -def test_evaluate(source, want) -> None: - stack: Stack = [] - evaluate(source.split(), stack) - assert want == stack[-1] - - -@mark.parametrize("value, want", [ - ([], ' →'), - ([3.], '3.0 →'), - ([3., 4., 5.], '3.0 │ 4.0 │ 5.0 →'), -]) -def test_display(value, want) -> None: - assert want == display(value) - - -@mark.parametrize("session", [ - """ - > 3 - 3.0 → - """, - """ - > 3 5 6 - 3.0 │ 5.0 │ 6.0 → - > * - 3.0 │ 30.0 → - > - - -27.0 → - """, -]) -def test_repl(capsys, session) -> None: - dlg = Dialogue(session) - repl(dlg.fake_input) - captured = capsys.readouterr() - assert dlg.session.strip() == captured.out.strip() diff --git a/08-def-type-hints/charindex.py b/08-def-type-hints/charindex.py index 36d20e3..c368c37 100644 --- a/08-def-type-hints/charindex.py +++ b/08-def-type-hints/charindex.py @@ -15,7 +15,7 @@ import sys import re import unicodedata -from typing import Dict, Set, Iterator +from collections.abc import Iterator RE_WORD = re.compile(r'\w+') STOP_CODE = sys.maxunicode + 1 @@ -25,8 +25,8 @@ def tokenize(text: str) -> Iterator[str]: # <1> for match in RE_WORD.finditer(text): yield match.group().upper() -def name_index(start: int = 32, end: int = STOP_CODE) -> Dict[str, Set[str]]: - index: Dict[str, Set[str]] = {} # <2> +def name_index(start: int = 32, end: int = STOP_CODE) -> dict[str, set[str]]: + index: dict[str, set[str]] = {} # <2> for char in (chr(i) for i in range(start, end)): if name := unicodedata.name(char, ''): # <3> for word in tokenize(name): diff --git a/08-def-type-hints/colors.py b/08-def-type-hints/colors.py index b57413c..c0d0665 100644 --- a/08-def-type-hints/colors.py +++ b/08-def-type-hints/colors.py @@ -1,4 +1,4 @@ -from typing import Tuple, Mapping +from collections.abc import Mapping NAMES = { 'aqua': 65535, @@ -19,7 +19,7 @@ 'yellow': 16776960, } -def rgb2hex(color=Tuple[int, int, int]) -> str: +def rgb2hex(color: tuple[int, int, int]) -> str: if any(c not in range(256) for c in color): raise ValueError('Color components must be in range(256)') values = (f'{n % 256:02x}' for n in color) @@ -27,7 +27,7 @@ def rgb2hex(color=Tuple[int, int, int]) -> str: HEX_ERROR = "Color must use format '#0099ff', got: {!r}" -def hex2rgb(color=str) -> Tuple[int, int, int]: +def hex2rgb(color: str) -> tuple[int, int, int]: if len(color) != 7 or color[0] != '#': raise ValueError(HEX_ERROR.format(color)) try: diff --git a/08-def-type-hints/columnize.py b/08-def-type-hints/columnize.py index ef995ae..66b72d8 100644 --- a/08-def-type-hints/columnize.py +++ b/08-def-type-hints/columnize.py @@ -1,7 +1,7 @@ # tag::COLUMNIZE[] -from typing import Sequence, List, Tuple +from collections.abc import Sequence -def columnize(sequence: Sequence[str], num_columns: int = 0) -> List[Tuple[str, ...]]: +def columnize(sequence: Sequence[str], num_columns: int = 0) -> list[tuple[str, ...]]: if num_columns == 0: num_columns = round(len(sequence) ** .5) num_rows, reminder = divmod(len(sequence), num_columns) diff --git a/08-def-type-hints/columnize2.py b/08-def-type-hints/columnize2.py deleted file mode 100644 index 2524fd3..0000000 --- a/08-def-type-hints/columnize2.py +++ /dev/null @@ -1,35 +0,0 @@ -from typing import Sequence, List, Tuple, TypeVar - -T = TypeVar('T') - -def columnize(sequence: Sequence[T], num_columns: int = 0) -> List[Tuple[T, ...]]: - if num_columns == 0: - num_columns = round(len(sequence) ** .5) - num_rows, reminder = divmod(len(sequence), num_columns) - num_rows += bool(reminder) - return [tuple(sequence[i::num_rows]) for i in range(num_rows)] - - -def demo() -> None: - nato = ('Alfa Bravo Charlie Delta Echo Foxtrot Golf Hotel India' - ' Juliett Kilo Lima Mike November Oscar Papa Quebec Romeo' - ' Sierra Tango Uniform Victor Whiskey X-ray Yankee Zulu' - ).split() - - for line in columnize(nato): - for word in line: - print(f'{word:15}', end='') - print() - - print() - for length in range(2, 21, 6): - values = list(range(1, length + 1)) - for row in columnize(values): - for cell in row: - print(f'{cell:5}', end='') - print() - print() - - -if __name__ == '__main__': - demo() diff --git a/08-def-type-hints/columnize_alias.py b/08-def-type-hints/columnize_alias.py deleted file mode 100644 index b783469..0000000 --- a/08-def-type-hints/columnize_alias.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Sequence, List, Tuple - -Row = Tuple[str, ...] - -def columnize(sequence: Sequence[str], num_columns: int) -> List[Row]: - if num_columns == 0: - num_columns = round(len(sequence) ** .5) - num_rows, reminder = divmod(len(sequence), num_columns) - num_rows += bool(reminder) - return [tuple(sequence[i::num_rows]) for i in range(num_rows)] - - -def demo() -> None: - nato = ('Alfa Bravo Charlie Delta Echo Foxtrot Golf Hotel India' - ' Juliett Kilo Lima Mike November Oscar Papa Quebec Romeo' - ' Sierra Tango Uniform Victor Whiskey X-ray Yankee Zulu' - ).split() - - for row in columnize(nato, 4): - for word in row: - print(f'{word:15}', end='') - print() - - -if __name__ == '__main__': - demo() diff --git a/08-def-type-hints/comparable/top.py b/08-def-type-hints/comparable/top.py index c552890..2851f62 100644 --- a/08-def-type-hints/comparable/top.py +++ b/08-def-type-hints/comparable/top.py @@ -20,11 +20,14 @@ """ # tag::TOP[] -from typing import TypeVar, Iterable, List +from collections.abc import Iterable +from typing import TypeVar + from comparable import SupportsLessThan LT = TypeVar('LT', bound=SupportsLessThan) -def top(series: Iterable[LT], length: int) -> List[LT]: - return sorted(series, reverse=True)[:length] +def top(series: Iterable[LT], length: int) -> list[LT]: + ordered = sorted(series, reverse=True) + return ordered[:length] # end::TOP[] diff --git a/08-def-type-hints/comparable/top_test.py b/08-def-type-hints/comparable/top_test.py index baff36b..c8c39ac 100644 --- a/08-def-type-hints/comparable/top_test.py +++ b/08-def-type-hints/comparable/top_test.py @@ -1,6 +1,11 @@ -from typing import Tuple, List, Iterator, TYPE_CHECKING -import pytest # type: ignore +# tag::TOP_IMPORT[] +from collections.abc import Iterator +from typing import TYPE_CHECKING # <1> + +import pytest + from top import top +# end::TOP_IMPORT[] @pytest.mark.parametrize('series, length, expected', [ ((1, 2, 3), 2, [3, 2]), @@ -8,9 +13,9 @@ ((3, 3, 3), 1, [3]), ]) def test_top( - series: Tuple[float, ...], + series: tuple[float, ...], length: int, - expected: List[float], + expected: list[float], ) -> None: result = top(series, length) assert expected == result @@ -18,13 +23,13 @@ def test_top( # tag::TOP_TEST[] def test_top_tuples() -> None: fruit = 'mango pear apple kiwi banana'.split() - series: Iterator[Tuple[int, str]] = ( + series: Iterator[tuple[int, str]] = ( # <2> (len(s), s) for s in fruit) length = 3 expected = [(6, 'banana'), (5, 'mango'), (5, 'apple')] result = top(series, length) - if TYPE_CHECKING: - reveal_type(series) + if TYPE_CHECKING: # <3> + reveal_type(series) # <4> reveal_type(expected) reveal_type(result) assert result == expected @@ -34,7 +39,7 @@ def test_top_objects_error() -> None: series = [object() for _ in range(4)] if TYPE_CHECKING: reveal_type(series) - with pytest.raises(TypeError) as exc: - top(series, 3) - assert "'<' not supported" in str(exc) + with pytest.raises(TypeError) as excinfo: + top(series, 3) # <5> + assert "'<' not supported" in str(excinfo.value) # end::TOP_TEST[] diff --git a/08-def-type-hints/coordinates/coordinates.py b/08-def-type-hints/coordinates/coordinates.py index d48b390..fb594eb 100644 --- a/08-def-type-hints/coordinates/coordinates.py +++ b/08-def-type-hints/coordinates/coordinates.py @@ -8,10 +8,10 @@ """ # tag::GEOHASH[] -from geolib import geohash as gh # type: ignore +from geolib import geohash as gh # type: ignore # <1> PRECISION = 9 -def geohash(lat_lon: tuple[float, float]) -> str: +def geohash(lat_lon: tuple[float, float]) -> str: # <2> return gh.encode(*lat_lon, PRECISION) # end::GEOHASH[] diff --git a/08-def-type-hints/coordinates/coordinates_named.py b/08-def-type-hints/coordinates/coordinates_named.py index 87cac72..76bd9bb 100644 --- a/08-def-type-hints/coordinates/coordinates_named.py +++ b/08-def-type-hints/coordinates/coordinates_named.py @@ -9,7 +9,7 @@ """ # tag::GEOHASH[] -from typing import Tuple, NamedTuple +from typing import NamedTuple from geolib import geohash as gh # type: ignore @@ -21,16 +21,21 @@ class Coordinate(NamedTuple): def geohash(lat_lon: Coordinate) -> str: return gh.encode(*lat_lon, PRECISION) +# end::GEOHASH[] -def display(lat_lon: Tuple[float, float]) -> str: +# tag::DISPLAY[] +def display(lat_lon: tuple[float, float]) -> str: lat, lon = lat_lon ns = 'N' if lat >= 0 else 'S' ew = 'E' if lon >= 0 else 'W' return f'{abs(lat):0.1f}°{ns}, {abs(lon):0.1f}°{ew}' - -# end::GEOHASH[] +# end::DISPLAY[] def demo(): shanghai = 31.2304, 121.4737 + print(display(shanghai)) s = geohash(shanghai) print(s) + +if __name__ == '__main__': + demo() diff --git a/08-def-type-hints/list.py b/08-def-type-hints/list.py deleted file mode 100644 index 6d122e7..0000000 --- a/08-def-type-hints/list.py +++ /dev/null @@ -1,10 +0,0 @@ -from typing import List, Tuple - -def tokenize(text: str) -> List[str]: - return text.upper().split() - -l: List[str] = [] -l.append(1) -print(l) - -t: Tuple[str, float] = ('São Paulo', 12_176_866) diff --git a/08-def-type-hints/messages/hints_1/messages.py b/08-def-type-hints/messages/hints_1/messages.py index c00e706..59b432e 100644 --- a/08-def-type-hints/messages/hints_1/messages.py +++ b/08-def-type-hints/messages/hints_1/messages.py @@ -5,16 +5,15 @@ >>> show_count(1, 'bird') '1 bird' >>> show_count(0, 'bird') -'no bird' +'no birds' # end::SHOW_COUNT_DOCTEST[] """ # tag::SHOW_COUNT[] def show_count(count: int, word: str) -> str: - if count == 0: - return f'no {word}' - elif count == 1: - return f'{count} {word}' - return f'{count} {word}s' + if count == 1: + return f'1 {word}' + count_str = str(count) if count else 'no' + return f'{count_str} {word}s' # end::SHOW_COUNT[] diff --git a/08-def-type-hints/messages/hints_1/messages_test.py b/08-def-type-hints/messages/hints_1/messages_test.py index 2a16f25..3688da1 100644 --- a/08-def-type-hints/messages/hints_1/messages_test.py +++ b/08-def-type-hints/messages/hints_1/messages_test.py @@ -7,11 +7,11 @@ (1, '1 part'), (2, '2 parts'), ]) -def test_show_count(qty, expected): +def test_show_count(qty: int, expected: str) -> None: got = show_count(qty, 'part') assert got == expected def test_show_count_zero(): got = show_count(0, 'part') - assert got == 'no part' + assert got == 'no parts' diff --git a/08-def-type-hints/messages/hints_2/messages.py b/08-def-type-hints/messages/hints_2/messages.py index c43d85f..fd2a331 100644 --- a/08-def-type-hints/messages/hints_2/messages.py +++ b/08-def-type-hints/messages/hints_2/messages.py @@ -4,21 +4,22 @@ >>> show_count(1, 'bird') '1 bird' >>> show_count(0, 'bird') -'no bird' +'no birds' >>> show_count(3, 'virus', 'viruses') '3 viruses' +>>> show_count(1, 'virus', 'viruses') +'1 virus' +>>> show_count(0, 'virus', 'viruses') +'no viruses' """ # tag::SHOW_COUNT[] def show_count(count: int, singular: str, plural: str = '') -> str: - if count == 0: - return f'no {singular}' - elif count == 1: + if count == 1: return f'1 {singular}' - else: - if plural: - return f'{count} {plural}' - else: - return f'{count} {singular}s' + count_str = str(count) if count else 'no' + if not plural: + plural = singular + 's' + return f'{count_str} {plural}' # end::SHOW_COUNT[] diff --git a/08-def-type-hints/messages/hints_2/messages_test.py b/08-def-type-hints/messages/hints_2/messages_test.py index f7b2fe1..2678d9b 100644 --- a/08-def-type-hints/messages/hints_2/messages_test.py +++ b/08-def-type-hints/messages/hints_2/messages_test.py @@ -1,4 +1,4 @@ -from pytest import mark # type: ignore +from pytest import mark from messages import show_count @@ -6,9 +6,9 @@ @mark.parametrize('qty, expected', [ (1, '1 part'), (2, '2 parts'), - (0, 'no part'), + (0, 'no parts'), ]) -def test_show_count(qty, expected): +def test_show_count(qty: int, expected: str) -> None: got = show_count(qty, 'part') assert got == expected @@ -17,9 +17,9 @@ def test_show_count(qty, expected): @mark.parametrize('qty, expected', [ (1, '1 child'), (2, '2 children'), - (0, 'no child'), + (0, 'no children'), ]) -def test_irregular(qty, expected) -> None: +def test_irregular(qty: int, expected: str) -> None: got = show_count(qty, 'child', 'children') assert got == expected # end::TEST_IRREGULAR[] diff --git a/08-def-type-hints/messages/no_hints/messages.py b/08-def-type-hints/messages/no_hints/messages.py index d7898c5..df037e7 100644 --- a/08-def-type-hints/messages/no_hints/messages.py +++ b/08-def-type-hints/messages/no_hints/messages.py @@ -5,16 +5,15 @@ >>> show_count(1, 'bird') '1 bird' >>> show_count(0, 'bird') -'no bird' +'no birds' # end::SHOW_COUNT_DOCTEST[] """ # tag::SHOW_COUNT[] def show_count(count, word): - if count == 0: - return f'no {word}' - elif count == 1: - return f'{count} {word}' - return f'{count} {word}s' + if count == 1: + return f'1 {word}' + count_str = str(count) if count else 'no' + return f'{count_str} {word}s' # end::SHOW_COUNT[] diff --git a/08-def-type-hints/messages/no_hints/messages_test.py b/08-def-type-hints/messages/no_hints/messages_test.py index a8ec100..09532d3 100644 --- a/08-def-type-hints/messages/no_hints/messages_test.py +++ b/08-def-type-hints/messages/no_hints/messages_test.py @@ -12,4 +12,4 @@ def test_show_count(qty, expected): def test_show_count_zero(): got = show_count(0, 'part') - assert got == 'no part' + assert got == 'no parts' diff --git a/08-def-type-hints/mode/mode_T.py b/08-def-type-hints/mode/mode_T.py deleted file mode 100644 index cf88bbb..0000000 --- a/08-def-type-hints/mode/mode_T.py +++ /dev/null @@ -1,26 +0,0 @@ -from collections import Counter -from typing import Iterable, TypeVar - -T = TypeVar('T') - -def mode(data: Iterable[T]) -> T: - data = iter(data) - pairs = Counter(data).most_common(1) - if len(pairs) == 0: - raise ValueError('no mode for empty data') - return pairs[0][0] - - -def demo() -> None: - from typing import TYPE_CHECKING - pop: list[set] = [set(), set()] - m = mode(pop) - if TYPE_CHECKING: - reveal_type(pop) - reveal_type(m) - print(pop) - print(repr(m), type(m)) - - -if __name__ == '__main__': - demo() diff --git a/08-def-type-hints/mode/mode_float.py b/08-def-type-hints/mode/mode_float.py index 0684202..79308be 100644 --- a/08-def-type-hints/mode/mode_float.py +++ b/08-def-type-hints/mode/mode_float.py @@ -1,6 +1,6 @@ # tag::MODE_FLOAT[] from collections import Counter -from typing import Iterable +from collections.abc import Iterable def mode(data: Iterable[float]) -> float: pairs = Counter(data).most_common(1) @@ -20,4 +20,4 @@ def demo() -> None: print(repr(m), type(m)) if __name__ == '__main__': - demo() \ No newline at end of file + demo() diff --git a/08-def-type-hints/mode/mode_hashable.py b/08-def-type-hints/mode/mode_hashable.py index aa7f313..57c3a30 100644 --- a/08-def-type-hints/mode/mode_hashable.py +++ b/08-def-type-hints/mode/mode_hashable.py @@ -1,6 +1,7 @@ # tag::MODE_HASHABLE_T[] from collections import Counter -from typing import Iterable, Hashable, TypeVar +from collections.abc import Iterable, Hashable +from typing import TypeVar HashableT = TypeVar('HashableT', bound=Hashable) diff --git a/08-def-type-hints/mode/mode_hashable_wrong.py b/08-def-type-hints/mode/mode_hashable_wrong.py deleted file mode 100644 index ff770a7..0000000 --- a/08-def-type-hints/mode/mode_hashable_wrong.py +++ /dev/null @@ -1,24 +0,0 @@ -# tag::MODE_FLOAT[] -from collections import Counter -from typing import Iterable, Hashable - -def mode(data: Iterable[Hashable]) -> Hashable: - data = iter(data) - pairs = Counter(data).most_common(1) - if len(pairs) == 0: - raise ValueError('no mode for empty data') - return pairs[0][0] -# end::MODE_FLOAT[] - -def demo() -> None: - import typing - pop = 'abracadabra' - m = mode(pop) - if typing.TYPE_CHECKING: - reveal_type(pop) - reveal_type(m) - print(pop) - print(m.upper(), type(m)) - -if __name__ == '__main__': - demo() \ No newline at end of file diff --git a/08-def-type-hints/mode/mode_number.py b/08-def-type-hints/mode/mode_number.py deleted file mode 100644 index 999387f..0000000 --- a/08-def-type-hints/mode/mode_number.py +++ /dev/null @@ -1,26 +0,0 @@ -from collections import Counter -from typing import Iterable, TypeVar -from decimal import Decimal -from fractions import Fraction - -NumberT = TypeVar('NumberT', float, Decimal, Fraction) - -def mode(data: Iterable[NumberT]) -> NumberT: - pairs = Counter(data).most_common(1) - if len(pairs) == 0: - raise ValueError('no mode for empty data') - return pairs[0][0] - - -def demo() -> None: - from typing import TYPE_CHECKING - pop = [Fraction(1, 2), Fraction(1, 3), Fraction(1, 4), Fraction(1, 2)] - m = mode(pop) - if TYPE_CHECKING: - reveal_type(pop) - reveal_type(m) - print(pop) - print(repr(m), type(m)) - -if __name__ == '__main__': - demo() \ No newline at end of file diff --git a/08-def-type-hints/messages/hints_1/mypy.ini b/08-def-type-hints/mypy.ini similarity index 50% rename from 08-def-type-hints/messages/hints_1/mypy.ini rename to 08-def-type-hints/mypy.ini index f658867..ab42819 100644 --- a/08-def-type-hints/messages/hints_1/mypy.ini +++ b/08-def-type-hints/mypy.ini @@ -1,6 +1,4 @@ [mypy] -python_version = 3.8 +python_version = 3.9 warn_unused_configs = True disallow_incomplete_defs = True -[mypy-pytest] -ignore_missing_imports = True diff --git a/08-def-type-hints/passdrill.py b/08-def-type-hints/passdrill.py deleted file mode 100755 index 83b1be1..0000000 --- a/08-def-type-hints/passdrill.py +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env python3 - -"""passdrill: typing drills for practicing passphrases -""" - -import os -import sys -from base64 import b64encode, b64decode -from getpass import getpass -from hashlib import scrypt -from typing import Sequence, Tuple - -HASH_FILENAME = 'passdrill.hash' -HELP = 'Use -s to save passphrase hash for practice.' - - -def prompt() -> str: - print('WARNING: the passphrase WILL BE SHOWN so that you can check it!') - confirmed = '' - while confirmed != 'y': - passphrase = input('Type passphrase to hash (it will be echoed): ') - if passphrase in ('', 'q'): - print('ERROR: the passphrase cannot be empty or "q".') - continue - print(f'Passphrase to be hashed -> {passphrase}') - confirmed = input('Confirm (y/n): ').lower() - return passphrase - - -def crypto_hash(salt: bytes, passphrase: str) -> bytes: - octets = passphrase.encode('utf-8') - # Recommended parameters for interactive logins as of 2017: - # N=32768, r=8 and p=1 (https://godoc.org/golang.org/x/crypto/scrypt) - return scrypt(octets, salt=salt, n=32768, r=8, p=1, maxmem=2 ** 26) - - -def build_hash(passphrase: str) -> bytes: - salt = os.urandom(32) - payload = crypto_hash(salt, passphrase) - return b64encode(salt) + b':' + b64encode(payload) - - -def save_hash() -> None: - salted_hash = build_hash(prompt()) - with open(HASH_FILENAME, 'wb') as fp: - fp.write(salted_hash) - print(f'Passphrase hash saved to {HASH_FILENAME}') - - -def load_hash() -> Tuple[bytes, bytes]: - try: - with open(HASH_FILENAME, 'rb') as fp: - salted_hash = fp.read() - except FileNotFoundError: - print('ERROR: passphrase hash file not found.', HELP) - # "standard" exit status codes: - # https://stackoverflow.com/questions/1101957/are-there-any-standard-exit-status-codes-in-linux/40484670#40484670 - sys.exit(74) # input/output error - - salt, stored_hash = salted_hash.split(b':') - return b64decode(salt), b64decode(stored_hash) - - -def practice() -> None: - salt, stored_hash = load_hash() - print('Type q to end practice.') - turn = 0 - correct = 0 - while True: - turn += 1 - response = getpass(f'{turn}:') - if response == '': - print('Type q to quit.') - turn -= 1 # don't count this response - continue - elif response == 'q': - turn -= 1 # don't count this response - break - if crypto_hash(salt, response) == stored_hash: - correct += 1 - answer = 'OK' - else: - answer = 'wrong' - print(f' {answer}\thits={correct}\tmisses={turn-correct}') - - if turn: - print(f'\n{turn} turns. {correct / turn:.1%} correct.') - - -def main(argv: Sequence[str]) -> None: - if len(argv) < 2: - practice() - elif len(argv) == 2 and argv[1] == '-s': - save_hash() - else: - print('ERROR: invalid argument.', HELP) - sys.exit(2) # command line usage error - - -if __name__ == '__main__': - main(sys.argv) diff --git a/08-def-type-hints/replacer.py b/08-def-type-hints/replacer.py index 73ec77d..553a927 100644 --- a/08-def-type-hints/replacer.py +++ b/08-def-type-hints/replacer.py @@ -13,9 +13,9 @@ """ # tag::ZIP_REPLACE[] -from typing import Iterable, Tuple +from collections.abc import Iterable -FromTo = Tuple[str, str] # <1> +FromTo = tuple[str, str] # <1> def zip_replace(text: str, changes: Iterable[FromTo]) -> str: # <2> for from_, to in changes: diff --git a/08-def-type-hints/replacer2.py b/08-def-type-hints/replacer2.py deleted file mode 100644 index 33cdaeb..0000000 --- a/08-def-type-hints/replacer2.py +++ /dev/null @@ -1,39 +0,0 @@ -""" -``zip_replace`` replaces multiple calls to ``str.replace``:: - - >>> changes = [ - ... ('(', ' ( '), - ... (')', ' ) '), - ... (' ', ' '), - ... ] - >>> expr = '(+ 2 (* 3 7))' - >>> zip_replace(expr, changes) - ' ( + 2 ( * 3 7 ) ) ' - -""" - -from typing import Iterable, NamedTuple - - -class FromTo(NamedTuple): - from_: str - to: str - - -def zip_replace(text: str, changes: Iterable[FromTo], count: int = -1) -> str: - for from_, to in changes: - text = text.replace(from_, to, count) - return text - - -def demo() -> None: - import doctest - failed, count = doctest.testmod() - print(f'{count-failed} of {count} doctests OK') - l33t = [FromTo(*p) for p in 'a4 e3 i1 o0'.split()] - text = 'mad skilled noob powned leet' - print(zip_replace(text, l33t)) - - -if __name__ == '__main__': - demo() diff --git a/08-def-type-hints/reveal_array.py b/08-def-type-hints/reveal_array.py deleted file mode 100644 index 149c85a..0000000 --- a/08-def-type-hints/reveal_array.py +++ /dev/null @@ -1,8 +0,0 @@ -from array import array -from typing import MutableSequence - -a = array('d') -reveal_type(a) -b: MutableSequence[float] = array('b') -reveal_type(b) - diff --git a/08-def-type-hints/sample.py b/08-def-type-hints/sample.py index 0e7e2e9..04b0319 100644 --- a/08-def-type-hints/sample.py +++ b/08-def-type-hints/sample.py @@ -1,10 +1,11 @@ # tag::SAMPLE[] +from collections.abc import Sequence from random import shuffle -from typing import Sequence, List, TypeVar +from typing import TypeVar T = TypeVar('T') -def sample(population: Sequence[T], size: int) -> List[T]: +def sample(population: Sequence[T], size: int) -> list[T]: if size < 1: raise ValueError('size must be >= 1') result = list(population) diff --git a/08-def-type-hints/typevar_bounded.py b/08-def-type-hints/typevar_bounded.py new file mode 100644 index 0000000..5c2adf0 --- /dev/null +++ b/08-def-type-hints/typevar_bounded.py @@ -0,0 +1,11 @@ +from typing import TypeVar, TYPE_CHECKING + +BT = TypeVar('BT', bound=float) + +def triple2(a: BT) -> BT: + return a * 3 + +res2 = triple2(2) + +if TYPE_CHECKING: + reveal_type(res2) diff --git a/08-def-type-hints/typevars_constrained.py b/08-def-type-hints/typevars_constrained.py index 2bfea13..8fb8d8e 100644 --- a/08-def-type-hints/typevars_constrained.py +++ b/08-def-type-hints/typevars_constrained.py @@ -7,7 +7,7 @@ def triple1(a: RT) -> RT: return a * 3 -res1 = triple1(1, 2) +res1 = triple1(2) if TYPE_CHECKING: reveal_type(res1) @@ -19,7 +19,7 @@ def triple1(a: RT) -> RT: def triple2(a: BT) -> BT: return a * 3 -res2 = triple2(1, 2) +res2 = triple2(2) if TYPE_CHECKING: reveal_type(res2) diff --git a/09-closure-deco/clockdeco.py b/09-closure-deco/clock/clockdeco.py similarity index 100% rename from 09-closure-deco/clockdeco.py rename to 09-closure-deco/clock/clockdeco.py diff --git a/09-closure-deco/clockdeco0.py b/09-closure-deco/clock/clockdeco0.py similarity index 100% rename from 09-closure-deco/clockdeco0.py rename to 09-closure-deco/clock/clockdeco0.py diff --git a/09-closure-deco/clockdeco_cls.py b/09-closure-deco/clock/clockdeco_cls.py similarity index 100% rename from 09-closure-deco/clockdeco_cls.py rename to 09-closure-deco/clock/clockdeco_cls.py diff --git a/09-closure-deco/clockdeco_demo.py b/09-closure-deco/clock/clockdeco_demo.py similarity index 90% rename from 09-closure-deco/clockdeco_demo.py rename to 09-closure-deco/clock/clockdeco_demo.py index 121b52f..bd41b5c 100644 --- a/09-closure-deco/clockdeco_demo.py +++ b/09-closure-deco/clock/clockdeco_demo.py @@ -1,17 +1,14 @@ import time -from clockdeco import clock - +from clockdeco0 import clock @clock def snooze(seconds): time.sleep(seconds) - @clock def factorial(n): return 1 if n < 2 else n*factorial(n-1) - if __name__ == '__main__': print('*' * 40, 'Calling snooze(.123)') snooze(.123) diff --git a/09-closure-deco/clockdeco_param.py b/09-closure-deco/clock/clockdeco_param.py similarity index 100% rename from 09-closure-deco/clockdeco_param.py rename to 09-closure-deco/clock/clockdeco_param.py diff --git a/09-closure-deco/clockdeco_param_demo1.py b/09-closure-deco/clock/clockdeco_param_demo1.py similarity index 100% rename from 09-closure-deco/clockdeco_param_demo1.py rename to 09-closure-deco/clock/clockdeco_param_demo1.py diff --git a/09-closure-deco/clockdeco_param_demo2.py b/09-closure-deco/clock/clockdeco_param_demo2.py similarity index 100% rename from 09-closure-deco/clockdeco_param_demo2.py rename to 09-closure-deco/clock/clockdeco_param_demo2.py diff --git a/10-dp-1class-func/classic_strategy.py b/10-dp-1class-func/classic_strategy.py index dc72e19..d796a79 100644 --- a/10-dp-1class-func/classic_strategy.py +++ b/10-dp-1class-func/classic_strategy.py @@ -6,20 +6,20 @@ >>> joe = Customer('John Doe', 0) # <1> >>> ann = Customer('Ann Smith', 1100) - >>> cart = [LineItem('banana', 4, .5), # <2> - ... LineItem('apple', 10, 1.5), - ... LineItem('watermelon', 5, 5.0)] + >>> cart = (LineItem('banana', 4, Decimal('.5')), # <2> + ... LineItem('apple', 10, Decimal('1.5')), + ... LineItem('watermelon', 5, Decimal(5))) >>> Order(joe, cart, FidelityPromo()) # <3> >>> Order(ann, cart, FidelityPromo()) # <4> - >>> banana_cart = [LineItem('banana', 30, .5), # <5> - ... LineItem('apple', 10, 1.5)] + >>> banana_cart = (LineItem('banana', 30, Decimal('.5')), # <5> + ... LineItem('apple', 10, Decimal('1.5'))) >>> Order(joe, banana_cart, BulkItemPromo()) # <6> - >>> big_cart = [LineItem(str(item_code), 1, 1.0) # <7> - ... for item_code in range(10)] - >>> Order(joe, big_cart, LargeOrderPromo()) # <8> + >>> long_cart = tuple(LineItem(str(sku), 1, Decimal(1)) # <7> + ... for sku in range(10)) + >>> Order(joe, long_cart, LargeOrderPromo()) # <8> >>> Order(joe, cart, LargeOrderPromo()) @@ -29,44 +29,37 @@ # tag::CLASSIC_STRATEGY[] from abc import ABC, abstractmethod -import typing -from typing import Sequence, Optional +from collections.abc import Sequence +from decimal import Decimal +from typing import NamedTuple, Optional -class Customer(typing.NamedTuple): +class Customer(NamedTuple): name: str fidelity: int -class LineItem: - def __init__(self, product: str, quantity: int, price: float): - self.product = product - self.quantity = quantity - self.price = price +class LineItem(NamedTuple): + product: str + quantity: int + price: Decimal - def total(self): + def total(self) -> Decimal: return self.price * self.quantity -class Order: # the Context - def __init__( - self, - customer: Customer, - cart: Sequence[LineItem], - promotion: Optional['Promotion'] = None, - ): - self.customer = customer - self.cart = list(cart) - self.promotion = promotion +class Order(NamedTuple): # the Context + customer: Customer + cart: Sequence[LineItem] + promotion: Optional['Promotion'] = None - def total(self) -> float: - if not hasattr(self, '__total'): - self.__total = sum(item.total() for item in self.cart) - return self.__total + def total(self) -> Decimal: + totals = (item.total() for item in self.cart) + return sum(totals, start=Decimal(0)) - def due(self) -> float: + def due(self) -> Decimal: if self.promotion is None: - discount = 0.0 + discount = Decimal(0) else: discount = self.promotion.discount(self) return self.total() - discount @@ -77,36 +70,37 @@ def __repr__(self): class Promotion(ABC): # the Strategy: an abstract base class @abstractmethod - def discount(self, order: Order) -> float: + def discount(self, order: Order) -> Decimal: """Return discount as a positive dollar amount""" class FidelityPromo(Promotion): # first Concrete Strategy """5% discount for customers with 1000 or more fidelity points""" - def discount(self, order: Order) -> float: - return order.total() * 0.05 if order.customer.fidelity >= 1000 else 0 + def discount(self, order: Order) -> Decimal: + rate = Decimal('0.05') + if order.customer.fidelity >= 1000: + return order.total() * rate + return Decimal(0) class BulkItemPromo(Promotion): # second Concrete Strategy """10% discount for each LineItem with 20 or more units""" - def discount(self, order: Order) -> float: - discount = 0 + def discount(self, order: Order) -> Decimal: + discount = Decimal(0) for item in order.cart: if item.quantity >= 20: - discount += item.total() * 0.1 + discount += item.total() * Decimal('0.1') return discount class LargeOrderPromo(Promotion): # third Concrete Strategy """7% discount for orders with 10 or more distinct items""" - def discount(self, order: Order) -> float: + def discount(self, order: Order) -> Decimal: distinct_items = {item.product for item in order.cart} if len(distinct_items) >= 10: - return order.total() * 0.07 - return 0 - - + return order.total() * Decimal('0.07') + return Decimal(0) # end::CLASSIC_STRATEGY[] diff --git a/10-dp-1class-func/classic_strategy_test.py b/10-dp-1class-func/classic_strategy_test.py index 8735811..143cd0c 100644 --- a/10-dp-1class-func/classic_strategy_test.py +++ b/10-dp-1class-func/classic_strategy_test.py @@ -1,4 +1,4 @@ -from typing import List +from decimal import Decimal import pytest # type: ignore @@ -17,47 +17,49 @@ def customer_fidelity_1100() -> Customer: @pytest.fixture -def cart_plain() -> List[LineItem]: - return [ - LineItem('banana', 4, 0.5), - LineItem('apple', 10, 1.5), - LineItem('watermelon', 5, 5.0), - ] +def cart_plain() -> tuple[LineItem, ...]: + return ( + LineItem('banana', 4, Decimal('0.5')), + LineItem('apple', 10, Decimal('1.5')), + LineItem('watermelon', 5, Decimal('5.0')), + ) def test_fidelity_promo_no_discount(customer_fidelity_0, cart_plain) -> None: order = Order(customer_fidelity_0, cart_plain, FidelityPromo()) - assert order.total() == 42.0 - assert order.due() == 42.0 + assert order.total() == 42 + assert order.due() == 42 def test_fidelity_promo_with_discount(customer_fidelity_1100, cart_plain) -> None: order = Order(customer_fidelity_1100, cart_plain, FidelityPromo()) - assert order.total() == 42.0 - assert order.due() == 39.9 + assert order.total() == 42 + assert order.due() == Decimal('39.9') def test_bulk_item_promo_no_discount(customer_fidelity_0, cart_plain) -> None: order = Order(customer_fidelity_0, cart_plain, BulkItemPromo()) - assert order.total() == 42.0 - assert order.due() == 42.0 + assert order.total() == 42 + assert order.due() == 42 def test_bulk_item_promo_with_discount(customer_fidelity_0) -> None: - cart = [LineItem('banana', 30, 0.5), LineItem('apple', 10, 1.5)] + cart = [LineItem('banana', 30, Decimal('0.5')), + LineItem('apple', 10, Decimal('1.5'))] order = Order(customer_fidelity_0, cart, BulkItemPromo()) - assert order.total() == 30.0 - assert order.due() == 28.5 + assert order.total() == 30 + assert order.due() == Decimal('28.5') def test_large_order_promo_no_discount(customer_fidelity_0, cart_plain) -> None: order = Order(customer_fidelity_0, cart_plain, LargeOrderPromo()) - assert order.total() == 42.0 - assert order.due() == 42.0 + assert order.total() == 42 + assert order.due() == 42 def test_large_order_promo_with_discount(customer_fidelity_0) -> None: - cart = [LineItem(str(item_code), 1, 1.0) for item_code in range(10)] + cart = [LineItem(str(item_code), 1, Decimal(1)) + for item_code in range(10)] order = Order(customer_fidelity_0, cart, LargeOrderPromo()) - assert order.total() == 10.0 - assert order.due() == 9.3 + assert order.total() == 10 + assert order.due() == Decimal('9.3') diff --git a/10-dp-1class-func/monkeytype/classic_strategy.py b/10-dp-1class-func/monkeytype/classic_strategy.py index 0057d96..670c4cb 100644 --- a/10-dp-1class-func/monkeytype/classic_strategy.py +++ b/10-dp-1class-func/monkeytype/classic_strategy.py @@ -17,9 +17,9 @@ ... LineItem('apple', 10, 1.5)] >>> Order(joe, banana_cart, BulkItemPromo()) # <6> - >>> long_order = [LineItem(str(item_code), 1, 1.0) # <7> + >>> long_cart = [LineItem(str(item_code), 1, 1.0) # <7> ... for item_code in range(10)] - >>> Order(joe, long_order, LargeOrderPromo()) # <8> + >>> Order(joe, long_cart, LargeOrderPromo()) # <8> >>> Order(joe, cart, LargeOrderPromo()) diff --git a/10-dp-1class-func/promotions.py b/10-dp-1class-func/promotions.py index 0f8a823..ee64b20 100644 --- a/10-dp-1class-func/promotions.py +++ b/10-dp-1class-func/promotions.py @@ -1,20 +1,25 @@ -def fidelity_promo(order): +from decimal import Decimal +from strategy import Order + +def fidelity_promo(order: Order) -> Decimal: # <3> """5% discount for customers with 1000 or more fidelity points""" - return order.total() * 0.05 if order.customer.fidelity >= 1000 else 0 + if order.customer.fidelity >= 1000: + return order.total() * Decimal('0.05') + return Decimal(0) -def bulk_item_promo(order): +def bulk_item_promo(order: Order) -> Decimal: """10% discount for each LineItem with 20 or more units""" - discount = 0 + discount = Decimal(0) for item in order.cart: if item.quantity >= 20: - discount += item.total() * 0.1 + discount += item.total() * Decimal('0.1') return discount -def large_order_promo(order): +def large_order_promo(order: Order) -> Decimal: """7% discount for orders with 10 or more distinct items""" distinct_items = {item.product for item in order.cart} if len(distinct_items) >= 10: - return order.total() * 0.07 - return 0 + return order.total() * Decimal('0.07') + return Decimal(0) diff --git a/10-dp-1class-func/pytypes/classic_strategy.py b/10-dp-1class-func/pytypes/classic_strategy.py index d929ffa..710fd26 100644 --- a/10-dp-1class-func/pytypes/classic_strategy.py +++ b/10-dp-1class-func/pytypes/classic_strategy.py @@ -17,9 +17,9 @@ ... LineItem('apple', 10, 1.5)] >>> Order(joe, banana_cart, BulkItemPromo()) # <6> - >>> long_order = [LineItem(str(item_code), 1, 1.0) # <7> + >>> long_cart = [LineItem(str(item_code), 1, 1.0) # <7> ... for item_code in range(10)] - >>> Order(joe, long_order, LargeOrderPromo()) # <8> + >>> Order(joe, long_cart, LargeOrderPromo()) # <8> >>> Order(joe, cart, LargeOrderPromo()) diff --git a/10-dp-1class-func/requirements.txt b/10-dp-1class-func/requirements.txt index 1826922..4c4f0e1 100644 --- a/10-dp-1class-func/requirements.txt +++ b/10-dp-1class-func/requirements.txt @@ -1,13 +1,2 @@ -mypy==0.770 -mypy-extensions==0.4.3 -typed-ast==1.4.1 -typing-extensions==3.7.4.1 -attrs==19.3.0 -more-itertools==8.2.0 -packaging==20.3 -pluggy==0.13.1 -py==1.10.0 -pyparsing==2.4.6 -pytest==5.4.1 -six==1.14.0 -wcwidth==0.1.9 +mypy==0.910 +pytest==6.2.4 diff --git a/10-dp-1class-func/strategy.py b/10-dp-1class-func/strategy.py index 2ab49d1..89a93ba 100644 --- a/10-dp-1class-func/strategy.py +++ b/10-dp-1class-func/strategy.py @@ -6,20 +6,20 @@ >>> joe = Customer('John Doe', 0) # <1> >>> ann = Customer('Ann Smith', 1100) - >>> cart = [LineItem('banana', 4, .5), - ... LineItem('apple', 10, 1.5), - ... LineItem('watermelon', 5, 5.0)] + >>> cart = [LineItem('banana', 4, Decimal('.5')), + ... LineItem('apple', 10, Decimal('1.5')), + ... LineItem('watermelon', 5, Decimal(5))] >>> Order(joe, cart, fidelity_promo) # <2> >>> Order(ann, cart, fidelity_promo) - >>> banana_cart = [LineItem('banana', 30, .5), - ... LineItem('apple', 10, 1.5)] + >>> banana_cart = [LineItem('banana', 30, Decimal('.5')), + ... LineItem('apple', 10, Decimal('1.5'))] >>> Order(joe, banana_cart, bulk_item_promo) # <3> - >>> big_cart = [LineItem(str(item_code), 1, 1.0) + >>> long_cart = [LineItem(str(item_code), 1, Decimal(1)) ... for item_code in range(10)] - >>> Order(joe, big_cart, large_order_promo) + >>> Order(joe, long_cart, large_order_promo) >>> Order(joe, cart, large_order_promo) @@ -28,75 +28,71 @@ """ # tag::STRATEGY[] -import typing -from typing import Sequence, Optional, Callable +from collections.abc import Sequence +from dataclasses import dataclass +from decimal import Decimal +from typing import Optional, Callable, NamedTuple -class Customer(typing.NamedTuple): +class Customer(NamedTuple): name: str fidelity: int -class LineItem: - def __init__(self, product: str, quantity: int, price: float): - self.product = product - self.quantity = quantity - self.price = price +class LineItem(NamedTuple): + product: str + quantity: int + price: Decimal def total(self): return self.price * self.quantity - +@dataclass(frozen=True) class Order: # the Context - def __init__( - self, - customer: Customer, - cart: Sequence[LineItem], - promotion: Optional[Callable[['Order'], float]] = None, - ) -> None: - self.customer = customer - self.cart = list(cart) - self.promotion = promotion - - def total(self) -> float: - if not hasattr(self, '__total'): - self.__total = sum(item.total() for item in self.cart) - return self.__total - - def due(self) -> float: + customer: Customer + cart: Sequence[LineItem] + promotion: Optional[Callable[['Order'], Decimal]] = None # <1> + + def total(self) -> Decimal: + totals = (item.total() for item in self.cart) + return sum(totals, start=Decimal(0)) + + def due(self) -> Decimal: if self.promotion is None: - discount = 0.0 + discount = Decimal(0) else: - discount = self.promotion(self) # <1> + discount = self.promotion(self) # <2> return self.total() - discount def __repr__(self): return f'' -# <2> +# <3> -def fidelity_promo(order: Order) -> float: # <3> +def fidelity_promo(order: Order) -> Decimal: # <4> """5% discount for customers with 1000 or more fidelity points""" - return order.total() * 0.05 if order.customer.fidelity >= 1000 else 0 + if order.customer.fidelity >= 1000: + return order.total() * Decimal('0.05') + return Decimal(0) -def bulk_item_promo(order: Order): +def bulk_item_promo(order: Order) -> Decimal: """10% discount for each LineItem with 20 or more units""" - discount = 0 + discount = Decimal(0) for item in order.cart: if item.quantity >= 20: - discount += item.total() * 0.1 + discount += item.total() * Decimal('0.1') return discount -def large_order_promo(order: Order): +def large_order_promo(order: Order) -> Decimal: """7% discount for orders with 10 or more distinct items""" distinct_items = {item.product for item in order.cart} if len(distinct_items) >= 10: - return order.total() * 0.07 - return 0 + return order.total() * Decimal('0.07') + return Decimal(0) # end::STRATEGY[] diff --git a/10-dp-1class-func/strategy_best.py b/10-dp-1class-func/strategy_best.py index a7c4d74..68cab48 100644 --- a/10-dp-1class-func/strategy_best.py +++ b/10-dp-1class-func/strategy_best.py @@ -3,19 +3,20 @@ # selecting best promotion from static list of functions """ + >>> from strategy import Customer, LineItem >>> joe = Customer('John Doe', 0) >>> ann = Customer('Ann Smith', 1100) - >>> cart = [LineItem('banana', 4, .5), - ... LineItem('apple', 10, 1.5), - ... LineItem('watermelon', 5, 5.0)] - >>> banana_cart = [LineItem('banana', 30, .5), - ... LineItem('apple', 10, 1.5)] - >>> big_cart = [LineItem(str(item_code), 1, 1.0) + >>> cart = [LineItem('banana', 4, Decimal('.5')), + ... LineItem('apple', 10, Decimal('1.5')), + ... LineItem('watermelon', 5, Decimal(5))] + >>> banana_cart = [LineItem('banana', 30, Decimal('.5')), + ... LineItem('apple', 10, Decimal('1.5'))] + >>> long_cart = [LineItem(str(item_code), 1, Decimal(1)) ... for item_code in range(10)] # tag::STRATEGY_BEST_TESTS[] - >>> Order(joe, big_cart, best_promo) # <1> + >>> Order(joe, long_cart, best_promo) # <1> >>> Order(joe, banana_cart, best_promo) # <2> @@ -25,7 +26,9 @@ # end::STRATEGY_BEST_TESTS[] """ -from strategy import Customer, LineItem, Order +from decimal import Decimal + +from strategy import Order from strategy import fidelity_promo, bulk_item_promo, large_order_promo # tag::STRATEGY_BEST[] @@ -33,9 +36,8 @@ promos = [fidelity_promo, bulk_item_promo, large_order_promo] # <1> -def best_promo(order) -> float: # <2> - """Select best discount available - """ +def best_promo(order: Order) -> Decimal: # <2> + """Compute the best discount available""" return max(promo(order) for promo in promos) # <3> diff --git a/10-dp-1class-func/strategy_best2.py b/10-dp-1class-func/strategy_best2.py index 62a993e..1c6ad9c 100644 --- a/10-dp-1class-func/strategy_best2.py +++ b/10-dp-1class-func/strategy_best2.py @@ -3,29 +3,31 @@ # selecting best promotion from current module globals """ + >>> from decimal import Decimal + >>> from strategy import Customer, LineItem, Order >>> joe = Customer('John Doe', 0) >>> ann = Customer('Ann Smith', 1100) - >>> cart = [LineItem('banana', 4, .5), - ... LineItem('apple', 10, 1.5), - ... LineItem('watermelon', 5, 5.0)] + >>> cart = [LineItem('banana', 4, Decimal('.5')), + ... LineItem('apple', 10, Decimal('1.5')), + ... LineItem('watermelon', 5, Decimal(5))] >>> Order(joe, cart, fidelity_promo) >>> Order(ann, cart, fidelity_promo) - >>> banana_cart = [LineItem('banana', 30, .5), - ... LineItem('apple', 10, 1.5)] + >>> banana_cart = [LineItem('banana', 30, Decimal('.5')), + ... LineItem('apple', 10, Decimal('1.5'))] >>> Order(joe, banana_cart, bulk_item_promo) - >>> long_order = [LineItem(str(item_code), 1, 1.0) + >>> long_cart = [LineItem(str(item_code), 1, Decimal(1)) ... for item_code in range(10)] - >>> Order(joe, long_order, large_order_promo) + >>> Order(joe, long_cart, large_order_promo) >>> Order(joe, cart, large_order_promo) # tag::STRATEGY_BEST_TESTS[] - >>> Order(joe, long_order, best_promo) + >>> Order(joe, long_cart, best_promo) >>> Order(joe, banana_cart, best_promo) @@ -35,78 +37,21 @@ # end::STRATEGY_BEST_TESTS[] """ -from collections import namedtuple - -Customer = namedtuple('Customer', 'name fidelity') - - -class LineItem: - def __init__(self, product, quantity, price): - self.product = product - self.quantity = quantity - self.price = price - - def total(self): - return self.price * self.quantity - - -class Order: # the Context - def __init__(self, customer, cart, promotion=None): - self.customer = customer - self.cart = list(cart) - self.promotion = promotion - - def total(self): - if not hasattr(self, '__total'): - self.__total = sum(item.total() for item in self.cart) - return self.__total - - def due(self): - if self.promotion is None: - discount = 0 - else: - discount = self.promotion(self) - return self.total() - discount - - def __repr__(self): - return f'' - - -def fidelity_promo(order): - """5% discount for customers with 1000 or more fidelity points""" - return order.total() * 0.05 if order.customer.fidelity >= 1000 else 0 - - -def bulk_item_promo(order): - """10% discount for each LineItem with 20 or more units""" - discount = 0 - for item in order.cart: - if item.quantity >= 20: - discount += item.total() * 0.1 - return discount - - -def large_order_promo(order): - """7% discount for orders with 10 or more distinct items""" - distinct_items = {item.product for item in order.cart} - if len(distinct_items) >= 10: - return order.total() * 0.07 - return 0 - - # tag::STRATEGY_BEST2[] +from decimal import Decimal +from strategy import Order +from strategy import ( + fidelity_promo, bulk_item_promo, large_order_promo # <1> +) -promos = [ - globals()[name] - for name in globals() # <1> - if name.endswith('_promo') and name != 'best_promo' # <2> -] # <3> - +promos = [promo for name, promo in globals().items() # <2> + if name.endswith('_promo') and # <3> + name != 'best_promo' # <4> +] -def best_promo(order): - """Select best discount available - """ - return max(promo(order) for promo in promos) # <4> +def best_promo(order: Order) -> Decimal: # <5> + """Compute the best discount available""" + return max(promo(order) for promo in promos) # end::STRATEGY_BEST2[] diff --git a/10-dp-1class-func/strategy_best3.py b/10-dp-1class-func/strategy_best3.py index 39ce3bf..8b16ceb 100644 --- a/10-dp-1class-func/strategy_best3.py +++ b/10-dp-1class-func/strategy_best3.py @@ -3,30 +3,32 @@ # selecting best promotion from imported module """ + >>> from decimal import Decimal + >>> from strategy import Customer, LineItem, Order >>> from promotions import * >>> joe = Customer('John Doe', 0) >>> ann = Customer('Ann Smith', 1100) - >>> cart = [LineItem('banana', 4, .5), - ... LineItem('apple', 10, 1.5), - ... LineItem('watermelon', 5, 5.0)] + >>> cart = [LineItem('banana', 4, Decimal('.5')), + ... LineItem('apple', 10, Decimal('1.5')), + ... LineItem('watermelon', 5, Decimal(5))] >>> Order(joe, cart, fidelity_promo) >>> Order(ann, cart, fidelity_promo) - >>> banana_cart = [LineItem('banana', 30, .5), - ... LineItem('apple', 10, 1.5)] + >>> banana_cart = [LineItem('banana', 30, Decimal('.5')), + ... LineItem('apple', 10, Decimal('1.5'))] >>> Order(joe, banana_cart, bulk_item_promo) - >>> long_order = [LineItem(str(item_code), 1, 1.0) + >>> long_cart = [LineItem(str(item_code), 1, Decimal(1)) ... for item_code in range(10)] - >>> Order(joe, long_order, large_order_promo) + >>> Order(joe, long_cart, large_order_promo) >>> Order(joe, cart, large_order_promo) # tag::STRATEGY_BEST_TESTS[] - >>> Order(joe, long_order, best_promo) + >>> Order(joe, long_cart, best_promo) >>> Order(joe, banana_cart, best_promo) @@ -36,55 +38,20 @@ # end::STRATEGY_BEST_TESTS[] """ -from collections import namedtuple +# tag::STRATEGY_BEST3[] + +from decimal import Decimal import inspect +from strategy import Order import promotions -Customer = namedtuple('Customer', 'name fidelity') - - -class LineItem: - def __init__(self, product, quantity, price): - self.product = product - self.quantity = quantity - self.price = price - - def total(self): - return self.price * self.quantity - - -class Order: # the Context - def __init__(self, customer, cart, promotion=None): - self.customer = customer - self.cart = list(cart) - self.promotion = promotion - def total(self): - if not hasattr(self, '__total'): - self.__total = sum(item.total() for item in self.cart) - return self.__total +promos = [func for _, func in inspect.getmembers(promotions, inspect.isfunction)] - def due(self): - if self.promotion is None: - discount = 0 - else: - discount = self.promotion(self) - return self.total() - discount - def __repr__(self): - return f'' - - -# tag::STRATEGY_BEST3[] - -promos = [func for name, func in inspect.getmembers(promotions, inspect.isfunction)] - - -def best_promo(order): - """Select best discount available - """ +def best_promo(order: Order) -> Decimal: + """Compute the best discount available""" return max(promo(order) for promo in promos) - # end::STRATEGY_BEST3[] diff --git a/10-dp-1class-func/strategy_best4.py b/10-dp-1class-func/strategy_best4.py index 955ac3a..8e124bb 100644 --- a/10-dp-1class-func/strategy_best4.py +++ b/10-dp-1class-func/strategy_best4.py @@ -4,29 +4,32 @@ # registered by a decorator """ + >>> from decimal import Decimal + >>> from strategy import Customer, LineItem, Order + >>> from promotions import * >>> joe = Customer('John Doe', 0) >>> ann = Customer('Ann Smith', 1100) - >>> cart = [LineItem('banana', 4, .5), - ... LineItem('apple', 10, 1.5), - ... LineItem('watermelon', 5, 5.0)] - >>> Order(joe, cart, fidelity) + >>> cart = [LineItem('banana', 4, Decimal('.5')), + ... LineItem('apple', 10, Decimal('1.5')), + ... LineItem('watermelon', 5, Decimal(5))] + >>> Order(joe, cart, fidelity_promo) - >>> Order(ann, cart, fidelity) + >>> Order(ann, cart, fidelity_promo) - >>> banana_cart = [LineItem('banana', 30, .5), - ... LineItem('apple', 10, 1.5)] - >>> Order(joe, banana_cart, bulk_item) + >>> banana_cart = [LineItem('banana', 30, Decimal('.5')), + ... LineItem('apple', 10, Decimal('1.5'))] + >>> Order(joe, banana_cart, bulk_item_promo) - >>> long_order = [LineItem(str(item_code), 1, 1.0) + >>> long_cart = [LineItem(str(item_code), 1, Decimal(1)) ... for item_code in range(10)] - >>> Order(joe, long_order, large_order) + >>> Order(joe, long_cart, large_order_promo) - >>> Order(joe, cart, large_order) + >>> Order(joe, cart, large_order_promo) # tag::STRATEGY_BEST_TESTS[] - >>> Order(joe, long_order, best_promo) + >>> Order(joe, long_cart, best_promo) >>> Order(joe, banana_cart, best_promo) @@ -36,47 +39,16 @@ # end::STRATEGY_BEST_TESTS[] """ -from collections import namedtuple -from typing import Callable, List - -Customer = namedtuple('Customer', 'name fidelity') - - -class LineItem: - def __init__(self, product, quantity, price): - self.product = product - self.quantity = quantity - self.price = price - - def total(self): - return self.price * self.quantity - - -class Order: # the Context - def __init__(self, customer, cart, promotion=None): - self.customer = customer - self.cart = list(cart) - self.promotion = promotion - - def total(self): - if not hasattr(self, '__total'): - self.__total = sum(item.total() for item in self.cart) - return self.__total - - def due(self): - if self.promotion is None: - discount = 0 - else: - discount = self.promotion(self) - return self.total() - discount - - def __repr__(self): - return f'' +from decimal import Decimal +from typing import Callable +from strategy import Order # tag::STRATEGY_BEST4[] -Promotion = Callable[[Order], float] # <2> +Promotion = Callable[[Order], Decimal] + +promos: list[Promotion] = [] # <1> def promotion(promo: Promotion) -> Promotion: # <2> @@ -84,38 +56,35 @@ def promotion(promo: Promotion) -> Promotion: # <2> return promo -promos: List[Promotion] = [] # <1> +def best_promo(order: Order) -> Decimal: + """Compute the best discount available""" + return max(promo(order) for promo in promos) # <3> -@promotion # <3> -def fidelity(order: Order) -> float: +@promotion # <4> +def fidelity(order: Order) -> Decimal: """5% discount for customers with 1000 or more fidelity points""" - return order.total() * 0.05 if order.customer.fidelity >= 1000 else 0 + if order.customer.fidelity >= 1000: + return order.total() * Decimal('0.05') + return Decimal(0) @promotion -def bulk_item(order: Order) -> float: +def bulk_item(order: Order) -> Decimal: """10% discount for each LineItem with 20 or more units""" - discount = 0 + discount = Decimal(0) for item in order.cart: if item.quantity >= 20: - discount += item.total() * 0.1 + discount += item.total() * Decimal('0.1') return discount @promotion -def large_order(order: Order) -> float: +def large_order(order: Order) -> Decimal: """7% discount for orders with 10 or more distinct items""" distinct_items = {item.product for item in order.cart} if len(distinct_items) >= 10: - return order.total() * 0.07 - return 0 - - -def best_promo(order: Order) -> float: # <4> - """Select best discount available - """ - return max(promo(order) for promo in promos) - + return order.total() * Decimal('0.07') + return Decimal(0) # end::STRATEGY_BEST4[] diff --git a/10-dp-1class-func/strategy_param.py b/10-dp-1class-func/strategy_param.py index 7318530..5490666 100644 --- a/10-dp-1class-func/strategy_param.py +++ b/10-dp-1class-func/strategy_param.py @@ -15,9 +15,9 @@ ... LineItem('apple', 10, 1.5)] >>> Order(joe, banana_cart, bulk_item_promo(10)) - >>> big_cart = [LineItem(str(item_code), 1, 1.0) + >>> long_cart = [LineItem(str(item_code), 1, 1.0) ... for item_code in range(10)] - >>> Order(joe, big_cart, LargeOrderPromo(7)) + >>> Order(joe, long_cart, LargeOrderPromo(7)) >>> Order(joe, cart, LargeOrderPromo(7)) diff --git a/10-dp-1class-func/strategy_param_test.py b/10-dp-1class-func/strategy_param_test.py index d550e2b..cfb965e 100644 --- a/10-dp-1class-func/strategy_param_test.py +++ b/10-dp-1class-func/strategy_param_test.py @@ -47,7 +47,7 @@ def test_large_order_promo_with_discount(customer_fidelity_0) -> None: assert order.due() == 9.3 -def test_general_discount(customer_fidelity_0, cart_plain) -> None: +def test_general_discount(customer_fidelity_1100, cart_plain) -> None: general_promo: Promotion = functools.partial(general_discount, 5) order = Order(customer_fidelity_1100, cart_plain, general_promo) assert order.total() == 42.0 diff --git a/10-dp-1class-func/strategy_test.py b/10-dp-1class-func/strategy_test.py index bf225ae..c47440e 100644 --- a/10-dp-1class-func/strategy_test.py +++ b/10-dp-1class-func/strategy_test.py @@ -1,4 +1,4 @@ -from typing import List +from decimal import Decimal import pytest # type: ignore @@ -17,47 +17,50 @@ def customer_fidelity_1100() -> Customer: @pytest.fixture -def cart_plain() -> List[LineItem]: - return [ - LineItem('banana', 4, 0.5), - LineItem('apple', 10, 1.5), - LineItem('watermelon', 5, 5.0), - ] +def cart_plain() -> tuple[LineItem, ...]: + return ( + LineItem('banana', 4, Decimal('0.5')), + LineItem('apple', 10, Decimal('1.5')), + LineItem('watermelon', 5, Decimal('5.0')), + ) def test_fidelity_promo_no_discount(customer_fidelity_0, cart_plain) -> None: order = Order(customer_fidelity_0, cart_plain, fidelity_promo) - assert order.total() == 42.0 - assert order.due() == 42.0 + assert order.total() == 42 + assert order.due() == 42 def test_fidelity_promo_with_discount(customer_fidelity_1100, cart_plain) -> None: order = Order(customer_fidelity_1100, cart_plain, fidelity_promo) - assert order.total() == 42.0 - assert order.due() == 39.9 + assert order.total() == 42 + assert order.due() == Decimal('39.9') def test_bulk_item_promo_no_discount(customer_fidelity_0, cart_plain) -> None: order = Order(customer_fidelity_0, cart_plain, bulk_item_promo) - assert order.total() == 42.0 - assert order.due() == 42.0 + assert order.total() == 42 + assert order.due() == 42 def test_bulk_item_promo_with_discount(customer_fidelity_0) -> None: - cart = [LineItem('banana', 30, 0.5), LineItem('apple', 10, 1.5)] + cart = [LineItem('banana', 30, Decimal('0.5')), + LineItem('apple', 10, Decimal('1.5'))] order = Order(customer_fidelity_0, cart, bulk_item_promo) - assert order.total() == 30.0 - assert order.due() == 28.5 + assert order.total() == 30 + assert order.due() == Decimal('28.5') def test_large_order_promo_no_discount(customer_fidelity_0, cart_plain) -> None: order = Order(customer_fidelity_0, cart_plain, large_order_promo) - assert order.total() == 42.0 - assert order.due() == 42.0 + assert order.total() == 42 + assert order.due() == 42 def test_large_order_promo_with_discount(customer_fidelity_0) -> None: - cart = [LineItem(str(item_code), 1, 1.0) for item_code in range(10)] + + cart = [LineItem(str(item_code), 1, Decimal(1)) + for item_code in range(10)] order = Order(customer_fidelity_0, cart, large_order_promo) - assert order.total() == 10.0 - assert order.due() == 9.3 + assert order.total() == 10 + assert order.due() == Decimal('9.3') diff --git a/10-dp-1class-func/untyped/classic_strategy.py b/10-dp-1class-func/untyped/classic_strategy.py index b969780..61cccd5 100644 --- a/10-dp-1class-func/untyped/classic_strategy.py +++ b/10-dp-1class-func/untyped/classic_strategy.py @@ -17,9 +17,9 @@ ... LineItem('apple', 10, 1.5)] >>> Order(joe, banana_cart, BulkItemPromo()) # <6> - >>> long_order = [LineItem(str(item_code), 1, 1.0) # <7> + >>> long_cart = [LineItem(str(item_code), 1, 1.0) # <7> ... for item_code in range(10)] - >>> Order(joe, long_order, LargeOrderPromo()) # <8> + >>> Order(joe, long_cart, LargeOrderPromo()) # <8> >>> Order(joe, cart, LargeOrderPromo()) diff --git a/10-dp-1class-func/untyped/strategy.py b/10-dp-1class-func/untyped/strategy.py index 1f8ad4c..518c69d 100644 --- a/10-dp-1class-func/untyped/strategy.py +++ b/10-dp-1class-func/untyped/strategy.py @@ -17,9 +17,9 @@ ... LineItem('apple', 10, 1.5)] >>> Order(joe, banana_cart, bulk_item_promo) # <3> - >>> long_order = [LineItem(str(item_code), 1, 1.0) + >>> long_cart = [LineItem(str(item_code), 1, 1.0) ... for item_code in range(10)] - >>> Order(joe, long_order, large_order_promo) + >>> Order(joe, long_cart, large_order_promo) >>> Order(joe, cart, large_order_promo) diff --git a/10-dp-1class-func/untyped/strategy_best.py b/10-dp-1class-func/untyped/strategy_best.py index c0585f7..718b672 100644 --- a/10-dp-1class-func/untyped/strategy_best.py +++ b/10-dp-1class-func/untyped/strategy_best.py @@ -16,16 +16,16 @@ ... LineItem('apple', 10, 1.5)] >>> Order(joe, banana_cart, bulk_item_promo) - >>> long_order = [LineItem(str(item_code), 1, 1.0) + >>> long_cart = [LineItem(str(item_code), 1, 1.0) ... for item_code in range(10)] - >>> Order(joe, long_order, large_order_promo) + >>> Order(joe, long_cart, large_order_promo) >>> Order(joe, cart, large_order_promo) # tag::STRATEGY_BEST_TESTS[] - >>> Order(joe, long_order, best_promo) # <1> + >>> Order(joe, long_cart, best_promo) # <1> >>> Order(joe, banana_cart, best_promo) # <2> diff --git a/10-dp-1class-func/untyped/strategy_best2.py b/10-dp-1class-func/untyped/strategy_best2.py index 1f4700f..bfcd839 100644 --- a/10-dp-1class-func/untyped/strategy_best2.py +++ b/10-dp-1class-func/untyped/strategy_best2.py @@ -16,16 +16,16 @@ ... LineItem('apple', 10, 1.5)] >>> Order(joe, banana_cart, bulk_item_promo) - >>> long_order = [LineItem(str(item_code), 1, 1.0) + >>> long_cart = [LineItem(str(item_code), 1, 1.0) ... for item_code in range(10)] - >>> Order(joe, long_order, large_order_promo) + >>> Order(joe, long_cart, large_order_promo) >>> Order(joe, cart, large_order_promo) # tag::STRATEGY_BEST_TESTS[] - >>> Order(joe, long_order, best_promo) + >>> Order(joe, long_cart, best_promo) >>> Order(joe, banana_cart, best_promo) diff --git a/10-dp-1class-func/untyped/strategy_best3.py b/10-dp-1class-func/untyped/strategy_best3.py index 8d21ffc..f911ce3 100644 --- a/10-dp-1class-func/untyped/strategy_best3.py +++ b/10-dp-1class-func/untyped/strategy_best3.py @@ -17,16 +17,16 @@ ... LineItem('apple', 10, 1.5)] >>> Order(joe, banana_cart, bulk_item_promo) - >>> long_order = [LineItem(str(item_code), 1, 1.0) + >>> long_cart = [LineItem(str(item_code), 1, 1.0) ... for item_code in range(10)] - >>> Order(joe, long_order, large_order_promo) + >>> Order(joe, long_cart, large_order_promo) >>> Order(joe, cart, large_order_promo) # tag::STRATEGY_BEST_TESTS[] - >>> Order(joe, long_order, best_promo) + >>> Order(joe, long_cart, best_promo) >>> Order(joe, banana_cart, best_promo) diff --git a/10-dp-1class-func/untyped/strategy_best4.py b/10-dp-1class-func/untyped/strategy_best4.py index b523752..9573176 100644 --- a/10-dp-1class-func/untyped/strategy_best4.py +++ b/10-dp-1class-func/untyped/strategy_best4.py @@ -17,16 +17,16 @@ ... LineItem('apple', 10, 1.5)] >>> Order(joe, banana_cart, bulk_item) - >>> long_order = [LineItem(str(item_code), 1, 1.0) + >>> long_cart = [LineItem(str(item_code), 1, 1.0) ... for item_code in range(10)] - >>> Order(joe, long_order, large_order) + >>> Order(joe, long_cart, large_order) >>> Order(joe, cart, large_order) # tag::STRATEGY_BEST_TESTS[] - >>> Order(joe, long_order, best_promo) + >>> Order(joe, long_cart, best_promo) >>> Order(joe, banana_cart, best_promo) diff --git a/10-dp-1class-func/untyped/strategy_param.py b/10-dp-1class-func/untyped/strategy_param.py index d5cc931..ab07132 100644 --- a/10-dp-1class-func/untyped/strategy_param.py +++ b/10-dp-1class-func/untyped/strategy_param.py @@ -15,9 +15,9 @@ ... LineItem('apple', 10, 1.5)] >>> Order(joe, banana_cart, bulk_item_promo(10)) - >>> long_order = [LineItem(str(item_code), 1, 1.0) + >>> long_cart = [LineItem(str(item_code), 1, 1.0) ... for item_code in range(10)] - >>> Order(joe, long_order, large_order_promo(7)) + >>> Order(joe, long_cart, large_order_promo(7)) >>> Order(joe, cart, large_order_promo(7)) diff --git a/10-dp-1class-func/untyped/strategy_param2.py b/10-dp-1class-func/untyped/strategy_param2.py index 625bbca..332f49d 100644 --- a/10-dp-1class-func/untyped/strategy_param2.py +++ b/10-dp-1class-func/untyped/strategy_param2.py @@ -15,9 +15,9 @@ ... LineItem('apple', 10, 1.5)] >>> Order(joe, banana_cart, BulkItemPromo(10)) - >>> long_order = [LineItem(str(item_code), 1, 1.0) + >>> long_cart = [LineItem(str(item_code), 1, 1.0) ... for item_code in range(10)] - >>> Order(joe, long_order, LargeOrderPromo(7)) + >>> Order(joe, long_cart, LargeOrderPromo(7)) >>> Order(joe, cart, LargeOrderPromo(7)) diff --git a/11-pythonic-obj/mem_test.py b/11-pythonic-obj/mem_test.py index 0d745f2..12fc54e 100644 --- a/11-pythonic-obj/mem_test.py +++ b/11-pythonic-obj/mem_test.py @@ -4,20 +4,25 @@ NUM_VECTORS = 10**7 +module = None if len(sys.argv) == 2: module_name = sys.argv[1].replace('.py', '') module = importlib.import_module(module_name) else: print(f'Usage: {sys.argv[0]} ') - sys.exit(2) # command line usage error -fmt = 'Selected Vector2d type: {.__name__}.{.__name__}' -print(fmt.format(module, module.Vector2d)) +if module is None: + print('Running test with built-in `complex`') + cls = complex +else: + fmt = 'Selected Vector2d type: {.__name__}.{.__name__}' + print(fmt.format(module, module.Vector2d)) + cls = module.Vector2d mem_init = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss -print(f'Creating {NUM_VECTORS:,} Vector2d instances') +print(f'Creating {NUM_VECTORS:,} {cls.__qualname__!r} instances') -vectors = [module.Vector2d(3.0, 4.0) for i in range(NUM_VECTORS)] +vectors = [cls(3.0, 4.0) for i in range(NUM_VECTORS)] mem_final = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss print(f'Initial RAM usage: {mem_init:14,}') diff --git a/11-pythonic-obj/patterns.py b/11-pythonic-obj/patterns.py new file mode 100644 index 0000000..9317a4c --- /dev/null +++ b/11-pythonic-obj/patterns.py @@ -0,0 +1,53 @@ +from vector2d_v3 import Vector2d + +# tag::KEYWORD_PATTERNS[] +def keyword_pattern_demo(v: Vector2d) -> None: + match v: + case Vector2d(x=0, y=0): + print(f'{v!r} is null') + case Vector2d(x=0): + print(f'{v!r} is vertical') + case Vector2d(y=0): + print(f'{v!r} is horizontal') + case Vector2d(x=x, y=y) if x==y: + print(f'{v!r} is diagonal') + case _: + print(f'{v!r} is awesome') +# end::KEYWORD_PATTERNS[] + +# tag::POSITIONAL_PATTERNS[] +def positional_pattern_demo(v: Vector2d) -> None: + match v: + case Vector2d(0, 0): + print(f'{v!r} is null') + case Vector2d(0): + print(f'{v!r} is vertical') + case Vector2d(_, 0): + print(f'{v!r} is horizontal') + case Vector2d(x, y) if x==y: + print(f'{v!r} is diagonal') + case _: + print(f'{v!r} is awesome') +# end::POSITIONAL_PATTERNS[] + + +def main(): + vectors = ( + Vector2d(1, 1), + Vector2d(0, 1), + Vector2d(1, 0), + Vector2d(1, 2), + Vector2d(0, 0), + ) + print('KEYWORD PATTERNS:') + for vector in vectors: + keyword_pattern_demo(vector) + + print('POSITIONAL PATTERNS:') + for vector in vectors: + positional_pattern_demo(vector) + + + +if __name__ == '__main__': + main() diff --git a/11-pythonic-obj/slots.rst b/11-pythonic-obj/slots.rst new file mode 100644 index 0000000..351c9de --- /dev/null +++ b/11-pythonic-obj/slots.rst @@ -0,0 +1,52 @@ +# tag::PIXEL[] +>>> class Pixel: +... __slots__ = ('x', 'y') # <1> +... +>>> p = Pixel() # <2> +>>> p.__dict__ # <3> +Traceback (most recent call last): + ... +AttributeError: 'Pixel' object has no attribute '__dict__' +>>> p.x = 10 # <4> +>>> p.y = 20 +>>> p.color = 'red' # <5> +Traceback (most recent call last): + ... +AttributeError: 'Pixel' object has no attribute 'color' + +# end::PIXEL[] + +# tag::OPEN_PIXEL[] +>>> class OpenPixel(Pixel): # <1> +... pass +... +>>> op = OpenPixel() +>>> op.__dict__ # <2> +{} +>>> op.x = 8 # <3> +>>> op.__dict__ # <4> +{} +>>> op.x # <5> +8 +>>> op.color = 'green' # <6> +>>> op.__dict__ # <7> +{'color': 'green'} + +# end::OPEN_PIXEL[] + +# tag::COLOR_PIXEL[] +>>> class ColorPixel(Pixel): +... __slots__ = ('color',) # <1> +>>> cp = ColorPixel() +>>> cp.__dict__ # <2> +Traceback (most recent call last): + ... +AttributeError: 'ColorPixel' object has no attribute '__dict__' +>>> cp.x = 2 +>>> cp.color = 'blue' # <3> +>>> cp.flavor = 'banana' +Traceback (most recent call last): + ... +AttributeError: 'ColorPixel' object has no attribute 'flavor' + +# end::COLOR_PIXEL[] diff --git a/11-pythonic-obj/vector2d_v3.py b/11-pythonic-obj/vector2d_v3.py index 376a8a4..9ee716c 100644 --- a/11-pythonic-obj/vector2d_v3.py +++ b/11-pythonic-obj/vector2d_v3.py @@ -72,7 +72,7 @@ >>> v1.x = 123 Traceback (most recent call last): ... - AttributeError: can't set attribute + AttributeError: can't set attribute 'x' Tests of hashing: @@ -90,6 +90,8 @@ import math class Vector2d: + __match_args__ = ('x', 'y') + typecode = 'd' def __init__(self, x, y): diff --git a/11-pythonic-obj/vector2d_v3_prophash.py b/11-pythonic-obj/vector2d_v3_prophash.py index 3552530..6d7dceb 100644 --- a/11-pythonic-obj/vector2d_v3_prophash.py +++ b/11-pythonic-obj/vector2d_v3_prophash.py @@ -72,7 +72,7 @@ >>> v1.x = 123 Traceback (most recent call last): ... - AttributeError: can't set attribute + AttributeError: can't set attribute 'x' # end::VECTOR2D_V3_HASH_DEMO[] @@ -112,7 +112,7 @@ def y(self): def __iter__(self): return (i for i in (self.x, self.y)) # <6> - # remaining methods follow (omitted in book listing) + # remaining methods: same as previous Vector2d # end::VECTOR2D_V3_PROP[] def __repr__(self): diff --git a/11-pythonic-obj/vector2d_v3_slots.py b/11-pythonic-obj/vector2d_v3_slots.py index 20b6da4..c48fb5b 100644 --- a/11-pythonic-obj/vector2d_v3_slots.py +++ b/11-pythonic-obj/vector2d_v3_slots.py @@ -72,7 +72,7 @@ >>> v1.x = 123 Traceback (most recent call last): ... - AttributeError: can't set attribute + AttributeError: can't set attribute 'x' Tests of hashing: @@ -90,11 +90,10 @@ # tag::VECTOR2D_V3_SLOTS[] class Vector2d: - __slots__ = ('__x', '__y') + __match_args__ = ('x', 'y') # <1> + __slots__ = ('__x', '__y') # <2> typecode = 'd' - - # methods follow (omitted in book listing) # end::VECTOR2D_V3_SLOTS[] def __init__(self, x, y): diff --git a/12-seq-hacking/vector_v3.py b/12-seq-hacking/vector_v3.py index 6ee18b5..c1f7859 100644 --- a/12-seq-hacking/vector_v3.py +++ b/12-seq-hacking/vector_v3.py @@ -199,15 +199,17 @@ def __getitem__(self, key): return self._components[index] # tag::VECTOR_V3_GETATTR[] - shortcut_names = 'xyzt' + __match_args__ = ('x', 'y', 'z', 't') # <1> def __getattr__(self, name): - cls = type(self) # <1> - if len(name) == 1: # <2> - pos = cls.shortcut_names.find(name) # <3> - if 0 <= pos < len(self._components): # <4> - return self._components[pos] - msg = f'{cls.__name__!r} object has no attribute {name!r}' # <5> + cls = type(self) # <2> + try: + pos = cls.__match_args__.index(name) # <3> + except ValueError: # <4> + pos = -1 + if 0 <= pos < len(self._components): # <5> + return self._components[pos] + msg = f'{cls.__name__!r} object has no attribute {name!r}' # <6> raise AttributeError(msg) # end::VECTOR_V3_GETATTR[] @@ -215,8 +217,8 @@ def __getattr__(self, name): def __setattr__(self, name, value): cls = type(self) if len(name) == 1: # <1> - if name in cls.shortcut_names: # <2> - error = 'read-only attribute {attr_name!r}' + if name in cls.__match_args__: # <2> + error = 'readonly attribute {attr_name!r}' elif name.islower(): # <3> error = "can't set attributes 'a' to 'z' in {cls_name!r}" else: diff --git a/12-seq-hacking/vector_v4.py b/12-seq-hacking/vector_v4.py index 95530eb..856f338 100644 --- a/12-seq-hacking/vector_v4.py +++ b/12-seq-hacking/vector_v4.py @@ -199,14 +199,16 @@ def __getitem__(self, key): index = operator.index(key) return self._components[index] - shortcut_names = 'xyzt' + __match_args__ = ('x', 'y', 'z', 't') def __getattr__(self, name): cls = type(self) - if len(name) == 1: - pos = cls.shortcut_names.find(name) - if 0 <= pos < len(self._components): - return self._components[pos] + try: + pos = cls.__match_args__.index(name) + except ValueError: + pos = -1 + if 0 <= pos < len(self._components): + return self._components[pos] msg = f'{cls.__name__!r} object has no attribute {name!r}' raise AttributeError(msg) diff --git a/12-seq-hacking/vector_v5.py b/12-seq-hacking/vector_v5.py index ebbd523..09b3044 100644 --- a/12-seq-hacking/vector_v5.py +++ b/12-seq-hacking/vector_v5.py @@ -242,14 +242,16 @@ def __getitem__(self, key): index = operator.index(key) return self._components[index] - shortcut_names = 'xyzt' + __match_args__ = ('x', 'y', 'z', 't') def __getattr__(self, name): cls = type(self) - if len(name) == 1: - pos = cls.shortcut_names.find(name) - if 0 <= pos < len(self._components): - return self._components[pos] + try: + pos = cls.__match_args__.index(name) + except ValueError: + pos = -1 + if 0 <= pos < len(self._components): + return self._components[pos] msg = f'{cls.__name__!r} object has no attribute {name!r}' raise AttributeError(msg) diff --git a/13-protocol-abc/frenchdeck2.py b/13-protocol-abc/frenchdeck2.py index e3ccc2c..612581d 100644 --- a/13-protocol-abc/frenchdeck2.py +++ b/13-protocol-abc/frenchdeck2.py @@ -1,8 +1,8 @@ -import collections +from collections import namedtuple, abc -Card = collections.namedtuple('Card', ['rank', 'suit']) +Card = namedtuple('Card', ['rank', 'suit']) -class FrenchDeck2(collections.MutableSequence): +class FrenchDeck2(abc.MutableSequence): ranks = [str(n) for n in range(2, 11)] + list('JQKA') suits = 'spades diamonds clubs hearts'.split() diff --git a/13-protocol-abc/typing/randompick_test.py b/13-protocol-abc/typing/randompick_test.py index f090022..115c4d3 100644 --- a/13-protocol-abc/typing/randompick_test.py +++ b/13-protocol-abc/typing/randompick_test.py @@ -12,14 +12,14 @@ def pick(self) -> Any: # <3> return self._items.pop() def test_isinstance() -> None: # <4> - popper = SimplePicker([1]) - assert isinstance(popper, RandomPicker) + popper: RandomPicker = SimplePicker([1]) # <5> + assert isinstance(popper, RandomPicker) # <6> -def test_item_type() -> None: # <5> +def test_item_type() -> None: # <7> items = [1, 2] popper = SimplePicker(items) item = popper.pick() assert item in items if TYPE_CHECKING: - reveal_type(item) # <6> + reveal_type(item) # <8> assert isinstance(item, int) diff --git a/13-protocol-abc/typing/vector2d_v4.py b/13-protocol-abc/typing/vector2d_v4.py index 1e9d4ac..deaa824 100644 --- a/13-protocol-abc/typing/vector2d_v4.py +++ b/13-protocol-abc/typing/vector2d_v4.py @@ -168,5 +168,5 @@ def __complex__(self): @classmethod def fromcomplex(cls, datum): - return Vector2d(datum.real, datum.imag) # <1> + return cls(datum.real, datum.imag) # <1> # end::VECTOR2D_V4_COMPLEX[] diff --git a/13-protocol-abc/typing/vector2d_v5.py b/13-protocol-abc/typing/vector2d_v5.py index ceda21c..378b826 100644 --- a/13-protocol-abc/typing/vector2d_v5.py +++ b/13-protocol-abc/typing/vector2d_v5.py @@ -170,5 +170,5 @@ def __complex__(self) -> complex: # <2> @classmethod def fromcomplex(cls, datum: SupportsComplex) -> Vector2d: # <3> c = complex(datum) # <4> - return Vector2d(c.real, c.imag) + return cls(c.real, c.imag) # end::VECTOR2D_V5_COMPLEX[] diff --git a/14-inheritance/uppermixin.py b/14-inheritance/uppermixin.py index d86ecea..12c4a17 100644 --- a/14-inheritance/uppermixin.py +++ b/14-inheritance/uppermixin.py @@ -1,10 +1,39 @@ -"""UpperDict uppercases all string keys. +""" +Short demos +=========== -Test for initializer. `str` keys are uppercased:: +``UpperDict`` behaves like a case-insensitive mapping`:: - >>> d = UpperDict([('a', 'letter A'), ('B', 'letter B'), (2, 'digit two')]) +# tag::UPPERDICT_DEMO[] + >>> d = UpperDict([('a', 'letter A'), (2, 'digit two')]) >>> list(d.keys()) - ['A', 'B', 2] + ['A', 2] + >>> d['b'] = 'letter B' + >>> 'b' in d + True + >>> d['a'], d.get('B') + ('letter A', 'letter B') + >>> list(d.keys()) + ['A', 2, 'B'] + +# end::UPPERDICT_DEMO[] + +And ``UpperCounter`` is also case-insensitive:: + +# tag::UPPERCOUNTER_DEMO[] + >>> c = UpperCounter('BaNanA') + >>> c.most_common() + [('A', 3), ('N', 2), ('B', 1)] + +# end::UPPERCOUNTER_DEMO[] + +Detailed tests +============== + +UpperDict uppercases all string keys. + + >>> d = UpperDict([('a', 'letter A'), ('B', 'letter B'), (2, 'digit two')]) + Tests for item retrieval using `d[key]` notation:: @@ -82,14 +111,12 @@ # tag::UPPERCASE_MIXIN[] import collections - def _upper(key): # <1> try: return key.upper() except AttributeError: return key - class UpperCaseMixin: # <2> def __setitem__(self, key, item): super().__setitem__(_upper(key), item) @@ -108,8 +135,6 @@ def __contains__(self, key): class UpperDict(UpperCaseMixin, collections.UserDict): # <1> pass - class UpperCounter(UpperCaseMixin, collections.Counter): # <2> """Specialized 'Counter' that uppercases string keys""" # <3> - # end::UPPERDICT[] diff --git a/15-more-types/protocol/abs_demo.py b/15-more-types/protocol/abs_demo.py index 9cb7f80..6af78ea 100755 --- a/15-more-types/protocol/abs_demo.py +++ b/15-more-types/protocol/abs_demo.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 +# tag::ABS_DEMO[] import math from typing import NamedTuple, SupportsAbs @@ -30,3 +31,4 @@ def is_unit(v: SupportsAbs[float]) -> bool: # <2> assert is_unit(v4) print('OK') +# end::ABS_DEMO[] diff --git a/16-op-overloading/vector2d_v3.py b/16-op-overloading/vector2d_v3.py index 5812dcf..9ee716c 100644 --- a/16-op-overloading/vector2d_v3.py +++ b/16-op-overloading/vector2d_v3.py @@ -1,5 +1,5 @@ """ -A 2-dimensional vector class +A two-dimensional vector class >>> v1 = Vector2d(3, 4) >>> print(v1.x, v1.y) @@ -72,7 +72,7 @@ >>> v1.x = 123 Traceback (most recent call last): ... - AttributeError: can't set attribute + AttributeError: can't set attribute 'x' Tests of hashing: @@ -81,7 +81,7 @@ >>> v2 = Vector2d(3.1, 4.2) >>> hash(v1), hash(v2) (7, 384307168202284039) - >>> len(set([v1, v2])) + >>> len({v1, v2}) 2 """ @@ -90,6 +90,8 @@ import math class Vector2d: + __match_args__ = ('x', 'y') + typecode = 'd' def __init__(self, x, y): diff --git a/16-op-overloading/vector_v6.py b/16-op-overloading/vector_v6.py index 7154851..6ae4dcf 100644 --- a/16-op-overloading/vector_v6.py +++ b/16-op-overloading/vector_v6.py @@ -305,14 +305,16 @@ def __getitem__(self, key): index = operator.index(key) return self._components[index] - shortcut_names = 'xyzt' + __match_args__ = ('x', 'y', 'z', 't') def __getattr__(self, name): cls = type(self) - if len(name) == 1: - pos = cls.shortcut_names.find(name) - if 0 <= pos < len(self._components): - return self._components[pos] + try: + pos = cls.__match_args__.index(name) + except ValueError: + pos = -1 + if 0 <= pos < len(self._components): + return self._components[pos] msg = f'{cls.__name__!r} object has no attribute {name!r}' raise AttributeError(msg) diff --git a/16-op-overloading/vector_v7.py b/16-op-overloading/vector_v7.py index e59c896..953622e 100644 --- a/16-op-overloading/vector_v7.py +++ b/16-op-overloading/vector_v7.py @@ -355,14 +355,16 @@ def __getitem__(self, key): index = operator.index(key) return self._components[index] - shortcut_names = 'xyzt' + __match_args__ = ('x', 'y', 'z', 't') def __getattr__(self, name): cls = type(self) - if len(name) == 1: - pos = cls.shortcut_names.find(name) - if 0 <= pos < len(self._components): - return self._components[pos] + try: + pos = cls.__match_args__.index(name) + except ValueError: + pos = -1 + if 0 <= pos < len(self._components): + return self._components[pos] msg = f'{cls.__name__!r} object has no attribute {name!r}' raise AttributeError(msg) diff --git a/16-op-overloading/vector_v8.py b/16-op-overloading/vector_v8.py index ee2cb48..44c05fd 100644 --- a/16-op-overloading/vector_v8.py +++ b/16-op-overloading/vector_v8.py @@ -361,14 +361,16 @@ def __getitem__(self, key): index = operator.index(key) return self._components[index] - shortcut_names = 'xyzt' + __match_args__ = ('x', 'y', 'z', 't') def __getattr__(self, name): cls = type(self) - if len(name) == 1: - pos = cls.shortcut_names.find(name) - if 0 <= pos < len(self._components): - return self._components[pos] + try: + pos = cls.__match_args__.index(name) + except ValueError: + pos = -1 + if 0 <= pos < len(self._components): + return self._components[pos] msg = f'{cls.__name__!r} object has no attribute {name!r}' raise AttributeError(msg) From fa1cd6bd5ef63e3623e71debe3f218a6befdbc64 Mon Sep 17 00:00:00 2001 From: kbaikov Date: Sun, 22 Aug 2021 16:29:22 +0200 Subject: [PATCH 03/66] Use fixture instead of yield_fixture The old @pytest.yield_fixture causes a deprecation warning: Use @pytest.fixture instead; they are the same. def records(): --- 23-dyn-attr-prop/oscon/test_schedule_v1.py | 2 +- 23-dyn-attr-prop/oscon/test_schedule_v2.py | 2 +- 23-dyn-attr-prop/oscon/test_schedule_v3.py | 2 +- 23-dyn-attr-prop/oscon/test_schedule_v4.py | 2 +- 23-dyn-attr-prop/oscon/test_schedule_v5.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/23-dyn-attr-prop/oscon/test_schedule_v1.py b/23-dyn-attr-prop/oscon/test_schedule_v1.py index 643f04f..cfd7dd0 100644 --- a/23-dyn-attr-prop/oscon/test_schedule_v1.py +++ b/23-dyn-attr-prop/oscon/test_schedule_v1.py @@ -3,7 +3,7 @@ import schedule_v1 as schedule -@pytest.yield_fixture +@pytest.fixture def records(): yield schedule.load(schedule.JSON_PATH) diff --git a/23-dyn-attr-prop/oscon/test_schedule_v2.py b/23-dyn-attr-prop/oscon/test_schedule_v2.py index a11b24d..e15d640 100644 --- a/23-dyn-attr-prop/oscon/test_schedule_v2.py +++ b/23-dyn-attr-prop/oscon/test_schedule_v2.py @@ -2,7 +2,7 @@ import schedule_v2 as schedule -@pytest.yield_fixture +@pytest.fixture def records(): yield schedule.load(schedule.JSON_PATH) diff --git a/23-dyn-attr-prop/oscon/test_schedule_v3.py b/23-dyn-attr-prop/oscon/test_schedule_v3.py index 1b7ea75..d9436d4 100644 --- a/23-dyn-attr-prop/oscon/test_schedule_v3.py +++ b/23-dyn-attr-prop/oscon/test_schedule_v3.py @@ -2,7 +2,7 @@ import schedule_v3 as schedule -@pytest.yield_fixture +@pytest.fixture def records(): yield schedule.load(schedule.JSON_PATH) diff --git a/23-dyn-attr-prop/oscon/test_schedule_v4.py b/23-dyn-attr-prop/oscon/test_schedule_v4.py index 1e5560a..4980bbd 100644 --- a/23-dyn-attr-prop/oscon/test_schedule_v4.py +++ b/23-dyn-attr-prop/oscon/test_schedule_v4.py @@ -2,7 +2,7 @@ import schedule_v4 as schedule -@pytest.yield_fixture +@pytest.fixture def records(): yield schedule.load(schedule.JSON_PATH) diff --git a/23-dyn-attr-prop/oscon/test_schedule_v5.py b/23-dyn-attr-prop/oscon/test_schedule_v5.py index 2151844..e3a5206 100644 --- a/23-dyn-attr-prop/oscon/test_schedule_v5.py +++ b/23-dyn-attr-prop/oscon/test_schedule_v5.py @@ -2,7 +2,7 @@ import schedule_v5 as schedule -@pytest.yield_fixture +@pytest.fixture def records(): yield schedule.load(schedule.JSON_PATH) From dd535abcf76739d451c2baaf7813b8390a7dfe88 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Wed, 25 Aug 2021 14:46:57 -0300 Subject: [PATCH 04/66] sync from Atlas --- 08-def-type-hints/columnize.py | 15 +++++++------ 15-more-types/cast/find.py | 2 +- 15-more-types/protocol/abs_demo.py | 4 ---- 15-more-types/protocol/mymax/mymax.py | 3 ++- 15-more-types/typeddict/books.py | 6 +++--- 15-more-types/typeddict/books_any.py | 4 ++-- 16-op-overloading/bingoaddable.py | 8 +++---- 17-it-generator/aritprog_v1.py | 2 +- 17-it-generator/aritprog_v2.py | 2 +- 17-it-generator/columnize_iter.py | 21 +++++++++--------- 17-it-generator/iter_gen_type.py | 13 +++++++++++ 17-it-generator/tree/step2/tree.py | 2 +- 23-dyn-attr-prop/oscon/data/osconfeed.json | 2 +- 23-dyn-attr-prop/oscon/demo_schedule2.py | 25 ---------------------- 23-dyn-attr-prop/oscon/test_schedule_v3.py | 2 +- 23-dyn-attr-prop/pseudo_construction.py | 2 +- 16 files changed, 51 insertions(+), 62 deletions(-) create mode 100644 17-it-generator/iter_gen_type.py delete mode 100755 23-dyn-attr-prop/oscon/demo_schedule2.py diff --git a/08-def-type-hints/columnize.py b/08-def-type-hints/columnize.py index 66b72d8..8f4e92b 100644 --- a/08-def-type-hints/columnize.py +++ b/08-def-type-hints/columnize.py @@ -1,9 +1,11 @@ # tag::COLUMNIZE[] from collections.abc import Sequence -def columnize(sequence: Sequence[str], num_columns: int = 0) -> list[tuple[str, ...]]: +def columnize( + sequence: Sequence[str], num_columns: int = 0 +) -> list[tuple[str, ...]]: if num_columns == 0: - num_columns = round(len(sequence) ** .5) + num_columns = round(len(sequence) ** 0.5) num_rows, reminder = divmod(len(sequence), num_columns) num_rows += bool(reminder) return [tuple(sequence[i::num_rows]) for i in range(num_rows)] @@ -11,10 +13,11 @@ def columnize(sequence: Sequence[str], num_columns: int = 0) -> list[tuple[str, def demo() -> None: - nato = ('Alfa Bravo Charlie Delta Echo Foxtrot Golf Hotel India' - ' Juliett Kilo Lima Mike November Oscar Papa Quebec Romeo' - ' Sierra Tango Uniform Victor Whiskey X-ray Yankee Zulu' - ).split() + nato = ( + 'Alfa Bravo Charlie Delta Echo Foxtrot Golf Hotel India' + ' Juliett Kilo Lima Mike November Oscar Papa Quebec Romeo' + ' Sierra Tango Uniform Victor Whiskey X-ray Yankee Zulu' + ).split() for row in columnize(nato, 4): for word in row: diff --git a/15-more-types/cast/find.py b/15-more-types/cast/find.py index c853ea8..e79fe5b 100644 --- a/15-more-types/cast/find.py +++ b/15-more-types/cast/find.py @@ -3,7 +3,7 @@ def find_first_str(a: list[object]) -> str: index = next(i for i, x in enumerate(a) if isinstance(x, str)) - # We only get here if there's at least one string in a + # We only get here if there's at least one string return cast(str, a[index]) # end::CAST[] diff --git a/15-more-types/protocol/abs_demo.py b/15-more-types/protocol/abs_demo.py index 6af78ea..9c0b74c 100755 --- a/15-more-types/protocol/abs_demo.py +++ b/15-more-types/protocol/abs_demo.py @@ -1,6 +1,3 @@ -#!/usr/bin/env python3 - -# tag::ABS_DEMO[] import math from typing import NamedTuple, SupportsAbs @@ -31,4 +28,3 @@ def is_unit(v: SupportsAbs[float]) -> bool: # <2> assert is_unit(v4) print('OK') -# end::ABS_DEMO[] diff --git a/15-more-types/protocol/mymax/mymax.py b/15-more-types/protocol/mymax/mymax.py index 5b9f4b2..6096985 100644 --- a/15-more-types/protocol/mymax/mymax.py +++ b/15-more-types/protocol/mymax/mymax.py @@ -1,5 +1,6 @@ # tag::MYMAX_TYPES[] -from typing import Protocol, Any, TypeVar, overload, Callable, Iterable, Union +from collections.abc import Callable, Iterable +from typing import Protocol, Any, TypeVar, overload, Union class SupportsLessThan(Protocol): def __lt__(self, other: Any) -> bool: ... diff --git a/15-more-types/typeddict/books.py b/15-more-types/typeddict/books.py index e33e21e..8caca46 100644 --- a/15-more-types/typeddict/books.py +++ b/15-more-types/typeddict/books.py @@ -1,6 +1,6 @@ +import json # tag::BOOKDICT[] from typing import TypedDict -import json class BookDict(TypedDict): isbn: str @@ -10,14 +10,14 @@ class BookDict(TypedDict): # end::BOOKDICT[] # tag::TOXML[] -AUTHOR_EL = '{}' +AUTHOR_ELEMENT = '{}' def to_xml(book: BookDict) -> str: # <1> elements: list[str] = [] # <2> for key, value in book.items(): if isinstance(value, list): # <3> elements.extend( - AUTHOR_EL.format(n) for n in value) # <4> + AUTHOR_ELEMENT.format(n) for n in value) # <4> else: tag = key.upper() elements.append(f'<{tag}>{value}') diff --git a/15-more-types/typeddict/books_any.py b/15-more-types/typeddict/books_any.py index 49a544e..0a5e1e4 100644 --- a/15-more-types/typeddict/books_any.py +++ b/15-more-types/typeddict/books_any.py @@ -10,13 +10,13 @@ class BookDict(TypedDict): # end::BOOKDICT[] # tag::TOXML[] -AUTHOR_EL = '{}' +AUTHOR_ELEMENT = '{}' def to_xml(book: BookDict) -> str: # <1> elements: List[str] = [] # <2> for key, value in book.items(): if isinstance(value, list): # <3> - elements.extend(AUTHOR_EL.format(n) + elements.extend(AUTHOR_ELEMENT.format(n) for n in value) else: tag = key.upper() diff --git a/16-op-overloading/bingoaddable.py b/16-op-overloading/bingoaddable.py index 38a70c7..da667d4 100644 --- a/16-op-overloading/bingoaddable.py +++ b/16-op-overloading/bingoaddable.py @@ -46,7 +46,7 @@ >>> globe += 1 # <6> Traceback (most recent call last): ... - TypeError: right operand in += must be 'AddableBingoCage' or an iterable + TypeError: right operand in += must be 'Tombola' or an iterable # end::ADDABLE_BINGO_IADD_DEMO[] @@ -72,9 +72,9 @@ def __iadd__(self, other): try: other_iterable = iter(other) # <4> except TypeError: # <5> - self_cls = type(self).__name__ - msg = "right operand in += must be {!r} or an iterable" - raise TypeError(msg.format(self_cls)) + msg = ('right operand in += must be ' + "'Tombola' or an iterable") + raise TypeError(msg) self.load(other_iterable) # <6> return self # <7> diff --git a/17-it-generator/aritprog_v1.py b/17-it-generator/aritprog_v1.py index 2ae66c4..69259bc 100644 --- a/17-it-generator/aritprog_v1.py +++ b/17-it-generator/aritprog_v1.py @@ -19,7 +19,7 @@ >>> from decimal import Decimal >>> ap = ArithmeticProgression(0, Decimal('.1'), .3) >>> list(ap) - [Decimal('0.0'), Decimal('0.1'), Decimal('0.2')] + [Decimal('0'), Decimal('0.1'), Decimal('0.2')] # end::ARITPROG_CLASS_DEMO[] """ diff --git a/17-it-generator/aritprog_v2.py b/17-it-generator/aritprog_v2.py index be211d8..42e27f8 100644 --- a/17-it-generator/aritprog_v2.py +++ b/17-it-generator/aritprog_v2.py @@ -14,7 +14,7 @@ >>> from decimal import Decimal >>> ap = aritprog_gen(0, Decimal('.1'), .3) >>> list(ap) - [Decimal('0.0'), Decimal('0.1'), Decimal('0.2')] + [Decimal('0'), Decimal('0.1'), Decimal('0.2')] """ diff --git a/17-it-generator/columnize_iter.py b/17-it-generator/columnize_iter.py index c9a6f7d..cee0f13 100644 --- a/17-it-generator/columnize_iter.py +++ b/17-it-generator/columnize_iter.py @@ -1,26 +1,27 @@ # tag::COLUMNIZE[] -from typing import Sequence, Tuple, Iterator +from collections.abc import Sequence, Iterator -def columnize(sequence: Sequence[str], num_columns: int = 0) -> Iterator[Tuple[str, ...]]: +def columnize( + sequence: Sequence[str], num_columns: int = 0 +) -> Iterator[tuple[str, ...]]: # <1> if num_columns == 0: - num_columns = round(len(sequence) ** .5) + num_columns = round(len(sequence) ** 0.5) num_rows, reminder = divmod(len(sequence), num_columns) num_rows += bool(reminder) - return (tuple(sequence[i::num_rows]) for i in range(num_rows)) + return (tuple(sequence[i::num_rows]) for i in range(num_rows)) # <2> # end::COLUMNIZE[] - def demo() -> None: - nato = ('Alfa Bravo Charlie Delta Echo Foxtrot Golf Hotel India' - ' Juliett Kilo Lima Mike November Oscar Papa Quebec Romeo' - ' Sierra Tango Uniform Victor Whiskey X-ray Yankee Zulu' - ).split() + nato = ( + 'Alfa Bravo Charlie Delta Echo Foxtrot Golf Hotel India' + ' Juliett Kilo Lima Mike November Oscar Papa Quebec Romeo' + ' Sierra Tango Uniform Victor Whiskey X-ray Yankee Zulu' + ).split() for row in columnize(nato, 4): for word in row: print(f'{word:15}', end='') print() - if __name__ == '__main__': demo() diff --git a/17-it-generator/iter_gen_type.py b/17-it-generator/iter_gen_type.py new file mode 100644 index 0000000..1730d87 --- /dev/null +++ b/17-it-generator/iter_gen_type.py @@ -0,0 +1,13 @@ +from collections.abc import Iterator +from keyword import kwlist +from typing import TYPE_CHECKING + +short_kw = (k for k in kwlist if len(k) < 5) # <1> + +if TYPE_CHECKING: + reveal_type(short_kw) # <2> + +long_kw: Iterator[str] = (k for k in kwlist if len(k) >= 4) # <3> + +if TYPE_CHECKING: # <4> + reveal_type(long_kw) diff --git a/17-it-generator/tree/step2/tree.py b/17-it-generator/tree/step2/tree.py index d4078b4..6a0e1fa 100644 --- a/17-it-generator/tree/step2/tree.py +++ b/17-it-generator/tree/step2/tree.py @@ -9,7 +9,7 @@ def sub_tree(cls): def display(cls): - for cls_name, level in tree(cls): + for cls_name, level in tree(cls): # <3> indent = ' ' * 4 * level print(f'{indent}{cls_name}') diff --git a/23-dyn-attr-prop/oscon/data/osconfeed.json b/23-dyn-attr-prop/oscon/data/osconfeed.json index 50ed313..7bea08d 100644 --- a/23-dyn-attr-prop/oscon/data/osconfeed.json +++ b/23-dyn-attr-prop/oscon/data/osconfeed.json @@ -1243,7 +1243,7 @@ "time_start": "2014-07-21 13:30:00", "time_stop": "2014-07-21 17:00:00", "venue_serial": 1451, - "description": "Metaprograming in Python is fun and profitable thanks to its rich Data Model \u2013 APIs that let you handle functions, modules and even classes as objects that you can create, inspect and modify at runtime. The Data Model also enables your own objects to support infix operators, become iterable and emulate collections. This workshop shows how, through a diverse selection of examples and exercises.", + "description": "Metaprogramming in Python is fun and profitable thanks to its rich Data Model \u2013 APIs that let you handle functions, modules and even classes as objects that you can create, inspect and modify at runtime. The Data Model also enables your own objects to support infix operators, become iterable and emulate collections. This workshop shows how, through a diverse selection of examples and exercises.", "website_url": "http://oscon.com/oscon2014/public/schedule/detail/34107", "speakers": [150170], "categories": [ diff --git a/23-dyn-attr-prop/oscon/demo_schedule2.py b/23-dyn-attr-prop/oscon/demo_schedule2.py deleted file mode 100755 index 12fd440..0000000 --- a/23-dyn-attr-prop/oscon/demo_schedule2.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env python3 - -import shelve - -from schedule_v2 import DB_NAME, CONFERENCE, load_db -from schedule_v2 import DbRecord, Event - -with shelve.open(DB_NAME) as db: - if CONFERENCE not in db: - load_db(db) - - DbRecord.set_db(db) - event = DbRecord.fetch('event.33950') - print(event) - print(event.venue) - print(event.venue.name) - for spkr in event.speakers: - print(f'{spkr.serial}:', spkr.name) - - print(repr(Event.venue)) - - event2 = DbRecord.fetch('event.33451') - print(event2) - print(event2.fetch) - print(event2.venue) \ No newline at end of file diff --git a/23-dyn-attr-prop/oscon/test_schedule_v3.py b/23-dyn-attr-prop/oscon/test_schedule_v3.py index d9436d4..12332c4 100644 --- a/23-dyn-attr-prop/oscon/test_schedule_v3.py +++ b/23-dyn-attr-prop/oscon/test_schedule_v3.py @@ -56,4 +56,4 @@ def test_event_speakers(): def test_event_no_speakers(): event = schedule.Record.fetch('event.36848') - assert event.speakers == [] \ No newline at end of file + assert event.speakers == [] diff --git a/23-dyn-attr-prop/pseudo_construction.py b/23-dyn-attr-prop/pseudo_construction.py index 5656192..af651a2 100644 --- a/23-dyn-attr-prop/pseudo_construction.py +++ b/23-dyn-attr-prop/pseudo_construction.py @@ -1,4 +1,4 @@ -# pseudo-code for object construction +# pseudocode for object construction def make(the_class, some_arg): new_object = the_class.__new__(some_arg) if isinstance(new_object, the_class): From 4ae4096c4cb8848d0c1dcf24ff2cb7efb72e3b2b Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Fri, 10 Sep 2021 12:34:39 -0300 Subject: [PATCH 05/66] renumbering chapters >= 19 --- .../primes/log-procs.txt | 0 .../primes/primes.py | 0 .../primes/procs.py | 0 .../primes/py36/primes.py | 0 .../primes/py36/procs.py | 0 .../primes/run_procs.sh | 0 .../primes/sequential.py | 0 .../primes/spinner_prime_async_broken.py | 0 .../primes/spinner_prime_async_nap.py | 0 .../primes/spinner_prime_proc.py | 0 .../primes/spinner_prime_thread.py | 0 .../primes/stats-procs.ipynb | 0 .../primes/threads.py | 0 .../spinner_async.py | 0 .../spinner_async_experiment.py | 0 .../spinner_proc.py | 0 .../spinner_thread.py | 0 19-coroutine/README.rst | 4 - 19-coroutine/coro_exc_demo.py | 66 ----- 19-coroutine/coro_finally_demo.py | 61 ----- 19-coroutine/coroaverager0.py | 28 -- 19-coroutine/coroaverager1.py | 30 --- 19-coroutine/coroaverager2.py | 61 ----- 19-coroutine/coroaverager3.py | 107 -------- 19-coroutine/coroutil.py | 12 - 19-coroutine/taxi_sim.py | 203 -------------- 19-coroutine/taxi_sim0.py | 255 ------------------ 19-coroutine/taxi_sim_delay.py | 215 --------------- 19-coroutine/yield_from_expansion.py | 52 ---- .../yield_from_expansion_simplified.py | 32 --- .../demo_executor_map.py | 0 .../getflags/.gitignore | 0 .../getflags/country_codes.txt | 0 .../getflags/downloaded/.gitignore | 0 {21-futures => 20-futures}/getflags/flags.py | 0 {21-futures => 20-futures}/getflags/flags.zip | Bin .../getflags/flags2_asyncio.py | 0 .../getflags/flags2_asyncio_executor.py | 0 .../getflags/flags2_common.py | 0 .../getflags/flags2_sequential.py | 0 .../getflags/flags2_threadpool.py | 0 .../getflags/flags3_asyncio.py | 0 .../getflags/flags_asyncio.py | 0 .../getflags/flags_threadpool.py | 0 .../getflags/flags_threadpool_futures.py | 0 .../getflags/requirements.txt | 0 .../getflags/slow_server.py | 0 {21-futures => 20-futures}/primes/primes.py | 0 .../primes/proc_pool.py | 0 {22-async => 21-async}/README.rst | 0 {22-async => 21-async}/domains/README.rst | 0 .../domains/asyncio/blogdom.py | 0 .../domains/asyncio/domaincheck.py | 0 .../domains/asyncio/domainlib.py | 0 .../domains/curio/blogdom.py | 0 .../domains/curio/domaincheck.py | 0 .../domains/curio/domainlib.py | 0 .../domains/curio/requirements.txt | 0 {22-async => 21-async}/mojifinder/README.md | 0 {22-async => 21-async}/mojifinder/bottle.py | 0 .../mojifinder/charindex.py | 0 .../mojifinder/requirements.txt | 0 .../mojifinder/static/form.html | 0 .../mojifinder/tcp_mojifinder.py | 0 .../mojifinder/web_mojifinder.py | 0 .../mojifinder/web_mojifinder_bottle.py | 0 .../README.rst | 0 .../blackknight.py | 0 .../bulkfood/bulkfood_v1.py | 0 .../bulkfood/bulkfood_v2.py | 0 .../bulkfood/bulkfood_v2b.py | 0 .../bulkfood/bulkfood_v2prop.py | 0 .../doc_property.py | 0 .../oscon/data/osconfeed.json | 0 .../oscon/demo_schedule2.py | 0 .../oscon/explore0.py | 0 .../oscon/explore1.py | 0 .../oscon/explore2.py | 0 .../oscon/osconfeed-sample.json | 0 .../oscon/osconfeed_explore.rst | 0 .../oscon/runtests.sh | 0 .../oscon/schedule_v1.py | 0 .../oscon/schedule_v2.py | 0 .../oscon/schedule_v3.py | 0 .../oscon/schedule_v4.py | 0 .../oscon/schedule_v4_hasattr.py | 0 .../oscon/schedule_v5.py | 0 .../oscon/test_schedule_v1.py | 0 .../oscon/test_schedule_v2.py | 0 .../oscon/test_schedule_v3.py | 0 .../oscon/test_schedule_v4.py | 0 .../oscon/test_schedule_v5.py | 0 .../pseudo_construction.py | 0 {24-descriptor => 23-descriptor}/README.rst | 0 .../bulkfood/bulkfood_v3.py | 0 .../bulkfood/bulkfood_v4.py | 0 .../bulkfood/bulkfood_v4c.py | 0 .../bulkfood/bulkfood_v5.py | 0 .../bulkfood/model_v4c.py | 0 .../bulkfood/model_v5.py | 0 .../descriptorkinds.py | 0 .../descriptorkinds_dump.py | 0 .../method_is_descriptor.py | 0 .../autoconst/autoconst.py | 0 .../autoconst/autoconst_demo.py | 0 .../bulkfood/README.md | 0 .../bulkfood/bulkfood_v6.py | 0 .../bulkfood/bulkfood_v7.py | 0 .../bulkfood/bulkfood_v8.py | 0 .../bulkfood/model_v6.py | 0 .../bulkfood/model_v7.py | 0 .../bulkfood/model_v8.py | 0 .../checked/decorator/checkeddeco.py | 0 .../checked/decorator/checkeddeco_demo.py | 0 .../checked/decorator/checkeddeco_test.py | 0 .../checked/initsub/checked_demo.py | 0 .../checked/initsub/checkedlib.py | 0 .../checked/initsub/checkedlib_test.py | 0 .../checked/metaclass/checked_demo.py | 0 .../checked/metaclass/checkedlib.py | 0 .../checked/metaclass/checkedlib_test.py | 0 .../evaltime/builderlib.py | 0 .../evaltime/evaldemo.py | 0 .../evaltime/evaldemo_meta.py | 0 .../evaltime/metalib.py | 0 .../factories.py | 0 .../factories_ducktyped.py | 0 .../hours/hours.py | 0 .../hours/hours_test.py | 0 .../metabunch/README.md | 0 .../metabunch/from3.6/bunch.py | 0 .../metabunch/from3.6/bunch_test.py | 0 .../metabunch/nutshell3e/bunch.py | 0 .../metabunch/nutshell3e/bunch_test.py | 0 .../metabunch/original/bunch.py | 0 .../metabunch/original/bunch_test.py | 0 .../metabunch/pre3.6/bunch.py | 0 .../metabunch/pre3.6/bunch_test.py | 0 .../persistent/.gitignore | 0 .../persistent/dblib.py | 0 .../persistent/dblib_test.py | 0 .../persistent/persistlib.py | 0 .../persistent/persistlib_test.py | 0 .../qualname/fakedjango.py | 0 .../qualname/models.py | 0 .../sentinel/sentinel.py | 0 .../sentinel/sentinel_test.py | 0 .../setattr/example_from_leo.py | 0 .../slots/slots_timing.py | 0 .../tinyenums/microenum.py | 0 .../tinyenums/microenum_demo.py | 0 .../tinyenums/nanoenum.py | 0 .../tinyenums/nanoenum_demo.py | 0 README.md | 15 +- 154 files changed, 7 insertions(+), 1134 deletions(-) rename {20-concurrency => 19-concurrency}/primes/log-procs.txt (100%) rename {20-concurrency => 19-concurrency}/primes/primes.py (100%) rename {20-concurrency => 19-concurrency}/primes/procs.py (100%) rename {20-concurrency => 19-concurrency}/primes/py36/primes.py (100%) rename {20-concurrency => 19-concurrency}/primes/py36/procs.py (100%) rename {20-concurrency => 19-concurrency}/primes/run_procs.sh (100%) rename {20-concurrency => 19-concurrency}/primes/sequential.py (100%) rename {20-concurrency => 19-concurrency}/primes/spinner_prime_async_broken.py (100%) rename {20-concurrency => 19-concurrency}/primes/spinner_prime_async_nap.py (100%) rename {20-concurrency => 19-concurrency}/primes/spinner_prime_proc.py (100%) rename {20-concurrency => 19-concurrency}/primes/spinner_prime_thread.py (100%) rename {20-concurrency => 19-concurrency}/primes/stats-procs.ipynb (100%) rename {20-concurrency => 19-concurrency}/primes/threads.py (100%) rename {20-concurrency => 19-concurrency}/spinner_async.py (100%) rename {20-concurrency => 19-concurrency}/spinner_async_experiment.py (100%) rename {20-concurrency => 19-concurrency}/spinner_proc.py (100%) rename {20-concurrency => 19-concurrency}/spinner_thread.py (100%) delete mode 100644 19-coroutine/README.rst delete mode 100644 19-coroutine/coro_exc_demo.py delete mode 100644 19-coroutine/coro_finally_demo.py delete mode 100644 19-coroutine/coroaverager0.py delete mode 100644 19-coroutine/coroaverager1.py delete mode 100644 19-coroutine/coroaverager2.py delete mode 100644 19-coroutine/coroaverager3.py delete mode 100644 19-coroutine/coroutil.py delete mode 100644 19-coroutine/taxi_sim.py delete mode 100644 19-coroutine/taxi_sim0.py delete mode 100644 19-coroutine/taxi_sim_delay.py delete mode 100644 19-coroutine/yield_from_expansion.py delete mode 100644 19-coroutine/yield_from_expansion_simplified.py rename {21-futures => 20-futures}/demo_executor_map.py (100%) rename {21-futures => 20-futures}/getflags/.gitignore (100%) rename {21-futures => 20-futures}/getflags/country_codes.txt (100%) rename {21-futures => 20-futures}/getflags/downloaded/.gitignore (100%) rename {21-futures => 20-futures}/getflags/flags.py (100%) rename {21-futures => 20-futures}/getflags/flags.zip (100%) rename {21-futures => 20-futures}/getflags/flags2_asyncio.py (100%) rename {21-futures => 20-futures}/getflags/flags2_asyncio_executor.py (100%) rename {21-futures => 20-futures}/getflags/flags2_common.py (100%) rename {21-futures => 20-futures}/getflags/flags2_sequential.py (100%) rename {21-futures => 20-futures}/getflags/flags2_threadpool.py (100%) rename {21-futures => 20-futures}/getflags/flags3_asyncio.py (100%) rename {21-futures => 20-futures}/getflags/flags_asyncio.py (100%) rename {21-futures => 20-futures}/getflags/flags_threadpool.py (100%) rename {21-futures => 20-futures}/getflags/flags_threadpool_futures.py (100%) rename {21-futures => 20-futures}/getflags/requirements.txt (100%) rename {21-futures => 20-futures}/getflags/slow_server.py (100%) rename {21-futures => 20-futures}/primes/primes.py (100%) rename {21-futures => 20-futures}/primes/proc_pool.py (100%) rename {22-async => 21-async}/README.rst (100%) rename {22-async => 21-async}/domains/README.rst (100%) rename {22-async => 21-async}/domains/asyncio/blogdom.py (100%) rename {22-async => 21-async}/domains/asyncio/domaincheck.py (100%) rename {22-async => 21-async}/domains/asyncio/domainlib.py (100%) rename {22-async => 21-async}/domains/curio/blogdom.py (100%) rename {22-async => 21-async}/domains/curio/domaincheck.py (100%) rename {22-async => 21-async}/domains/curio/domainlib.py (100%) rename {22-async => 21-async}/domains/curio/requirements.txt (100%) rename {22-async => 21-async}/mojifinder/README.md (100%) rename {22-async => 21-async}/mojifinder/bottle.py (100%) rename {22-async => 21-async}/mojifinder/charindex.py (100%) rename {22-async => 21-async}/mojifinder/requirements.txt (100%) rename {22-async => 21-async}/mojifinder/static/form.html (100%) rename {22-async => 21-async}/mojifinder/tcp_mojifinder.py (100%) rename {22-async => 21-async}/mojifinder/web_mojifinder.py (100%) rename {22-async => 21-async}/mojifinder/web_mojifinder_bottle.py (100%) rename {23-dyn-attr-prop => 22-dyn-attr-prop}/README.rst (100%) rename {23-dyn-attr-prop => 22-dyn-attr-prop}/blackknight.py (100%) rename {23-dyn-attr-prop => 22-dyn-attr-prop}/bulkfood/bulkfood_v1.py (100%) rename {23-dyn-attr-prop => 22-dyn-attr-prop}/bulkfood/bulkfood_v2.py (100%) rename {23-dyn-attr-prop => 22-dyn-attr-prop}/bulkfood/bulkfood_v2b.py (100%) rename {23-dyn-attr-prop => 22-dyn-attr-prop}/bulkfood/bulkfood_v2prop.py (100%) rename {23-dyn-attr-prop => 22-dyn-attr-prop}/doc_property.py (100%) rename {23-dyn-attr-prop => 22-dyn-attr-prop}/oscon/data/osconfeed.json (100%) rename {23-dyn-attr-prop => 22-dyn-attr-prop}/oscon/demo_schedule2.py (100%) rename {23-dyn-attr-prop => 22-dyn-attr-prop}/oscon/explore0.py (100%) rename {23-dyn-attr-prop => 22-dyn-attr-prop}/oscon/explore1.py (100%) rename {23-dyn-attr-prop => 22-dyn-attr-prop}/oscon/explore2.py (100%) rename {23-dyn-attr-prop => 22-dyn-attr-prop}/oscon/osconfeed-sample.json (100%) rename {23-dyn-attr-prop => 22-dyn-attr-prop}/oscon/osconfeed_explore.rst (100%) rename {23-dyn-attr-prop => 22-dyn-attr-prop}/oscon/runtests.sh (100%) rename {23-dyn-attr-prop => 22-dyn-attr-prop}/oscon/schedule_v1.py (100%) rename {23-dyn-attr-prop => 22-dyn-attr-prop}/oscon/schedule_v2.py (100%) rename {23-dyn-attr-prop => 22-dyn-attr-prop}/oscon/schedule_v3.py (100%) rename {23-dyn-attr-prop => 22-dyn-attr-prop}/oscon/schedule_v4.py (100%) rename {23-dyn-attr-prop => 22-dyn-attr-prop}/oscon/schedule_v4_hasattr.py (100%) rename {23-dyn-attr-prop => 22-dyn-attr-prop}/oscon/schedule_v5.py (100%) rename {23-dyn-attr-prop => 22-dyn-attr-prop}/oscon/test_schedule_v1.py (100%) rename {23-dyn-attr-prop => 22-dyn-attr-prop}/oscon/test_schedule_v2.py (100%) rename {23-dyn-attr-prop => 22-dyn-attr-prop}/oscon/test_schedule_v3.py (100%) rename {23-dyn-attr-prop => 22-dyn-attr-prop}/oscon/test_schedule_v4.py (100%) rename {23-dyn-attr-prop => 22-dyn-attr-prop}/oscon/test_schedule_v5.py (100%) rename {23-dyn-attr-prop => 22-dyn-attr-prop}/pseudo_construction.py (100%) rename {24-descriptor => 23-descriptor}/README.rst (100%) rename {24-descriptor => 23-descriptor}/bulkfood/bulkfood_v3.py (100%) rename {24-descriptor => 23-descriptor}/bulkfood/bulkfood_v4.py (100%) rename {24-descriptor => 23-descriptor}/bulkfood/bulkfood_v4c.py (100%) rename {24-descriptor => 23-descriptor}/bulkfood/bulkfood_v5.py (100%) rename {24-descriptor => 23-descriptor}/bulkfood/model_v4c.py (100%) rename {24-descriptor => 23-descriptor}/bulkfood/model_v5.py (100%) rename {24-descriptor => 23-descriptor}/descriptorkinds.py (100%) rename {24-descriptor => 23-descriptor}/descriptorkinds_dump.py (100%) rename {24-descriptor => 23-descriptor}/method_is_descriptor.py (100%) rename {25-class-metaprog => 24-class-metaprog}/autoconst/autoconst.py (100%) rename {25-class-metaprog => 24-class-metaprog}/autoconst/autoconst_demo.py (100%) rename {25-class-metaprog => 24-class-metaprog}/bulkfood/README.md (100%) rename {25-class-metaprog => 24-class-metaprog}/bulkfood/bulkfood_v6.py (100%) rename {25-class-metaprog => 24-class-metaprog}/bulkfood/bulkfood_v7.py (100%) rename {25-class-metaprog => 24-class-metaprog}/bulkfood/bulkfood_v8.py (100%) rename {25-class-metaprog => 24-class-metaprog}/bulkfood/model_v6.py (100%) rename {25-class-metaprog => 24-class-metaprog}/bulkfood/model_v7.py (100%) rename {25-class-metaprog => 24-class-metaprog}/bulkfood/model_v8.py (100%) rename {25-class-metaprog => 24-class-metaprog}/checked/decorator/checkeddeco.py (100%) rename {25-class-metaprog => 24-class-metaprog}/checked/decorator/checkeddeco_demo.py (100%) rename {25-class-metaprog => 24-class-metaprog}/checked/decorator/checkeddeco_test.py (100%) rename {25-class-metaprog => 24-class-metaprog}/checked/initsub/checked_demo.py (100%) rename {25-class-metaprog => 24-class-metaprog}/checked/initsub/checkedlib.py (100%) rename {25-class-metaprog => 24-class-metaprog}/checked/initsub/checkedlib_test.py (100%) rename {25-class-metaprog => 24-class-metaprog}/checked/metaclass/checked_demo.py (100%) rename {25-class-metaprog => 24-class-metaprog}/checked/metaclass/checkedlib.py (100%) rename {25-class-metaprog => 24-class-metaprog}/checked/metaclass/checkedlib_test.py (100%) rename {25-class-metaprog => 24-class-metaprog}/evaltime/builderlib.py (100%) rename {25-class-metaprog => 24-class-metaprog}/evaltime/evaldemo.py (100%) rename {25-class-metaprog => 24-class-metaprog}/evaltime/evaldemo_meta.py (100%) rename {25-class-metaprog => 24-class-metaprog}/evaltime/metalib.py (100%) rename {25-class-metaprog => 24-class-metaprog}/factories.py (100%) rename {25-class-metaprog => 24-class-metaprog}/factories_ducktyped.py (100%) rename {25-class-metaprog => 24-class-metaprog}/hours/hours.py (100%) rename {25-class-metaprog => 24-class-metaprog}/hours/hours_test.py (100%) rename {25-class-metaprog => 24-class-metaprog}/metabunch/README.md (100%) rename {25-class-metaprog => 24-class-metaprog}/metabunch/from3.6/bunch.py (100%) rename {25-class-metaprog => 24-class-metaprog}/metabunch/from3.6/bunch_test.py (100%) rename {25-class-metaprog => 24-class-metaprog}/metabunch/nutshell3e/bunch.py (100%) rename {25-class-metaprog => 24-class-metaprog}/metabunch/nutshell3e/bunch_test.py (100%) rename {25-class-metaprog => 24-class-metaprog}/metabunch/original/bunch.py (100%) rename {25-class-metaprog => 24-class-metaprog}/metabunch/original/bunch_test.py (100%) rename {25-class-metaprog => 24-class-metaprog}/metabunch/pre3.6/bunch.py (100%) rename {25-class-metaprog => 24-class-metaprog}/metabunch/pre3.6/bunch_test.py (100%) rename {25-class-metaprog => 24-class-metaprog}/persistent/.gitignore (100%) rename {25-class-metaprog => 24-class-metaprog}/persistent/dblib.py (100%) rename {25-class-metaprog => 24-class-metaprog}/persistent/dblib_test.py (100%) rename {25-class-metaprog => 24-class-metaprog}/persistent/persistlib.py (100%) rename {25-class-metaprog => 24-class-metaprog}/persistent/persistlib_test.py (100%) rename {25-class-metaprog => 24-class-metaprog}/qualname/fakedjango.py (100%) rename {25-class-metaprog => 24-class-metaprog}/qualname/models.py (100%) rename {25-class-metaprog => 24-class-metaprog}/sentinel/sentinel.py (100%) rename {25-class-metaprog => 24-class-metaprog}/sentinel/sentinel_test.py (100%) rename {25-class-metaprog => 24-class-metaprog}/setattr/example_from_leo.py (100%) rename {25-class-metaprog => 24-class-metaprog}/slots/slots_timing.py (100%) rename {25-class-metaprog => 24-class-metaprog}/tinyenums/microenum.py (100%) rename {25-class-metaprog => 24-class-metaprog}/tinyenums/microenum_demo.py (100%) rename {25-class-metaprog => 24-class-metaprog}/tinyenums/nanoenum.py (100%) rename {25-class-metaprog => 24-class-metaprog}/tinyenums/nanoenum_demo.py (100%) diff --git a/20-concurrency/primes/log-procs.txt b/19-concurrency/primes/log-procs.txt similarity index 100% rename from 20-concurrency/primes/log-procs.txt rename to 19-concurrency/primes/log-procs.txt diff --git a/20-concurrency/primes/primes.py b/19-concurrency/primes/primes.py similarity index 100% rename from 20-concurrency/primes/primes.py rename to 19-concurrency/primes/primes.py diff --git a/20-concurrency/primes/procs.py b/19-concurrency/primes/procs.py similarity index 100% rename from 20-concurrency/primes/procs.py rename to 19-concurrency/primes/procs.py diff --git a/20-concurrency/primes/py36/primes.py b/19-concurrency/primes/py36/primes.py similarity index 100% rename from 20-concurrency/primes/py36/primes.py rename to 19-concurrency/primes/py36/primes.py diff --git a/20-concurrency/primes/py36/procs.py b/19-concurrency/primes/py36/procs.py similarity index 100% rename from 20-concurrency/primes/py36/procs.py rename to 19-concurrency/primes/py36/procs.py diff --git a/20-concurrency/primes/run_procs.sh b/19-concurrency/primes/run_procs.sh similarity index 100% rename from 20-concurrency/primes/run_procs.sh rename to 19-concurrency/primes/run_procs.sh diff --git a/20-concurrency/primes/sequential.py b/19-concurrency/primes/sequential.py similarity index 100% rename from 20-concurrency/primes/sequential.py rename to 19-concurrency/primes/sequential.py diff --git a/20-concurrency/primes/spinner_prime_async_broken.py b/19-concurrency/primes/spinner_prime_async_broken.py similarity index 100% rename from 20-concurrency/primes/spinner_prime_async_broken.py rename to 19-concurrency/primes/spinner_prime_async_broken.py diff --git a/20-concurrency/primes/spinner_prime_async_nap.py b/19-concurrency/primes/spinner_prime_async_nap.py similarity index 100% rename from 20-concurrency/primes/spinner_prime_async_nap.py rename to 19-concurrency/primes/spinner_prime_async_nap.py diff --git a/20-concurrency/primes/spinner_prime_proc.py b/19-concurrency/primes/spinner_prime_proc.py similarity index 100% rename from 20-concurrency/primes/spinner_prime_proc.py rename to 19-concurrency/primes/spinner_prime_proc.py diff --git a/20-concurrency/primes/spinner_prime_thread.py b/19-concurrency/primes/spinner_prime_thread.py similarity index 100% rename from 20-concurrency/primes/spinner_prime_thread.py rename to 19-concurrency/primes/spinner_prime_thread.py diff --git a/20-concurrency/primes/stats-procs.ipynb b/19-concurrency/primes/stats-procs.ipynb similarity index 100% rename from 20-concurrency/primes/stats-procs.ipynb rename to 19-concurrency/primes/stats-procs.ipynb diff --git a/20-concurrency/primes/threads.py b/19-concurrency/primes/threads.py similarity index 100% rename from 20-concurrency/primes/threads.py rename to 19-concurrency/primes/threads.py diff --git a/20-concurrency/spinner_async.py b/19-concurrency/spinner_async.py similarity index 100% rename from 20-concurrency/spinner_async.py rename to 19-concurrency/spinner_async.py diff --git a/20-concurrency/spinner_async_experiment.py b/19-concurrency/spinner_async_experiment.py similarity index 100% rename from 20-concurrency/spinner_async_experiment.py rename to 19-concurrency/spinner_async_experiment.py diff --git a/20-concurrency/spinner_proc.py b/19-concurrency/spinner_proc.py similarity index 100% rename from 20-concurrency/spinner_proc.py rename to 19-concurrency/spinner_proc.py diff --git a/20-concurrency/spinner_thread.py b/19-concurrency/spinner_thread.py similarity index 100% rename from 20-concurrency/spinner_thread.py rename to 19-concurrency/spinner_thread.py diff --git a/19-coroutine/README.rst b/19-coroutine/README.rst deleted file mode 100644 index 2771530..0000000 --- a/19-coroutine/README.rst +++ /dev/null @@ -1,4 +0,0 @@ -Sample code for Chapter 16 - "Coroutines" - -From the book "Fluent Python" by Luciano Ramalho (O'Reilly, 2015) -http://shop.oreilly.com/product/0636920032519.do diff --git a/19-coroutine/coro_exc_demo.py b/19-coroutine/coro_exc_demo.py deleted file mode 100644 index a68684f..0000000 --- a/19-coroutine/coro_exc_demo.py +++ /dev/null @@ -1,66 +0,0 @@ -""" -Coroutine closing demonstration:: - -# tag::DEMO_CORO_EXC_1[] - >>> exc_coro = demo_exc_handling() - >>> next(exc_coro) - -> coroutine started - >>> exc_coro.send(11) - -> coroutine received: 11 - >>> exc_coro.send(22) - -> coroutine received: 22 - >>> exc_coro.close() - >>> from inspect import getgeneratorstate - >>> getgeneratorstate(exc_coro) - 'GEN_CLOSED' - -# end::DEMO_CORO_EXC_1[] - -Coroutine handling exception:: - -# tag::DEMO_CORO_EXC_2[] - >>> exc_coro = demo_exc_handling() - >>> next(exc_coro) - -> coroutine started - >>> exc_coro.send(11) - -> coroutine received: 11 - >>> exc_coro.throw(DemoException) - *** DemoException handled. Continuing... - >>> getgeneratorstate(exc_coro) - 'GEN_SUSPENDED' - -# end::DEMO_CORO_EXC_2[] - -Coroutine not handling exception:: - -# tag::DEMO_CORO_EXC_3[] - >>> exc_coro = demo_exc_handling() - >>> next(exc_coro) - -> coroutine started - >>> exc_coro.send(11) - -> coroutine received: 11 - >>> exc_coro.throw(ZeroDivisionError) - Traceback (most recent call last): - ... - ZeroDivisionError - >>> getgeneratorstate(exc_coro) - 'GEN_CLOSED' - -# end::DEMO_CORO_EXC_3[] -""" - -# tag::EX_CORO_EXC[] -class DemoException(Exception): - """An exception type for the demonstration.""" - -def demo_exc_handling(): - print('-> coroutine started') - while True: - try: - x = yield - except DemoException: # <1> - print('*** DemoException handled. Continuing...') - else: # <2> - print(f'-> coroutine received: {x!r}') - raise RuntimeError('This line should never run.') # <3> -# end::EX_CORO_EXC[] diff --git a/19-coroutine/coro_finally_demo.py b/19-coroutine/coro_finally_demo.py deleted file mode 100644 index fd4545d..0000000 --- a/19-coroutine/coro_finally_demo.py +++ /dev/null @@ -1,61 +0,0 @@ -""" -Second coroutine closing demonstration:: - - >>> fin_coro = demo_finally() - >>> next(fin_coro) - -> coroutine started - >>> fin_coro.send(11) - -> coroutine received: 11 - >>> fin_coro.send(22) - -> coroutine received: 22 - >>> fin_coro.close() - -> coroutine ending - - -Second coroutine not handling exception:: - - >>> fin_coro = demo_finally() - >>> next(fin_coro) - -> coroutine started - >>> fin_coro.send(11) - -> coroutine received: 11 - >>> fin_coro.throw(ZeroDivisionError) # doctest: +SKIP - -> coroutine ending - Traceback (most recent call last): - File "", line 1, in - File "coro_exception_demos.py", line 109, in demo_finally - print(f'-> coroutine received: {x!r}') - ZeroDivisionError - - -The last test above must be skipped because the output '-> coroutine ending' -is not detected by doctest, which raises a false error. However, if you -run this file as shown below, you'll see that output "leak" into standard -output:: - - - $ python3 -m doctest coro_exception_demo.py - -> coroutine ending - -""" - - -# tag::EX_CORO_FINALLY[] -class DemoException(Exception): - """An exception type for the demonstration.""" - - -def demo_finally(): - print('-> coroutine started') - try: - while True: - try: - x = yield - except DemoException: - print('*** DemoException handled. Continuing...') - else: - print(f'-> coroutine received: {x!r}') - finally: - print('-> coroutine ending') - -# end::EX_CORO_FINALLY[] diff --git a/19-coroutine/coroaverager0.py b/19-coroutine/coroaverager0.py deleted file mode 100644 index 10ccfdc..0000000 --- a/19-coroutine/coroaverager0.py +++ /dev/null @@ -1,28 +0,0 @@ -""" -A coroutine to compute a running average - -# tag::CORO_AVERAGER_TEST[] - >>> coro_avg = averager() # <1> - >>> next(coro_avg) # <2> - >>> coro_avg.send(10) # <3> - 10.0 - >>> coro_avg.send(30) - 20.0 - >>> coro_avg.send(5) - 15.0 - -# end::CORO_AVERAGER_TEST[] - -""" - -# tag::CORO_AVERAGER[] -def averager(): - total = 0.0 - count = 0 - average = None - while True: # <1> - term = yield average # <2> - total += term - count += 1 - average = total/count -# end::CORO_AVERAGER[] diff --git a/19-coroutine/coroaverager1.py b/19-coroutine/coroaverager1.py deleted file mode 100644 index 3b3c5e9..0000000 --- a/19-coroutine/coroaverager1.py +++ /dev/null @@ -1,30 +0,0 @@ -# tag::DECORATED_AVERAGER[] -""" -A coroutine to compute a running average - - >>> coro_avg = averager() # <1> - >>> from inspect import getgeneratorstate - >>> getgeneratorstate(coro_avg) # <2> - 'GEN_SUSPENDED' - >>> coro_avg.send(10) # <3> - 10.0 - >>> coro_avg.send(30) - 20.0 - >>> coro_avg.send(5) - 15.0 - -""" - -from coroutil import coroutine # <4> - -@coroutine # <5> -def averager(): # <6> - total = 0.0 - count = 0 - average = None - while True: - term = yield average - total += term - count += 1 - average = total/count -# end::DECORATED_AVERAGER[] diff --git a/19-coroutine/coroaverager2.py b/19-coroutine/coroaverager2.py deleted file mode 100644 index 9d724c0..0000000 --- a/19-coroutine/coroaverager2.py +++ /dev/null @@ -1,61 +0,0 @@ -""" -A coroutine to compute a running average. - -Testing ``averager`` by itself:: - -# tag::RETURNING_AVERAGER_DEMO1[] - - >>> coro_avg = averager() - >>> next(coro_avg) - >>> coro_avg.send(10) # <1> - >>> coro_avg.send(30) - >>> coro_avg.send(6.5) - >>> coro_avg.send(None) # <2> - Traceback (most recent call last): - ... - StopIteration: Result(count=3, average=15.5) - -# end::RETURNING_AVERAGER_DEMO1[] - -Catching `StopIteration` to extract the value returned by -the coroutine:: - -# tag::RETURNING_AVERAGER_DEMO2[] - - >>> coro_avg = averager() - >>> next(coro_avg) - >>> coro_avg.send(10) - >>> coro_avg.send(30) - >>> coro_avg.send(6.5) - >>> try: - ... coro_avg.send(None) - ... except StopIteration as exc: - ... result = exc.value - ... - >>> result - Result(count=3, average=15.5) - -# end::RETURNING_AVERAGER_DEMO2[] - - -""" - -# tag::RETURNING_AVERAGER[] -from collections import namedtuple - -Result = namedtuple('Result', 'count average') - - -def averager(): - total = 0.0 - count = 0 - average = None - while True: - term = yield - if term is None: - break # <1> - total += term - count += 1 - average = total/count - return Result(count, average) # <2> -# end::RETURNING_AVERAGER[] diff --git a/19-coroutine/coroaverager3.py b/19-coroutine/coroaverager3.py deleted file mode 100644 index 2b24df9..0000000 --- a/19-coroutine/coroaverager3.py +++ /dev/null @@ -1,107 +0,0 @@ -""" -A coroutine to compute a running average. - -Testing ``averager`` by itself:: - - >>> coro_avg = averager() - >>> next(coro_avg) - >>> coro_avg.send(10) - >>> coro_avg.send(30) - >>> coro_avg.send(6.5) - >>> coro_avg.send(None) - Traceback (most recent call last): - ... - StopIteration: Result(count=3, average=15.5) - - -Driving it with ``yield from``:: - - >>> def summarize(results): - ... while True: - ... result = yield from averager() - ... results.append(result) - ... - >>> results = [] - >>> summary = summarize(results) - >>> next(summary) - >>> for height in data['girls;m']: - ... summary.send(height) - ... - >>> summary.send(None) - >>> for height in data['boys;m']: - ... summary.send(height) - ... - >>> summary.send(None) - >>> results == [ - ... Result(count=10, average=1.4279999999999997), - ... Result(count=9, average=1.3888888888888888) - ... ] - True - -""" - -# tag::YIELD_FROM_AVERAGER[] -from collections import namedtuple - -Result = namedtuple('Result', 'count average') - - -# the subgenerator -def averager(): # <1> - total = 0.0 - count = 0 - average = None - while True: - term = yield # <2> - if term is None: # <3> - break - total += term - count += 1 - average = total/count - return Result(count, average) # <4> - - -# the delegating generator -def grouper(results, key): # <5> - while True: # <6> - results[key] = yield from averager() # <7> - - -# the client code, a.k.a. the caller -def main(data): # <8> - results = {} - for key, values in data.items(): - group = grouper(results, key) # <9> - next(group) # <10> - for value in values: - group.send(value) # <11> - group.send(None) # important! <12> - - # print(results) # uncomment to debug - report(results) - - -# output report -def report(results): - for key, result in sorted(results.items()): - group, unit = key.split(';') - print(f'{result.count:2} {group:5}', - f'averaging {result.average:.2f}{unit}') - - -data = { - 'girls;kg': - [40.9, 38.5, 44.3, 42.2, 45.2, 41.7, 44.5, 38.0, 40.6, 44.5], - 'girls;m': - [1.6, 1.51, 1.4, 1.3, 1.41, 1.39, 1.33, 1.46, 1.45, 1.43], - 'boys;kg': - [39.0, 40.8, 43.2, 40.8, 43.1, 38.6, 41.4, 40.6, 36.3], - 'boys;m': - [1.38, 1.5, 1.32, 1.25, 1.37, 1.48, 1.25, 1.49, 1.46], -} - - -if __name__ == '__main__': - main(data) - -# end::YIELD_FROM_AVERAGER[] diff --git a/19-coroutine/coroutil.py b/19-coroutine/coroutil.py deleted file mode 100644 index 4420db8..0000000 --- a/19-coroutine/coroutil.py +++ /dev/null @@ -1,12 +0,0 @@ -# tag::CORO_DECO[] -from functools import wraps - -def coroutine(func): - """Decorator: primes `func` by advancing to first `yield`""" - @wraps(func) - def primer(*args, **kwargs): # <1> - gen = func(*args, **kwargs) # <2> - next(gen) # <3> - return gen # <4> - return primer -# end::CORO_DECO[] diff --git a/19-coroutine/taxi_sim.py b/19-coroutine/taxi_sim.py deleted file mode 100644 index 6bf0ce9..0000000 --- a/19-coroutine/taxi_sim.py +++ /dev/null @@ -1,203 +0,0 @@ - -""" -Taxi simulator -============== - -Driving a taxi from the console:: - - >>> from taxi_sim import taxi_process - >>> taxi = taxi_process(ident=13, trips=2, start_time=0) - >>> next(taxi) - Event(time=0, proc=13, action='leave garage') - >>> taxi.send(_.time + 7) - Event(time=7, proc=13, action='pick up passenger') - >>> taxi.send(_.time + 23) - Event(time=30, proc=13, action='drop off passenger') - >>> taxi.send(_.time + 5) - Event(time=35, proc=13, action='pick up passenger') - >>> taxi.send(_.time + 48) - Event(time=83, proc=13, action='drop off passenger') - >>> taxi.send(_.time + 1) - Event(time=84, proc=13, action='going home') - >>> taxi.send(_.time + 10) - Traceback (most recent call last): - File "", line 1, in - StopIteration - -Sample run with two cars, random seed 10. This is a valid doctest:: - - >>> main(num_taxis=2, seed=10) - taxi: 0 Event(time=0, proc=0, action='leave garage') - taxi: 0 Event(time=5, proc=0, action='pick up passenger') - taxi: 1 Event(time=5, proc=1, action='leave garage') - taxi: 1 Event(time=10, proc=1, action='pick up passenger') - taxi: 1 Event(time=15, proc=1, action='drop off passenger') - taxi: 0 Event(time=17, proc=0, action='drop off passenger') - taxi: 1 Event(time=24, proc=1, action='pick up passenger') - taxi: 0 Event(time=26, proc=0, action='pick up passenger') - taxi: 0 Event(time=30, proc=0, action='drop off passenger') - taxi: 0 Event(time=34, proc=0, action='going home') - taxi: 1 Event(time=46, proc=1, action='drop off passenger') - taxi: 1 Event(time=48, proc=1, action='pick up passenger') - taxi: 1 Event(time=110, proc=1, action='drop off passenger') - taxi: 1 Event(time=139, proc=1, action='pick up passenger') - taxi: 1 Event(time=140, proc=1, action='drop off passenger') - taxi: 1 Event(time=150, proc=1, action='going home') - *** end of events *** - -See longer sample run at the end of this module. - -""" - -import argparse -import collections -import random -import queue - - -DEFAULT_NUMBER_OF_TAXIS = 3 -DEFAULT_END_TIME = 180 -SEARCH_DURATION = 5 -TRIP_DURATION = 20 -DEPARTURE_INTERVAL = 5 - -Event = collections.namedtuple('Event', 'time proc action') - - -# tag::TAXI_PROCESS[] -def taxi_process(ident, trips, start_time=0): # <1> - """Yield to simulator issuing event at each state change""" - time = yield Event(start_time, ident, 'leave garage') # <2> - for i in range(trips): # <3> - time = yield Event(time, ident, 'pick up passenger') # <4> - time = yield Event(time, ident, 'drop off passenger') # <5> - - yield Event(time, ident, 'going home') # <6> - # end of taxi process # <7> -# end::TAXI_PROCESS[] - - -# tag::TAXI_SIMULATOR[] -class Simulator: - - def __init__(self, procs_map): - self.events = queue.PriorityQueue() - self.procs = dict(procs_map) - - def run(self, end_time): # <1> - """Schedule and display events until time is up""" - # schedule the first event for each cab - for _, proc in sorted(self.procs.items()): # <2> - first_event = next(proc) # <3> - self.events.put(first_event) # <4> - - # main loop of the simulation - sim_time = 0 # <5> - while sim_time < end_time: # <6> - if self.events.empty(): # <7> - print('*** end of events ***') - break - - current_event = self.events.get() # <8> - sim_time, proc_id, previous_action = current_event # <9> - print('taxi:', proc_id, proc_id * ' ', current_event) # <10> - active_proc = self.procs[proc_id] # <11> - next_time = sim_time + compute_duration(previous_action) # <12> - try: - next_event = active_proc.send(next_time) # <13> - except StopIteration: - del self.procs[proc_id] # <14> - else: - self.events.put(next_event) # <15> - else: # <16> - msg = '*** end of simulation time: {} events pending ***' - print(msg.format(self.events.qsize())) -# end::TAXI_SIMULATOR[] - - -def compute_duration(previous_action): - """Compute action duration using exponential distribution""" - if previous_action in ['leave garage', 'drop off passenger']: - # new state is prowling - interval = SEARCH_DURATION - elif previous_action == 'pick up passenger': - # new state is trip - interval = TRIP_DURATION - elif previous_action == 'going home': - interval = 1 - else: - raise ValueError(f'Unknown previous_action: {previous_action}') - return int(random.expovariate(1 / interval)) + 1 - - -def main(end_time=DEFAULT_END_TIME, num_taxis=DEFAULT_NUMBER_OF_TAXIS, - seed=None): - """Initialize random generator, build procs and run simulation""" - if seed is not None: - random.seed(seed) # get reproducible results - - taxis = {i: taxi_process(i, (i + 1) * 2, i * DEPARTURE_INTERVAL) - for i in range(num_taxis)} - sim = Simulator(taxis) - sim.run(end_time) - - -if __name__ == '__main__': - - parser = argparse.ArgumentParser( - description='Taxi fleet simulator.') - parser.add_argument('-e', '--end-time', type=int, - default=DEFAULT_END_TIME, - help='simulation end time; default = %s' - % DEFAULT_END_TIME) - parser.add_argument('-t', '--taxis', type=int, - default=DEFAULT_NUMBER_OF_TAXIS, - help='number of taxis running; default = %s' - % DEFAULT_NUMBER_OF_TAXIS) - parser.add_argument('-s', '--seed', type=int, default=None, - help='random generator seed (for testing)') - - args = parser.parse_args() - main(args.end_time, args.taxis, args.seed) - - -""" - -Sample run from the command line, seed=3, maximum elapsed time=120:: - -# tag::TAXI_SAMPLE_RUN[] -$ python3 taxi_sim.py -s 3 -e 120 -taxi: 0 Event(time=0, proc=0, action='leave garage') -taxi: 0 Event(time=2, proc=0, action='pick up passenger') -taxi: 1 Event(time=5, proc=1, action='leave garage') -taxi: 1 Event(time=8, proc=1, action='pick up passenger') -taxi: 2 Event(time=10, proc=2, action='leave garage') -taxi: 2 Event(time=15, proc=2, action='pick up passenger') -taxi: 2 Event(time=17, proc=2, action='drop off passenger') -taxi: 0 Event(time=18, proc=0, action='drop off passenger') -taxi: 2 Event(time=18, proc=2, action='pick up passenger') -taxi: 2 Event(time=25, proc=2, action='drop off passenger') -taxi: 1 Event(time=27, proc=1, action='drop off passenger') -taxi: 2 Event(time=27, proc=2, action='pick up passenger') -taxi: 0 Event(time=28, proc=0, action='pick up passenger') -taxi: 2 Event(time=40, proc=2, action='drop off passenger') -taxi: 2 Event(time=44, proc=2, action='pick up passenger') -taxi: 1 Event(time=55, proc=1, action='pick up passenger') -taxi: 1 Event(time=59, proc=1, action='drop off passenger') -taxi: 0 Event(time=65, proc=0, action='drop off passenger') -taxi: 1 Event(time=65, proc=1, action='pick up passenger') -taxi: 2 Event(time=65, proc=2, action='drop off passenger') -taxi: 2 Event(time=72, proc=2, action='pick up passenger') -taxi: 0 Event(time=76, proc=0, action='going home') -taxi: 1 Event(time=80, proc=1, action='drop off passenger') -taxi: 1 Event(time=88, proc=1, action='pick up passenger') -taxi: 2 Event(time=95, proc=2, action='drop off passenger') -taxi: 2 Event(time=97, proc=2, action='pick up passenger') -taxi: 2 Event(time=98, proc=2, action='drop off passenger') -taxi: 1 Event(time=106, proc=1, action='drop off passenger') -taxi: 2 Event(time=109, proc=2, action='going home') -taxi: 1 Event(time=110, proc=1, action='going home') -*** end of events *** -# end::TAXI_SAMPLE_RUN[] - -""" diff --git a/19-coroutine/taxi_sim0.py b/19-coroutine/taxi_sim0.py deleted file mode 100644 index ed988f5..0000000 --- a/19-coroutine/taxi_sim0.py +++ /dev/null @@ -1,255 +0,0 @@ - -""" -Taxi simulator - -Sample run with two cars, random seed 10. This is a valid doctest. - - >>> main(num_taxis=2, seed=10) - taxi: 0 Event(time=0, proc=0, action='leave garage') - taxi: 0 Event(time=4, proc=0, action='pick up passenger') - taxi: 1 Event(time=5, proc=1, action='leave garage') - taxi: 1 Event(time=9, proc=1, action='pick up passenger') - taxi: 0 Event(time=10, proc=0, action='drop off passenger') - taxi: 1 Event(time=12, proc=1, action='drop off passenger') - taxi: 0 Event(time=17, proc=0, action='pick up passenger') - taxi: 1 Event(time=19, proc=1, action='pick up passenger') - taxi: 1 Event(time=21, proc=1, action='drop off passenger') - taxi: 1 Event(time=24, proc=1, action='pick up passenger') - taxi: 0 Event(time=28, proc=0, action='drop off passenger') - taxi: 1 Event(time=28, proc=1, action='drop off passenger') - taxi: 0 Event(time=29, proc=0, action='going home') - taxi: 1 Event(time=30, proc=1, action='pick up passenger') - taxi: 1 Event(time=61, proc=1, action='drop off passenger') - taxi: 1 Event(time=62, proc=1, action='going home') - *** end of events *** - -See explanation and longer sample run at the end of this module. - -""" - -import argparse -import collections -import queue -import random - -DEFAULT_NUMBER_OF_TAXIS = 3 -DEFAULT_END_TIME = 80 -SEARCH_DURATION = 4 -TRIP_DURATION = 10 -DEPARTURE_INTERVAL = 5 - -Event = collections.namedtuple('Event', 'time proc action') - - -def compute_delay(interval): - """Compute action delay using exponential distribution""" - return int(random.expovariate(1 / interval)) + 1 - -# BEGIN TAXI_PROCESS -def taxi_process(ident, trips, start_time=0): # <1> - """Yield to simulator issuing event at each state change""" - time = yield Event(start_time, ident, 'leave garage') # <2> - for i in range(trips): # <3> - prowling_ends = time + compute_delay(SEARCH_DURATION) # <4> - time = yield Event(prowling_ends, ident, 'pick up passenger') # <5> - - trip_ends = time + compute_delay(TRIP_DURATION) # <6> - time = yield Event(trip_ends, ident, 'drop off passenger') # <7> - - yield Event(time + 1, ident, 'going home') # <8> - # end of taxi process # <9> -# END TAXI_PROCESS - -# BEGIN TAXI_SIMULATOR -class Simulator: - - def __init__(self, procs_map): - self.events = queue.PriorityQueue() - self.procs = dict(procs_map) - - def run(self, end_time): # <1> - """Schedule and display events until time is up""" - # schedule the first event for each cab - for _, proc in sorted(self.procs.items()): # <2> - first_event = next(proc) # <3> - self.events.put(first_event) # <4> - - # main loop of the simulation - time = 0 - while time < end_time: # <5> - if self.events.empty(): # <6> - print('*** end of events ***') - break - - # get and display current event - current_event = self.events.get() # <7> - print('taxi:', current_event.proc, # <8> - current_event.proc * ' ', current_event) - - # schedule next action for current proc - time = current_event.time # <9> - proc = self.procs[current_event.proc] # <10> - try: - next_event = proc.send(time) # <11> - except StopIteration: - del self.procs[current_event.proc] # <12> - else: - self.events.put(next_event) # <13> - else: # <14> - msg = '*** end of simulation time: {} events pending ***' - print(msg.format(self.events.qsize())) -# END TAXI_SIMULATOR - -def main(end_time=DEFAULT_END_TIME, num_taxis=DEFAULT_NUMBER_OF_TAXIS, - seed=None): - """Initialize random generator, build procs and run simulation""" - if seed is not None: - random.seed(seed) # get reproducible results - - taxis = {i: taxi_process(i, (i + 1) * 2, i * DEPARTURE_INTERVAL) - for i in range(num_taxis)} - sim = Simulator(taxis) - sim.run(end_time) - - -if __name__ == '__main__': - - parser = argparse.ArgumentParser( - description='Taxi fleet simulator.') - parser.add_argument('-e', '--end-time', type=int, - default=DEFAULT_END_TIME, - help='simulation end time; default = %s' - % DEFAULT_END_TIME) - parser.add_argument('-t', '--taxis', type=int, - default=DEFAULT_NUMBER_OF_TAXIS, - help='number of taxis running; default = %s' - % DEFAULT_NUMBER_OF_TAXIS) - parser.add_argument('-s', '--seed', type=int, default=None, - help='random generator seed (for testing)') - - args = parser.parse_args() - main(args.end_time, args.taxis, args.seed) - - -""" -Notes for the ``taxi_process`` coroutine:: - -<1> `taxi_process` will be called once per taxi, creating a generator - object to represent its operations. `ident` is the number of the taxi - (eg. 0, 1, 2 in the sample run); `trips` is the number of trips this - taxi will make before going home; `start_time` is when the taxi - leaves the garage. - -<2> The first `Event` yielded is `'leave garage'`. This suspends the - coroutine, and lets the simulation main loop proceed to the next - scheduled event. When it's time to reactivate this process, the main - loop will `send` the current simulation time, which is assigned to - `time`. - -<3> This block will be repeated once for each trip. - -<4> The ending time of the search for a passenger is computed. - -<5> An `Event` signaling passenger pick up is yielded. The coroutine - pauses here. When the time comes to reactivate this coroutine, - the main loop will again `send` the current time. - -<6> The ending time of the trip is computed, taking into account the - current `time`. - -<7> An `Event` signaling passenger drop off is yielded. Coroutine - suspended again, waiting for the main loop to send the time of when - it's time to continue. - -<8> The `for` loop ends after the given number of trips, and a final - `'going home'` event is yielded, to happen 1 minute after the current - time. The coroutine will suspend for the last time. When reactivated, - it will be sent the time from the simulation main loop, but here I - don't assign it to any variable because it will not be useful. - -<9> When the coroutine falls off the end, the coroutine object raises - `StopIteration`. - - -Notes for the ``Simulator.run`` method:: - -<1> The simulation `end_time` is the only required argument for `run`. - -<2> Use `sorted` to retrieve the `self.procs` items ordered by the - integer key; we don't care about the key, so assign it to `_`. - -<3> `next(proc)` primes each coroutine by advancing it to the first - yield, so it's ready to be sent data. An `Event` is yielded. - -<4> Add each event to the `self.events` `PriorityQueue`. The first - event for each taxi is `'leave garage'`, as seen in the sample run - (ex_taxi_process>>). - -<5> Main loop of the simulation: run until the current `time` equals - or exceeds the `end_time`. - -<6> The main loop may also exit if there are no pending events in the - queue. - -<7> Get `Event` with the smallest `time` in the queue; this is the - `current_event`. - -<8> Display the `Event`, identifying the taxi and adding indentation - according to the taxi id. - -<9> Update the simulation time with the time of the `current_event`. - -<10> Retrieve the coroutine for this taxi from the `self.procs` - dictionary. - -<11> Send the `time` to the coroutine. The coroutine will yield the - `next_event` or raise `StopIteration` it's finished. - -<12> If `StopIteration` was raised, delete the coroutine from the - `self.procs` dictionary. - -<13> Otherwise, put the `next_event` in the queue. - -<14> If the loop exits because the simulation time passed, display the - number of events pending (which may be zero by coincidence, - sometimes). - - -Sample run from the command line, seed=24, total elapsed time=160:: - -# BEGIN TAXI_SAMPLE_RUN -$ python3 taxi_sim.py -s 24 -e 160 -taxi: 0 Event(time=0, proc=0, action='leave garage') -taxi: 0 Event(time=5, proc=0, action='pick up passenger') -taxi: 1 Event(time=5, proc=1, action='leave garage') -taxi: 1 Event(time=6, proc=1, action='pick up passenger') -taxi: 2 Event(time=10, proc=2, action='leave garage') -taxi: 2 Event(time=11, proc=2, action='pick up passenger') -taxi: 2 Event(time=23, proc=2, action='drop off passenger') -taxi: 0 Event(time=24, proc=0, action='drop off passenger') -taxi: 2 Event(time=24, proc=2, action='pick up passenger') -taxi: 2 Event(time=26, proc=2, action='drop off passenger') -taxi: 0 Event(time=30, proc=0, action='pick up passenger') -taxi: 2 Event(time=31, proc=2, action='pick up passenger') -taxi: 0 Event(time=43, proc=0, action='drop off passenger') -taxi: 0 Event(time=44, proc=0, action='going home') -taxi: 2 Event(time=46, proc=2, action='drop off passenger') -taxi: 2 Event(time=49, proc=2, action='pick up passenger') -taxi: 1 Event(time=70, proc=1, action='drop off passenger') -taxi: 2 Event(time=70, proc=2, action='drop off passenger') -taxi: 2 Event(time=71, proc=2, action='pick up passenger') -taxi: 2 Event(time=79, proc=2, action='drop off passenger') -taxi: 1 Event(time=88, proc=1, action='pick up passenger') -taxi: 2 Event(time=92, proc=2, action='pick up passenger') -taxi: 2 Event(time=98, proc=2, action='drop off passenger') -taxi: 2 Event(time=99, proc=2, action='going home') -taxi: 1 Event(time=102, proc=1, action='drop off passenger') -taxi: 1 Event(time=104, proc=1, action='pick up passenger') -taxi: 1 Event(time=135, proc=1, action='drop off passenger') -taxi: 1 Event(time=136, proc=1, action='pick up passenger') -taxi: 1 Event(time=151, proc=1, action='drop off passenger') -taxi: 1 Event(time=152, proc=1, action='going home') -*** end of events *** -# END TAXI_SAMPLE_RUN - -""" diff --git a/19-coroutine/taxi_sim_delay.py b/19-coroutine/taxi_sim_delay.py deleted file mode 100644 index 8f38e4f..0000000 --- a/19-coroutine/taxi_sim_delay.py +++ /dev/null @@ -1,215 +0,0 @@ - -""" -Taxi simulator with delay on output -=================================== - -This is a variation of ``taxi_sim.py`` which adds a ``-d`` comand-line -option. When given, that option adds a delay in the main loop, pausing -the simulation for .5s for each "minute" of simulation time. - - -Driving a taxi from the console:: - - >>> from taxi_sim import taxi_process - >>> taxi = taxi_process(ident=13, trips=2, start_time=0) - >>> next(taxi) - Event(time=0, proc=13, action='leave garage') - >>> taxi.send(_.time + 7) - Event(time=7, proc=13, action='pick up passenger') - >>> taxi.send(_.time + 23) - Event(time=30, proc=13, action='drop off passenger') - >>> taxi.send(_.time + 5) - Event(time=35, proc=13, action='pick up passenger') - >>> taxi.send(_.time + 48) - Event(time=83, proc=13, action='drop off passenger') - >>> taxi.send(_.time + 1) - Event(time=84, proc=13, action='going home') - >>> taxi.send(_.time + 10) - Traceback (most recent call last): - File "", line 1, in - StopIteration - -Sample run with two cars, random seed 10. This is a valid doctest:: - - >>> main(num_taxis=2, seed=10) - taxi: 0 Event(time=0, proc=0, action='leave garage') - taxi: 0 Event(time=5, proc=0, action='pick up passenger') - taxi: 1 Event(time=5, proc=1, action='leave garage') - taxi: 1 Event(time=10, proc=1, action='pick up passenger') - taxi: 1 Event(time=15, proc=1, action='drop off passenger') - taxi: 0 Event(time=17, proc=0, action='drop off passenger') - taxi: 1 Event(time=24, proc=1, action='pick up passenger') - taxi: 0 Event(time=26, proc=0, action='pick up passenger') - taxi: 0 Event(time=30, proc=0, action='drop off passenger') - taxi: 0 Event(time=34, proc=0, action='going home') - taxi: 1 Event(time=46, proc=1, action='drop off passenger') - taxi: 1 Event(time=48, proc=1, action='pick up passenger') - taxi: 1 Event(time=110, proc=1, action='drop off passenger') - taxi: 1 Event(time=139, proc=1, action='pick up passenger') - taxi: 1 Event(time=140, proc=1, action='drop off passenger') - taxi: 1 Event(time=150, proc=1, action='going home') - *** end of events *** - -See longer sample run at the end of this module. - -""" - -import random -import collections -import queue -import argparse -import time - -DEFAULT_NUMBER_OF_TAXIS = 3 -DEFAULT_END_TIME = 180 -SEARCH_DURATION = 5 -TRIP_DURATION = 20 -DEPARTURE_INTERVAL = 5 - -Event = collections.namedtuple('Event', 'time proc action') - - -# BEGIN TAXI_PROCESS -def taxi_process(ident, trips, start_time=0): # <1> - """Yield to simulator issuing event at each state change""" - time = yield Event(start_time, ident, 'leave garage') # <2> - for i in range(trips): # <3> - time = yield Event(time, ident, 'pick up passenger') # <4> - time = yield Event(time, ident, 'drop off passenger') # <5> - - yield Event(time, ident, 'going home') # <6> - # end of taxi process # <7> -# END TAXI_PROCESS - - -# BEGIN TAXI_SIMULATOR -class Simulator: - - def __init__(self, procs_map): - self.events = queue.PriorityQueue() - self.procs = dict(procs_map) - - def run(self, end_time, delay=False): # <1> - """Schedule and display events until time is up""" - # schedule the first event for each cab - for _, proc in sorted(self.procs.items()): # <2> - first_event = next(proc) # <3> - self.events.put(first_event) # <4> - - # main loop of the simulation - sim_time = 0 # <5> - while sim_time < end_time: # <6> - if self.events.empty(): # <7> - print('*** end of events ***') - break - - # get and display current event - current_event = self.events.get() # <8> - if delay: - time.sleep((current_event.time - sim_time) / 2) - # update the simulation time - sim_time, proc_id, previous_action = current_event - print('taxi:', proc_id, proc_id * ' ', current_event) - active_proc = self.procs[proc_id] - # schedule next action for current proc - next_time = sim_time + compute_duration(previous_action) - try: - next_event = active_proc.send(next_time) # <12> - except StopIteration: - del self.procs[proc_id] # <13> - else: - self.events.put(next_event) # <14> - else: # <15> - msg = '*** end of simulation time: {} events pending ***' - print(msg.format(self.events.qsize())) -# END TAXI_SIMULATOR - - -def compute_duration(previous_action): - """Compute action duration using exponential distribution""" - if previous_action in ['leave garage', 'drop off passenger']: - # new state is prowling - interval = SEARCH_DURATION - elif previous_action == 'pick up passenger': - # new state is trip - interval = TRIP_DURATION - elif previous_action == 'going home': - interval = 1 - else: - raise ValueError('Unknown previous_action: %s' % previous_action) - return int(random.expovariate(1/interval)) + 1 - - -def main(end_time=DEFAULT_END_TIME, num_taxis=DEFAULT_NUMBER_OF_TAXIS, - seed=None, delay=False): - """Initialize random generator, build procs and run simulation""" - if seed is not None: - random.seed(seed) # get reproducible results - - taxis = {i: taxi_process(i, (i+1)*2, i*DEPARTURE_INTERVAL) - for i in range(num_taxis)} - sim = Simulator(taxis) - sim.run(end_time, delay) - - -if __name__ == '__main__': - - parser = argparse.ArgumentParser( - description='Taxi fleet simulator.') - parser.add_argument('-e', '--end-time', type=int, - default=DEFAULT_END_TIME, - help='simulation end time; default = %s' - % DEFAULT_END_TIME) - parser.add_argument('-t', '--taxis', type=int, - default=DEFAULT_NUMBER_OF_TAXIS, - help='number of taxis running; default = %s' - % DEFAULT_NUMBER_OF_TAXIS) - parser.add_argument('-s', '--seed', type=int, default=None, - help='random generator seed (for testing)') - parser.add_argument('-d', '--delay', action='store_true', - help='introduce delay proportional to simulation time') - - args = parser.parse_args() - main(args.end_time, args.taxis, args.seed, args.delay) - - -""" - -Sample run from the command line, seed=3, maximum elapsed time=120:: - -# BEGIN TAXI_SAMPLE_RUN -$ python3 taxi_sim.py -s 3 -e 120 -taxi: 0 Event(time=0, proc=0, action='leave garage') -taxi: 0 Event(time=2, proc=0, action='pick up passenger') -taxi: 1 Event(time=5, proc=1, action='leave garage') -taxi: 1 Event(time=8, proc=1, action='pick up passenger') -taxi: 2 Event(time=10, proc=2, action='leave garage') -taxi: 2 Event(time=15, proc=2, action='pick up passenger') -taxi: 2 Event(time=17, proc=2, action='drop off passenger') -taxi: 0 Event(time=18, proc=0, action='drop off passenger') -taxi: 2 Event(time=18, proc=2, action='pick up passenger') -taxi: 2 Event(time=25, proc=2, action='drop off passenger') -taxi: 1 Event(time=27, proc=1, action='drop off passenger') -taxi: 2 Event(time=27, proc=2, action='pick up passenger') -taxi: 0 Event(time=28, proc=0, action='pick up passenger') -taxi: 2 Event(time=40, proc=2, action='drop off passenger') -taxi: 2 Event(time=44, proc=2, action='pick up passenger') -taxi: 1 Event(time=55, proc=1, action='pick up passenger') -taxi: 1 Event(time=59, proc=1, action='drop off passenger') -taxi: 0 Event(time=65, proc=0, action='drop off passenger') -taxi: 1 Event(time=65, proc=1, action='pick up passenger') -taxi: 2 Event(time=65, proc=2, action='drop off passenger') -taxi: 2 Event(time=72, proc=2, action='pick up passenger') -taxi: 0 Event(time=76, proc=0, action='going home') -taxi: 1 Event(time=80, proc=1, action='drop off passenger') -taxi: 1 Event(time=88, proc=1, action='pick up passenger') -taxi: 2 Event(time=95, proc=2, action='drop off passenger') -taxi: 2 Event(time=97, proc=2, action='pick up passenger') -taxi: 2 Event(time=98, proc=2, action='drop off passenger') -taxi: 1 Event(time=106, proc=1, action='drop off passenger') -taxi: 2 Event(time=109, proc=2, action='going home') -taxi: 1 Event(time=110, proc=1, action='going home') -*** end of events *** -# END TAXI_SAMPLE_RUN - -""" diff --git a/19-coroutine/yield_from_expansion.py b/19-coroutine/yield_from_expansion.py deleted file mode 100644 index 837925f..0000000 --- a/19-coroutine/yield_from_expansion.py +++ /dev/null @@ -1,52 +0,0 @@ -# Code below is the expansion of the statement: -# -# RESULT = yield from EXPR -# -# Copied verbatim from the Formal Semantics section of -# PEP 380 -- Syntax for Delegating to a Subgenerator -# -# https://www.python.org/dev/peps/pep-0380/#formal-semantics - - -# tag::YIELD_FROM_EXPANSION[] -_i = iter(EXPR) # <1> -try: - _y = next(_i) # <2> -except StopIteration as _e: - _r = _e.value # <3> -else: - while 1: # <4> - try: - _s = yield _y # <5> - except GeneratorExit as _e: # <6> - try: - _m = _i.close - except AttributeError: - pass - else: - _m() - raise _e - except BaseException as _e: # <7> - _x = sys.exc_info() - try: - _m = _i.throw - except AttributeError: - raise _e - else: # <8> - try: - _y = _m(*_x) - except StopIteration as _e: - _r = _e.value - break - else: # <9> - try: # <10> - if _s is None: # <11> - _y = next(_i) - else: - _y = _i.send(_s) - except StopIteration as _e: # <12> - _r = _e.value - break - -RESULT = _r # <13> -# end::YIELD_FROM_EXPANSION[] diff --git a/19-coroutine/yield_from_expansion_simplified.py b/19-coroutine/yield_from_expansion_simplified.py deleted file mode 100644 index 7648da5..0000000 --- a/19-coroutine/yield_from_expansion_simplified.py +++ /dev/null @@ -1,32 +0,0 @@ -# Code below is a very simplified expansion of the statement: -# -# RESULT = yield from EXPR -# -# This code assumes that the subgenerator will run to completion, -# without the client ever calling ``.throw()`` or ``.close()``. -# Also, this code makes no distinction between the client -# calling ``next(subgen)`` or ``subgen.send(...)`` -# -# The full expansion is in: -# PEP 380 -- Syntax for Delegating to a Subgenerator -# -# https://www.python.org/dev/peps/pep-0380/#formal-semantics - - -# tag::YIELD_FROM_EXPANSION_SIMPLIFIED[] -_i = iter(EXPR) # <1> -try: - _y = next(_i) # <2> -except StopIteration as _e: - _r = _e.value # <3> -else: - while 1: # <4> - _s = yield _y # <5> - try: - _y = _i.send(_s) # <6> - except StopIteration as _e: # <7> - _r = _e.value - break - -RESULT = _r # <8> -# end::YIELD_FROM_EXPANSION_SIMPLIFIED[] diff --git a/21-futures/demo_executor_map.py b/20-futures/demo_executor_map.py similarity index 100% rename from 21-futures/demo_executor_map.py rename to 20-futures/demo_executor_map.py diff --git a/21-futures/getflags/.gitignore b/20-futures/getflags/.gitignore similarity index 100% rename from 21-futures/getflags/.gitignore rename to 20-futures/getflags/.gitignore diff --git a/21-futures/getflags/country_codes.txt b/20-futures/getflags/country_codes.txt similarity index 100% rename from 21-futures/getflags/country_codes.txt rename to 20-futures/getflags/country_codes.txt diff --git a/21-futures/getflags/downloaded/.gitignore b/20-futures/getflags/downloaded/.gitignore similarity index 100% rename from 21-futures/getflags/downloaded/.gitignore rename to 20-futures/getflags/downloaded/.gitignore diff --git a/21-futures/getflags/flags.py b/20-futures/getflags/flags.py similarity index 100% rename from 21-futures/getflags/flags.py rename to 20-futures/getflags/flags.py diff --git a/21-futures/getflags/flags.zip b/20-futures/getflags/flags.zip similarity index 100% rename from 21-futures/getflags/flags.zip rename to 20-futures/getflags/flags.zip diff --git a/21-futures/getflags/flags2_asyncio.py b/20-futures/getflags/flags2_asyncio.py similarity index 100% rename from 21-futures/getflags/flags2_asyncio.py rename to 20-futures/getflags/flags2_asyncio.py diff --git a/21-futures/getflags/flags2_asyncio_executor.py b/20-futures/getflags/flags2_asyncio_executor.py similarity index 100% rename from 21-futures/getflags/flags2_asyncio_executor.py rename to 20-futures/getflags/flags2_asyncio_executor.py diff --git a/21-futures/getflags/flags2_common.py b/20-futures/getflags/flags2_common.py similarity index 100% rename from 21-futures/getflags/flags2_common.py rename to 20-futures/getflags/flags2_common.py diff --git a/21-futures/getflags/flags2_sequential.py b/20-futures/getflags/flags2_sequential.py similarity index 100% rename from 21-futures/getflags/flags2_sequential.py rename to 20-futures/getflags/flags2_sequential.py diff --git a/21-futures/getflags/flags2_threadpool.py b/20-futures/getflags/flags2_threadpool.py similarity index 100% rename from 21-futures/getflags/flags2_threadpool.py rename to 20-futures/getflags/flags2_threadpool.py diff --git a/21-futures/getflags/flags3_asyncio.py b/20-futures/getflags/flags3_asyncio.py similarity index 100% rename from 21-futures/getflags/flags3_asyncio.py rename to 20-futures/getflags/flags3_asyncio.py diff --git a/21-futures/getflags/flags_asyncio.py b/20-futures/getflags/flags_asyncio.py similarity index 100% rename from 21-futures/getflags/flags_asyncio.py rename to 20-futures/getflags/flags_asyncio.py diff --git a/21-futures/getflags/flags_threadpool.py b/20-futures/getflags/flags_threadpool.py similarity index 100% rename from 21-futures/getflags/flags_threadpool.py rename to 20-futures/getflags/flags_threadpool.py diff --git a/21-futures/getflags/flags_threadpool_futures.py b/20-futures/getflags/flags_threadpool_futures.py similarity index 100% rename from 21-futures/getflags/flags_threadpool_futures.py rename to 20-futures/getflags/flags_threadpool_futures.py diff --git a/21-futures/getflags/requirements.txt b/20-futures/getflags/requirements.txt similarity index 100% rename from 21-futures/getflags/requirements.txt rename to 20-futures/getflags/requirements.txt diff --git a/21-futures/getflags/slow_server.py b/20-futures/getflags/slow_server.py similarity index 100% rename from 21-futures/getflags/slow_server.py rename to 20-futures/getflags/slow_server.py diff --git a/21-futures/primes/primes.py b/20-futures/primes/primes.py similarity index 100% rename from 21-futures/primes/primes.py rename to 20-futures/primes/primes.py diff --git a/21-futures/primes/proc_pool.py b/20-futures/primes/proc_pool.py similarity index 100% rename from 21-futures/primes/proc_pool.py rename to 20-futures/primes/proc_pool.py diff --git a/22-async/README.rst b/21-async/README.rst similarity index 100% rename from 22-async/README.rst rename to 21-async/README.rst diff --git a/22-async/domains/README.rst b/21-async/domains/README.rst similarity index 100% rename from 22-async/domains/README.rst rename to 21-async/domains/README.rst diff --git a/22-async/domains/asyncio/blogdom.py b/21-async/domains/asyncio/blogdom.py similarity index 100% rename from 22-async/domains/asyncio/blogdom.py rename to 21-async/domains/asyncio/blogdom.py diff --git a/22-async/domains/asyncio/domaincheck.py b/21-async/domains/asyncio/domaincheck.py similarity index 100% rename from 22-async/domains/asyncio/domaincheck.py rename to 21-async/domains/asyncio/domaincheck.py diff --git a/22-async/domains/asyncio/domainlib.py b/21-async/domains/asyncio/domainlib.py similarity index 100% rename from 22-async/domains/asyncio/domainlib.py rename to 21-async/domains/asyncio/domainlib.py diff --git a/22-async/domains/curio/blogdom.py b/21-async/domains/curio/blogdom.py similarity index 100% rename from 22-async/domains/curio/blogdom.py rename to 21-async/domains/curio/blogdom.py diff --git a/22-async/domains/curio/domaincheck.py b/21-async/domains/curio/domaincheck.py similarity index 100% rename from 22-async/domains/curio/domaincheck.py rename to 21-async/domains/curio/domaincheck.py diff --git a/22-async/domains/curio/domainlib.py b/21-async/domains/curio/domainlib.py similarity index 100% rename from 22-async/domains/curio/domainlib.py rename to 21-async/domains/curio/domainlib.py diff --git a/22-async/domains/curio/requirements.txt b/21-async/domains/curio/requirements.txt similarity index 100% rename from 22-async/domains/curio/requirements.txt rename to 21-async/domains/curio/requirements.txt diff --git a/22-async/mojifinder/README.md b/21-async/mojifinder/README.md similarity index 100% rename from 22-async/mojifinder/README.md rename to 21-async/mojifinder/README.md diff --git a/22-async/mojifinder/bottle.py b/21-async/mojifinder/bottle.py similarity index 100% rename from 22-async/mojifinder/bottle.py rename to 21-async/mojifinder/bottle.py diff --git a/22-async/mojifinder/charindex.py b/21-async/mojifinder/charindex.py similarity index 100% rename from 22-async/mojifinder/charindex.py rename to 21-async/mojifinder/charindex.py diff --git a/22-async/mojifinder/requirements.txt b/21-async/mojifinder/requirements.txt similarity index 100% rename from 22-async/mojifinder/requirements.txt rename to 21-async/mojifinder/requirements.txt diff --git a/22-async/mojifinder/static/form.html b/21-async/mojifinder/static/form.html similarity index 100% rename from 22-async/mojifinder/static/form.html rename to 21-async/mojifinder/static/form.html diff --git a/22-async/mojifinder/tcp_mojifinder.py b/21-async/mojifinder/tcp_mojifinder.py similarity index 100% rename from 22-async/mojifinder/tcp_mojifinder.py rename to 21-async/mojifinder/tcp_mojifinder.py diff --git a/22-async/mojifinder/web_mojifinder.py b/21-async/mojifinder/web_mojifinder.py similarity index 100% rename from 22-async/mojifinder/web_mojifinder.py rename to 21-async/mojifinder/web_mojifinder.py diff --git a/22-async/mojifinder/web_mojifinder_bottle.py b/21-async/mojifinder/web_mojifinder_bottle.py similarity index 100% rename from 22-async/mojifinder/web_mojifinder_bottle.py rename to 21-async/mojifinder/web_mojifinder_bottle.py diff --git a/23-dyn-attr-prop/README.rst b/22-dyn-attr-prop/README.rst similarity index 100% rename from 23-dyn-attr-prop/README.rst rename to 22-dyn-attr-prop/README.rst diff --git a/23-dyn-attr-prop/blackknight.py b/22-dyn-attr-prop/blackknight.py similarity index 100% rename from 23-dyn-attr-prop/blackknight.py rename to 22-dyn-attr-prop/blackknight.py diff --git a/23-dyn-attr-prop/bulkfood/bulkfood_v1.py b/22-dyn-attr-prop/bulkfood/bulkfood_v1.py similarity index 100% rename from 23-dyn-attr-prop/bulkfood/bulkfood_v1.py rename to 22-dyn-attr-prop/bulkfood/bulkfood_v1.py diff --git a/23-dyn-attr-prop/bulkfood/bulkfood_v2.py b/22-dyn-attr-prop/bulkfood/bulkfood_v2.py similarity index 100% rename from 23-dyn-attr-prop/bulkfood/bulkfood_v2.py rename to 22-dyn-attr-prop/bulkfood/bulkfood_v2.py diff --git a/23-dyn-attr-prop/bulkfood/bulkfood_v2b.py b/22-dyn-attr-prop/bulkfood/bulkfood_v2b.py similarity index 100% rename from 23-dyn-attr-prop/bulkfood/bulkfood_v2b.py rename to 22-dyn-attr-prop/bulkfood/bulkfood_v2b.py diff --git a/23-dyn-attr-prop/bulkfood/bulkfood_v2prop.py b/22-dyn-attr-prop/bulkfood/bulkfood_v2prop.py similarity index 100% rename from 23-dyn-attr-prop/bulkfood/bulkfood_v2prop.py rename to 22-dyn-attr-prop/bulkfood/bulkfood_v2prop.py diff --git a/23-dyn-attr-prop/doc_property.py b/22-dyn-attr-prop/doc_property.py similarity index 100% rename from 23-dyn-attr-prop/doc_property.py rename to 22-dyn-attr-prop/doc_property.py diff --git a/23-dyn-attr-prop/oscon/data/osconfeed.json b/22-dyn-attr-prop/oscon/data/osconfeed.json similarity index 100% rename from 23-dyn-attr-prop/oscon/data/osconfeed.json rename to 22-dyn-attr-prop/oscon/data/osconfeed.json diff --git a/23-dyn-attr-prop/oscon/demo_schedule2.py b/22-dyn-attr-prop/oscon/demo_schedule2.py similarity index 100% rename from 23-dyn-attr-prop/oscon/demo_schedule2.py rename to 22-dyn-attr-prop/oscon/demo_schedule2.py diff --git a/23-dyn-attr-prop/oscon/explore0.py b/22-dyn-attr-prop/oscon/explore0.py similarity index 100% rename from 23-dyn-attr-prop/oscon/explore0.py rename to 22-dyn-attr-prop/oscon/explore0.py diff --git a/23-dyn-attr-prop/oscon/explore1.py b/22-dyn-attr-prop/oscon/explore1.py similarity index 100% rename from 23-dyn-attr-prop/oscon/explore1.py rename to 22-dyn-attr-prop/oscon/explore1.py diff --git a/23-dyn-attr-prop/oscon/explore2.py b/22-dyn-attr-prop/oscon/explore2.py similarity index 100% rename from 23-dyn-attr-prop/oscon/explore2.py rename to 22-dyn-attr-prop/oscon/explore2.py diff --git a/23-dyn-attr-prop/oscon/osconfeed-sample.json b/22-dyn-attr-prop/oscon/osconfeed-sample.json similarity index 100% rename from 23-dyn-attr-prop/oscon/osconfeed-sample.json rename to 22-dyn-attr-prop/oscon/osconfeed-sample.json diff --git a/23-dyn-attr-prop/oscon/osconfeed_explore.rst b/22-dyn-attr-prop/oscon/osconfeed_explore.rst similarity index 100% rename from 23-dyn-attr-prop/oscon/osconfeed_explore.rst rename to 22-dyn-attr-prop/oscon/osconfeed_explore.rst diff --git a/23-dyn-attr-prop/oscon/runtests.sh b/22-dyn-attr-prop/oscon/runtests.sh similarity index 100% rename from 23-dyn-attr-prop/oscon/runtests.sh rename to 22-dyn-attr-prop/oscon/runtests.sh diff --git a/23-dyn-attr-prop/oscon/schedule_v1.py b/22-dyn-attr-prop/oscon/schedule_v1.py similarity index 100% rename from 23-dyn-attr-prop/oscon/schedule_v1.py rename to 22-dyn-attr-prop/oscon/schedule_v1.py diff --git a/23-dyn-attr-prop/oscon/schedule_v2.py b/22-dyn-attr-prop/oscon/schedule_v2.py similarity index 100% rename from 23-dyn-attr-prop/oscon/schedule_v2.py rename to 22-dyn-attr-prop/oscon/schedule_v2.py diff --git a/23-dyn-attr-prop/oscon/schedule_v3.py b/22-dyn-attr-prop/oscon/schedule_v3.py similarity index 100% rename from 23-dyn-attr-prop/oscon/schedule_v3.py rename to 22-dyn-attr-prop/oscon/schedule_v3.py diff --git a/23-dyn-attr-prop/oscon/schedule_v4.py b/22-dyn-attr-prop/oscon/schedule_v4.py similarity index 100% rename from 23-dyn-attr-prop/oscon/schedule_v4.py rename to 22-dyn-attr-prop/oscon/schedule_v4.py diff --git a/23-dyn-attr-prop/oscon/schedule_v4_hasattr.py b/22-dyn-attr-prop/oscon/schedule_v4_hasattr.py similarity index 100% rename from 23-dyn-attr-prop/oscon/schedule_v4_hasattr.py rename to 22-dyn-attr-prop/oscon/schedule_v4_hasattr.py diff --git a/23-dyn-attr-prop/oscon/schedule_v5.py b/22-dyn-attr-prop/oscon/schedule_v5.py similarity index 100% rename from 23-dyn-attr-prop/oscon/schedule_v5.py rename to 22-dyn-attr-prop/oscon/schedule_v5.py diff --git a/23-dyn-attr-prop/oscon/test_schedule_v1.py b/22-dyn-attr-prop/oscon/test_schedule_v1.py similarity index 100% rename from 23-dyn-attr-prop/oscon/test_schedule_v1.py rename to 22-dyn-attr-prop/oscon/test_schedule_v1.py diff --git a/23-dyn-attr-prop/oscon/test_schedule_v2.py b/22-dyn-attr-prop/oscon/test_schedule_v2.py similarity index 100% rename from 23-dyn-attr-prop/oscon/test_schedule_v2.py rename to 22-dyn-attr-prop/oscon/test_schedule_v2.py diff --git a/23-dyn-attr-prop/oscon/test_schedule_v3.py b/22-dyn-attr-prop/oscon/test_schedule_v3.py similarity index 100% rename from 23-dyn-attr-prop/oscon/test_schedule_v3.py rename to 22-dyn-attr-prop/oscon/test_schedule_v3.py diff --git a/23-dyn-attr-prop/oscon/test_schedule_v4.py b/22-dyn-attr-prop/oscon/test_schedule_v4.py similarity index 100% rename from 23-dyn-attr-prop/oscon/test_schedule_v4.py rename to 22-dyn-attr-prop/oscon/test_schedule_v4.py diff --git a/23-dyn-attr-prop/oscon/test_schedule_v5.py b/22-dyn-attr-prop/oscon/test_schedule_v5.py similarity index 100% rename from 23-dyn-attr-prop/oscon/test_schedule_v5.py rename to 22-dyn-attr-prop/oscon/test_schedule_v5.py diff --git a/23-dyn-attr-prop/pseudo_construction.py b/22-dyn-attr-prop/pseudo_construction.py similarity index 100% rename from 23-dyn-attr-prop/pseudo_construction.py rename to 22-dyn-attr-prop/pseudo_construction.py diff --git a/24-descriptor/README.rst b/23-descriptor/README.rst similarity index 100% rename from 24-descriptor/README.rst rename to 23-descriptor/README.rst diff --git a/24-descriptor/bulkfood/bulkfood_v3.py b/23-descriptor/bulkfood/bulkfood_v3.py similarity index 100% rename from 24-descriptor/bulkfood/bulkfood_v3.py rename to 23-descriptor/bulkfood/bulkfood_v3.py diff --git a/24-descriptor/bulkfood/bulkfood_v4.py b/23-descriptor/bulkfood/bulkfood_v4.py similarity index 100% rename from 24-descriptor/bulkfood/bulkfood_v4.py rename to 23-descriptor/bulkfood/bulkfood_v4.py diff --git a/24-descriptor/bulkfood/bulkfood_v4c.py b/23-descriptor/bulkfood/bulkfood_v4c.py similarity index 100% rename from 24-descriptor/bulkfood/bulkfood_v4c.py rename to 23-descriptor/bulkfood/bulkfood_v4c.py diff --git a/24-descriptor/bulkfood/bulkfood_v5.py b/23-descriptor/bulkfood/bulkfood_v5.py similarity index 100% rename from 24-descriptor/bulkfood/bulkfood_v5.py rename to 23-descriptor/bulkfood/bulkfood_v5.py diff --git a/24-descriptor/bulkfood/model_v4c.py b/23-descriptor/bulkfood/model_v4c.py similarity index 100% rename from 24-descriptor/bulkfood/model_v4c.py rename to 23-descriptor/bulkfood/model_v4c.py diff --git a/24-descriptor/bulkfood/model_v5.py b/23-descriptor/bulkfood/model_v5.py similarity index 100% rename from 24-descriptor/bulkfood/model_v5.py rename to 23-descriptor/bulkfood/model_v5.py diff --git a/24-descriptor/descriptorkinds.py b/23-descriptor/descriptorkinds.py similarity index 100% rename from 24-descriptor/descriptorkinds.py rename to 23-descriptor/descriptorkinds.py diff --git a/24-descriptor/descriptorkinds_dump.py b/23-descriptor/descriptorkinds_dump.py similarity index 100% rename from 24-descriptor/descriptorkinds_dump.py rename to 23-descriptor/descriptorkinds_dump.py diff --git a/24-descriptor/method_is_descriptor.py b/23-descriptor/method_is_descriptor.py similarity index 100% rename from 24-descriptor/method_is_descriptor.py rename to 23-descriptor/method_is_descriptor.py diff --git a/25-class-metaprog/autoconst/autoconst.py b/24-class-metaprog/autoconst/autoconst.py similarity index 100% rename from 25-class-metaprog/autoconst/autoconst.py rename to 24-class-metaprog/autoconst/autoconst.py diff --git a/25-class-metaprog/autoconst/autoconst_demo.py b/24-class-metaprog/autoconst/autoconst_demo.py similarity index 100% rename from 25-class-metaprog/autoconst/autoconst_demo.py rename to 24-class-metaprog/autoconst/autoconst_demo.py diff --git a/25-class-metaprog/bulkfood/README.md b/24-class-metaprog/bulkfood/README.md similarity index 100% rename from 25-class-metaprog/bulkfood/README.md rename to 24-class-metaprog/bulkfood/README.md diff --git a/25-class-metaprog/bulkfood/bulkfood_v6.py b/24-class-metaprog/bulkfood/bulkfood_v6.py similarity index 100% rename from 25-class-metaprog/bulkfood/bulkfood_v6.py rename to 24-class-metaprog/bulkfood/bulkfood_v6.py diff --git a/25-class-metaprog/bulkfood/bulkfood_v7.py b/24-class-metaprog/bulkfood/bulkfood_v7.py similarity index 100% rename from 25-class-metaprog/bulkfood/bulkfood_v7.py rename to 24-class-metaprog/bulkfood/bulkfood_v7.py diff --git a/25-class-metaprog/bulkfood/bulkfood_v8.py b/24-class-metaprog/bulkfood/bulkfood_v8.py similarity index 100% rename from 25-class-metaprog/bulkfood/bulkfood_v8.py rename to 24-class-metaprog/bulkfood/bulkfood_v8.py diff --git a/25-class-metaprog/bulkfood/model_v6.py b/24-class-metaprog/bulkfood/model_v6.py similarity index 100% rename from 25-class-metaprog/bulkfood/model_v6.py rename to 24-class-metaprog/bulkfood/model_v6.py diff --git a/25-class-metaprog/bulkfood/model_v7.py b/24-class-metaprog/bulkfood/model_v7.py similarity index 100% rename from 25-class-metaprog/bulkfood/model_v7.py rename to 24-class-metaprog/bulkfood/model_v7.py diff --git a/25-class-metaprog/bulkfood/model_v8.py b/24-class-metaprog/bulkfood/model_v8.py similarity index 100% rename from 25-class-metaprog/bulkfood/model_v8.py rename to 24-class-metaprog/bulkfood/model_v8.py diff --git a/25-class-metaprog/checked/decorator/checkeddeco.py b/24-class-metaprog/checked/decorator/checkeddeco.py similarity index 100% rename from 25-class-metaprog/checked/decorator/checkeddeco.py rename to 24-class-metaprog/checked/decorator/checkeddeco.py diff --git a/25-class-metaprog/checked/decorator/checkeddeco_demo.py b/24-class-metaprog/checked/decorator/checkeddeco_demo.py similarity index 100% rename from 25-class-metaprog/checked/decorator/checkeddeco_demo.py rename to 24-class-metaprog/checked/decorator/checkeddeco_demo.py diff --git a/25-class-metaprog/checked/decorator/checkeddeco_test.py b/24-class-metaprog/checked/decorator/checkeddeco_test.py similarity index 100% rename from 25-class-metaprog/checked/decorator/checkeddeco_test.py rename to 24-class-metaprog/checked/decorator/checkeddeco_test.py diff --git a/25-class-metaprog/checked/initsub/checked_demo.py b/24-class-metaprog/checked/initsub/checked_demo.py similarity index 100% rename from 25-class-metaprog/checked/initsub/checked_demo.py rename to 24-class-metaprog/checked/initsub/checked_demo.py diff --git a/25-class-metaprog/checked/initsub/checkedlib.py b/24-class-metaprog/checked/initsub/checkedlib.py similarity index 100% rename from 25-class-metaprog/checked/initsub/checkedlib.py rename to 24-class-metaprog/checked/initsub/checkedlib.py diff --git a/25-class-metaprog/checked/initsub/checkedlib_test.py b/24-class-metaprog/checked/initsub/checkedlib_test.py similarity index 100% rename from 25-class-metaprog/checked/initsub/checkedlib_test.py rename to 24-class-metaprog/checked/initsub/checkedlib_test.py diff --git a/25-class-metaprog/checked/metaclass/checked_demo.py b/24-class-metaprog/checked/metaclass/checked_demo.py similarity index 100% rename from 25-class-metaprog/checked/metaclass/checked_demo.py rename to 24-class-metaprog/checked/metaclass/checked_demo.py diff --git a/25-class-metaprog/checked/metaclass/checkedlib.py b/24-class-metaprog/checked/metaclass/checkedlib.py similarity index 100% rename from 25-class-metaprog/checked/metaclass/checkedlib.py rename to 24-class-metaprog/checked/metaclass/checkedlib.py diff --git a/25-class-metaprog/checked/metaclass/checkedlib_test.py b/24-class-metaprog/checked/metaclass/checkedlib_test.py similarity index 100% rename from 25-class-metaprog/checked/metaclass/checkedlib_test.py rename to 24-class-metaprog/checked/metaclass/checkedlib_test.py diff --git a/25-class-metaprog/evaltime/builderlib.py b/24-class-metaprog/evaltime/builderlib.py similarity index 100% rename from 25-class-metaprog/evaltime/builderlib.py rename to 24-class-metaprog/evaltime/builderlib.py diff --git a/25-class-metaprog/evaltime/evaldemo.py b/24-class-metaprog/evaltime/evaldemo.py similarity index 100% rename from 25-class-metaprog/evaltime/evaldemo.py rename to 24-class-metaprog/evaltime/evaldemo.py diff --git a/25-class-metaprog/evaltime/evaldemo_meta.py b/24-class-metaprog/evaltime/evaldemo_meta.py similarity index 100% rename from 25-class-metaprog/evaltime/evaldemo_meta.py rename to 24-class-metaprog/evaltime/evaldemo_meta.py diff --git a/25-class-metaprog/evaltime/metalib.py b/24-class-metaprog/evaltime/metalib.py similarity index 100% rename from 25-class-metaprog/evaltime/metalib.py rename to 24-class-metaprog/evaltime/metalib.py diff --git a/25-class-metaprog/factories.py b/24-class-metaprog/factories.py similarity index 100% rename from 25-class-metaprog/factories.py rename to 24-class-metaprog/factories.py diff --git a/25-class-metaprog/factories_ducktyped.py b/24-class-metaprog/factories_ducktyped.py similarity index 100% rename from 25-class-metaprog/factories_ducktyped.py rename to 24-class-metaprog/factories_ducktyped.py diff --git a/25-class-metaprog/hours/hours.py b/24-class-metaprog/hours/hours.py similarity index 100% rename from 25-class-metaprog/hours/hours.py rename to 24-class-metaprog/hours/hours.py diff --git a/25-class-metaprog/hours/hours_test.py b/24-class-metaprog/hours/hours_test.py similarity index 100% rename from 25-class-metaprog/hours/hours_test.py rename to 24-class-metaprog/hours/hours_test.py diff --git a/25-class-metaprog/metabunch/README.md b/24-class-metaprog/metabunch/README.md similarity index 100% rename from 25-class-metaprog/metabunch/README.md rename to 24-class-metaprog/metabunch/README.md diff --git a/25-class-metaprog/metabunch/from3.6/bunch.py b/24-class-metaprog/metabunch/from3.6/bunch.py similarity index 100% rename from 25-class-metaprog/metabunch/from3.6/bunch.py rename to 24-class-metaprog/metabunch/from3.6/bunch.py diff --git a/25-class-metaprog/metabunch/from3.6/bunch_test.py b/24-class-metaprog/metabunch/from3.6/bunch_test.py similarity index 100% rename from 25-class-metaprog/metabunch/from3.6/bunch_test.py rename to 24-class-metaprog/metabunch/from3.6/bunch_test.py diff --git a/25-class-metaprog/metabunch/nutshell3e/bunch.py b/24-class-metaprog/metabunch/nutshell3e/bunch.py similarity index 100% rename from 25-class-metaprog/metabunch/nutshell3e/bunch.py rename to 24-class-metaprog/metabunch/nutshell3e/bunch.py diff --git a/25-class-metaprog/metabunch/nutshell3e/bunch_test.py b/24-class-metaprog/metabunch/nutshell3e/bunch_test.py similarity index 100% rename from 25-class-metaprog/metabunch/nutshell3e/bunch_test.py rename to 24-class-metaprog/metabunch/nutshell3e/bunch_test.py diff --git a/25-class-metaprog/metabunch/original/bunch.py b/24-class-metaprog/metabunch/original/bunch.py similarity index 100% rename from 25-class-metaprog/metabunch/original/bunch.py rename to 24-class-metaprog/metabunch/original/bunch.py diff --git a/25-class-metaprog/metabunch/original/bunch_test.py b/24-class-metaprog/metabunch/original/bunch_test.py similarity index 100% rename from 25-class-metaprog/metabunch/original/bunch_test.py rename to 24-class-metaprog/metabunch/original/bunch_test.py diff --git a/25-class-metaprog/metabunch/pre3.6/bunch.py b/24-class-metaprog/metabunch/pre3.6/bunch.py similarity index 100% rename from 25-class-metaprog/metabunch/pre3.6/bunch.py rename to 24-class-metaprog/metabunch/pre3.6/bunch.py diff --git a/25-class-metaprog/metabunch/pre3.6/bunch_test.py b/24-class-metaprog/metabunch/pre3.6/bunch_test.py similarity index 100% rename from 25-class-metaprog/metabunch/pre3.6/bunch_test.py rename to 24-class-metaprog/metabunch/pre3.6/bunch_test.py diff --git a/25-class-metaprog/persistent/.gitignore b/24-class-metaprog/persistent/.gitignore similarity index 100% rename from 25-class-metaprog/persistent/.gitignore rename to 24-class-metaprog/persistent/.gitignore diff --git a/25-class-metaprog/persistent/dblib.py b/24-class-metaprog/persistent/dblib.py similarity index 100% rename from 25-class-metaprog/persistent/dblib.py rename to 24-class-metaprog/persistent/dblib.py diff --git a/25-class-metaprog/persistent/dblib_test.py b/24-class-metaprog/persistent/dblib_test.py similarity index 100% rename from 25-class-metaprog/persistent/dblib_test.py rename to 24-class-metaprog/persistent/dblib_test.py diff --git a/25-class-metaprog/persistent/persistlib.py b/24-class-metaprog/persistent/persistlib.py similarity index 100% rename from 25-class-metaprog/persistent/persistlib.py rename to 24-class-metaprog/persistent/persistlib.py diff --git a/25-class-metaprog/persistent/persistlib_test.py b/24-class-metaprog/persistent/persistlib_test.py similarity index 100% rename from 25-class-metaprog/persistent/persistlib_test.py rename to 24-class-metaprog/persistent/persistlib_test.py diff --git a/25-class-metaprog/qualname/fakedjango.py b/24-class-metaprog/qualname/fakedjango.py similarity index 100% rename from 25-class-metaprog/qualname/fakedjango.py rename to 24-class-metaprog/qualname/fakedjango.py diff --git a/25-class-metaprog/qualname/models.py b/24-class-metaprog/qualname/models.py similarity index 100% rename from 25-class-metaprog/qualname/models.py rename to 24-class-metaprog/qualname/models.py diff --git a/25-class-metaprog/sentinel/sentinel.py b/24-class-metaprog/sentinel/sentinel.py similarity index 100% rename from 25-class-metaprog/sentinel/sentinel.py rename to 24-class-metaprog/sentinel/sentinel.py diff --git a/25-class-metaprog/sentinel/sentinel_test.py b/24-class-metaprog/sentinel/sentinel_test.py similarity index 100% rename from 25-class-metaprog/sentinel/sentinel_test.py rename to 24-class-metaprog/sentinel/sentinel_test.py diff --git a/25-class-metaprog/setattr/example_from_leo.py b/24-class-metaprog/setattr/example_from_leo.py similarity index 100% rename from 25-class-metaprog/setattr/example_from_leo.py rename to 24-class-metaprog/setattr/example_from_leo.py diff --git a/25-class-metaprog/slots/slots_timing.py b/24-class-metaprog/slots/slots_timing.py similarity index 100% rename from 25-class-metaprog/slots/slots_timing.py rename to 24-class-metaprog/slots/slots_timing.py diff --git a/25-class-metaprog/tinyenums/microenum.py b/24-class-metaprog/tinyenums/microenum.py similarity index 100% rename from 25-class-metaprog/tinyenums/microenum.py rename to 24-class-metaprog/tinyenums/microenum.py diff --git a/25-class-metaprog/tinyenums/microenum_demo.py b/24-class-metaprog/tinyenums/microenum_demo.py similarity index 100% rename from 25-class-metaprog/tinyenums/microenum_demo.py rename to 24-class-metaprog/tinyenums/microenum_demo.py diff --git a/25-class-metaprog/tinyenums/nanoenum.py b/24-class-metaprog/tinyenums/nanoenum.py similarity index 100% rename from 25-class-metaprog/tinyenums/nanoenum.py rename to 24-class-metaprog/tinyenums/nanoenum.py diff --git a/25-class-metaprog/tinyenums/nanoenum_demo.py b/24-class-metaprog/tinyenums/nanoenum_demo.py similarity index 100% rename from 25-class-metaprog/tinyenums/nanoenum_demo.py rename to 24-class-metaprog/tinyenums/nanoenum_demo.py diff --git a/README.md b/README.md index 102993a..f0854e9 100644 --- a/README.md +++ b/README.md @@ -41,13 +41,12 @@ Part / Chapter #|Title|Directory|1st ed. Chapter # 15|More About Type Hints|[15-more-types](15-more-types)|🆕 16|Operator Overloading: Doing It Right|[16-op-overloading](16-op-overloading)|13 **V – Control Flow**| -17|Iterables, Iterators, and Generators|[17-it-generator](17-it-generator)|14 +17|Iterators, Generators, and Classic Coroutines|[17-it-generator](17-it-generator)|14 18|Context Managers and else Blocks|[18-with-match](18-with-match)|15 -19|Classic Coroutines|[19-coroutine](19-coroutine)|16 -20|Concurrency Models in Python|[20-concurrency](20-concurrency)|🆕 -21|Concurrency with Futures|[21-futures](21-futures)|17 -22|Asynchronous Programming|[22-async](22-async)|18 +19|Concurrency Models in Python|[19-concurrency](19-concurrency)|🆕 +20|Concurrency with Futures|[20-futures](20-futures)|17 +21|Asynchronous Programming|[21-async](21-async)|18 **VI – Metaprogramming**| -23|Dynamic Attributes and Properties|[22-dyn-attr-prop](22-dyn-attr-prop)|19 -24|Attribute Descriptors|[23-descriptor](23-descriptor)|20 -25|Class Metaprogramming|[24-class-metaprog](24-class-metaprog)|21 +22|Dynamic Attributes and Properties|[22-dyn-attr-prop](22-dyn-attr-prop)|19 +23|Attribute Descriptors|[23-descriptor](23-descriptor)|20 +24|Class Metaprogramming|[24-class-metaprog](24-class-metaprog)|21 From 6527037ae7319ba370a1ee2d9fe79214d0ed9452 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Wed, 15 Sep 2021 22:48:08 -0300 Subject: [PATCH 06/66] moved lispy from 02 to 18 --- 02-array-seq/lispy/py3.10/examples_test.py | 109 -------- 02-array-seq/lispy/py3.10/meta_test.py | 69 ----- 02-array-seq/lispy/py3.9-no-hints/README.md | 33 --- 02-array-seq/lispy/py3.9-no-hints/lis.py | 142 ---------- 02-array-seq/lispy/py3.9-no-hints/lis_test.py | 166 ----------- 05-data-classes/dataclass/hackerclub.py | 2 +- .../dataclass/hackerclub_annotated.py | 2 +- 17-it-generator/aritprog_v3.py | 6 +- 17-it-generator/coroaverager.py | 43 +++ 17-it-generator/coroaverager2.py | 96 +++++++ 17-it-generator/fibo_gen.py | 7 + 17-it-generator/sentence_gen.py | 2 +- 18-with-match/lisplus/examples_test.py | 109 -------- 18-with-match/lisplus/lis.py | 192 ------------- 18-with-match/lisplus/lis_test.py | 182 ------------ 18-with-match/lisplus/meta_test.py | 64 ----- {02-array-seq => 18-with-match}/lispy/LICENSE | 0 .../lispy/README.md | 0 .../lispy/original/LICENSE | 0 .../lispy/original/README.md | 0 .../lispy/original/lis.py | 0 .../lispy/original/lispy.py | 0 .../lispy/original/lispytest.py | 0 18-with-match/lispy/py3.10/examples_test.py | 259 ++++++++++++++++++ .../lispy/py3.10/lis.py | 178 +++++++----- .../lispy/py3.10/lis_test.py | 0 18-with-match/lispy/py3.10/quicksort.scm | 17 ++ .../lispy/py3.9/README.md | 0 .../lispy/py3.9/lis.py | 18 +- .../lispy/py3.9/lis_test.py | 0 18-with-match/mirror.py | 28 +- 18-with-match/mirror_gen.py | 22 +- 18-with-match/mirror_gen_exc.py | 9 +- 20-futures/getflags/flags2_asyncio.py | 4 +- 20-futures/getflags/flags3_asyncio.py | 4 +- 20-futures/getflags/requirements.txt | 16 +- 20-futures/getflags/slow_server.py | 1 + 22-dyn-attr-prop/oscon/demo_schedule2.py | 25 -- 38 files changed, 588 insertions(+), 1217 deletions(-) delete mode 100644 02-array-seq/lispy/py3.10/examples_test.py delete mode 100644 02-array-seq/lispy/py3.10/meta_test.py delete mode 100644 02-array-seq/lispy/py3.9-no-hints/README.md delete mode 100644 02-array-seq/lispy/py3.9-no-hints/lis.py delete mode 100644 02-array-seq/lispy/py3.9-no-hints/lis_test.py create mode 100644 17-it-generator/coroaverager.py create mode 100644 17-it-generator/coroaverager2.py create mode 100644 17-it-generator/fibo_gen.py delete mode 100644 18-with-match/lisplus/examples_test.py delete mode 100644 18-with-match/lisplus/lis.py delete mode 100644 18-with-match/lisplus/lis_test.py delete mode 100644 18-with-match/lisplus/meta_test.py rename {02-array-seq => 18-with-match}/lispy/LICENSE (100%) rename {02-array-seq => 18-with-match}/lispy/README.md (100%) rename {02-array-seq => 18-with-match}/lispy/original/LICENSE (100%) rename {02-array-seq => 18-with-match}/lispy/original/README.md (100%) rename {02-array-seq => 18-with-match}/lispy/original/lis.py (100%) rename {02-array-seq => 18-with-match}/lispy/original/lispy.py (100%) rename {02-array-seq => 18-with-match}/lispy/original/lispytest.py (100%) create mode 100644 18-with-match/lispy/py3.10/examples_test.py rename {02-array-seq => 18-with-match}/lispy/py3.10/lis.py (70%) mode change 100644 => 100755 rename {02-array-seq => 18-with-match}/lispy/py3.10/lis_test.py (100%) create mode 100644 18-with-match/lispy/py3.10/quicksort.scm rename {02-array-seq => 18-with-match}/lispy/py3.9/README.md (100%) rename {02-array-seq => 18-with-match}/lispy/py3.9/lis.py (91%) rename {02-array-seq => 18-with-match}/lispy/py3.9/lis_test.py (100%) delete mode 100755 22-dyn-attr-prop/oscon/demo_schedule2.py diff --git a/02-array-seq/lispy/py3.10/examples_test.py b/02-array-seq/lispy/py3.10/examples_test.py deleted file mode 100644 index 38510a3..0000000 --- a/02-array-seq/lispy/py3.10/examples_test.py +++ /dev/null @@ -1,109 +0,0 @@ -""" -Doctests for `parse`: - ->>> from lis import parse - -# tag::PARSE_DEMO[] ->>> parse('1.5') # <1> -1.5 ->>> parse('set!') # <2> -'set!' ->>> parse('(gcd 18 44)') # <3> -['gcd', 18, 44] ->>> parse('(- m (* n (// m n)))') # <4> -['-', 'm', ['*', 'n', ['//', 'm', 'n']]] - -# end::PARSE_DEMO[] - -""" - -import math - -from lis import run - - -fact_src = """ -(define (! n) - (if (< n 2) - 1 - (* n (! (- n 1))) - ) -) -(! 42) -""" -def test_factorial(): - got = run(fact_src) - assert got == 1405006117752879898543142606244511569936384000000000 - assert got == math.factorial(42) - - -gcd_src = """ -(define (mod m n) - (- m (* n (// m n)))) -(define (gcd m n) - (if (= n 0) - m - (gcd n (mod m n)))) -(gcd 18 45) -""" -def test_gcd(): - got = run(gcd_src) - assert got == 9 - - -quicksort_src = """ -(define (quicksort lst) - (if (null? lst) - lst - (begin - (define pivot (car lst)) - (define rest (cdr lst)) - (append - (quicksort - (filter (lambda (x) (< x pivot)) rest)) - (list pivot) - (quicksort - (filter (lambda (x) (>= x pivot)) rest))) - ) - ) -) -(quicksort (list 2 1 6 3 4 0 8 9 7 5)) -""" -def test_quicksort(): - got = run(quicksort_src) - assert got == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - - -# Example from Structure and Interpretation of Computer Programs -# https://mitpress.mit.edu/sites/default/files/sicp/full-text/sicp/book/node12.html - -newton_src = """ -(define (sqrt x) - (sqrt-iter 1.0 x)) -(define (sqrt-iter guess x) - (if (good-enough? guess x) - guess - (sqrt-iter (improve guess x) x))) -(define (good-enough? guess x) - (< (abs (- (* guess guess) x)) 0.001)) -(define (improve guess x) - (average guess (/ x guess))) -(define (average x y) - (/ (+ x y) 2)) -(sqrt 123454321) -""" -def test_newton(): - got = run(newton_src) - assert math.isclose(got, 11111) - - -closure_src = """ -(define (make-adder increment) - (lambda (x) (+ increment x)) -) -(define inc (make-adder 1)) -(inc 99) -""" -def test_newton(): - got = run(closure_src) - assert got == 100 diff --git a/02-array-seq/lispy/py3.10/meta_test.py b/02-array-seq/lispy/py3.10/meta_test.py deleted file mode 100644 index 3ddc3f3..0000000 --- a/02-array-seq/lispy/py3.10/meta_test.py +++ /dev/null @@ -1,69 +0,0 @@ -""" -Tests for developing a meta-circular interpreter, step-by-step. -""" - - -import operator as op - -from lis import run - -env_scm = """ -(define standard-env (list - (list (quote +) +) - (list (quote -) -) -)) -standard-env -""" - -def test_env_build(): - got = run(env_scm) - assert got == [['+', op.add], ['-', op.sub]] - -scan_scm = """ -(define l (quote (a b c))) -(define (scan what where) - (if (null? where) - () - (if (eq? what (car where)) - what - (scan what (cdr where)))) -) -""" - -def test_scan(): - source = scan_scm + '(scan (quote a) l )' - got = run(source) - assert got == 'a' - - -def test_scan_not_found(): - source = scan_scm + '(scan (quote z) l )' - got = run(source) - assert got == [] - - -lookup_scm = """ -(define env (list - (list (quote +) +) - (list (quote -) -) -)) -(define (lookup what where) - (if (null? where) - () - (if (eq? what (car (car where))) - (car (cdr (car where))) - (lookup what (cdr where)))) -) -""" - -def test_lookup(): - source = lookup_scm + '(lookup (quote +) env)' - got = run(source) - assert got == op.add - - -def test_lookup_not_found(): - source = lookup_scm + '(lookup (quote z) env )' - got = run(source) - assert got == [] - diff --git a/02-array-seq/lispy/py3.9-no-hints/README.md b/02-array-seq/lispy/py3.9-no-hints/README.md deleted file mode 100644 index 2b6f4ea..0000000 --- a/02-array-seq/lispy/py3.9-no-hints/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# Changes from the original - -While adapting Peter Norvig's [lis.py](https://github.com/norvig/pytudes/blob/705c0a335c1811a203e79587d7d41865cf7f41c7/py/lis.py) for -use in _Fluent Python, Second Edition_, I made a few changes for didactic reasons. - -_Luciano Ramalho_ - -## Significant changes - -* Make the `lambda` form accept more than one expression as the body. This is consistent with _Scheme_ syntax, and provides a useful example for the book. To implement this: - * In `Procedure.__call__`: evaluate `self.body` as a list of expressions, instead of a single expression. Return the value of the last expression. - * In `evaluate()`: when processing `lambda`, unpack expression into `(_, parms, *body)`, to accept a list of expressions as the body. -* Remove the `global_env` global `dict`. It is only used as a default value for the `env` parameter in `evaluate()`, but it is unsafe to use mutable data structures as parameter default values. To implement this: - * In `repl()`: create local variable `global_env` and pass it as the `env` paramater of `evaluate()`. - * In `evaluate()`, remove `global_env` default value for `env`. -* Rewrite the custom test script -[lispytest.py](https://github.com/norvig/pytudes/blob/705c0a335c1811a203e79587d7d41865cf7f41c7/py/lispytest.py) as -[lis_test.py](https://github.com/fluentpython/example-code-2e/blob/master/02-array-seq/lispy/py3.9/lis_test.py): -a standard [pytest](https://docs.pytest.org) test suite including new test cases, preserving all Norvig's the test cases for -[lis.py](https://github.com/norvig/pytudes/blob/705c0a335c1811a203e79587d7d41865cf7f41c7/py/lis.py) -but removing the test cases for the features implemented only in -[lispy.py](https://github.com/norvig/pytudes/blob/705c0a335c1811a203e79587d7d41865cf7f41c7/py/lispy.py) - - -## Name changes - -Cosmetic changes to make the code look more familiar to -Python programmers, the audience of _Fluent Python_. - -* Rename `eval()` to `evaluate()`, to avoid confusion with Python's `eval` built-in function. -* Refer to the list class as `list` instead of aliasing as `List`, to avoid confusion with `typing.List` which is often imported as `List`. -* Import `collections.ChainMap` as `ChainMap` instead of `Environment`. - diff --git a/02-array-seq/lispy/py3.9-no-hints/lis.py b/02-array-seq/lispy/py3.9-no-hints/lis.py deleted file mode 100644 index c74c3ae..0000000 --- a/02-array-seq/lispy/py3.9-no-hints/lis.py +++ /dev/null @@ -1,142 +0,0 @@ -################ Lispy: Scheme Interpreter in Python 3.9 - -## (c) Peter Norvig, 2010-18; See http://norvig.com/lispy.html -## Minor edits for Fluent Python, Second Edition (O'Reilly, 2021) -## by Luciano Ramalho, adding type hints and pattern matching. - -################ Imports and Types - -import math -import operator as op -from collections import ChainMap -from typing import Any - -Symbol = str # A Lisp Symbol is implemented as a Python str -Number = (int, float) # A Lisp Number is implemented as a Python int or float - -class Procedure: - "A user-defined Scheme procedure." - def __init__(self, parms, body, env): - self.parms, self.body, self.env = parms, body, env - def __call__(self, *args): - env = ChainMap(dict(zip(self.parms, args)), self.env) - for exp in self.body: - result = evaluate(exp, env) - return result - - -################ Global Environment - -def standard_env(): - "An environment with some Scheme standard procedures." - env = {} - env.update(vars(math)) # sin, cos, sqrt, pi, ... - env.update({ - '+':op.add, '-':op.sub, '*':op.mul, '/':op.truediv, - '>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq, - 'abs': abs, - 'append': op.add, - 'apply': lambda proc, args: proc(*args), - 'begin': lambda *x: x[-1], - 'car': lambda x: x[0], - 'cdr': lambda x: x[1:], - 'cons': lambda x,y: [x] + y, - 'eq?': op.is_, - 'equal?': op.eq, - 'length': len, - 'list': lambda *x: list(x), - 'list?': lambda x: isinstance(x,list), - 'map': lambda *args: list(map(*args)), - 'max': max, - 'min': min, - 'not': op.not_, - 'null?': lambda x: x == [], - 'number?': lambda x: isinstance(x, Number), - 'procedure?': callable, - 'round': round, - 'symbol?': lambda x: isinstance(x, Symbol), - }) - return env - -################ Parsing: parse, tokenize, and read_from_tokens - -def parse(program): - "Read a Scheme expression from a string." - return read_from_tokens(tokenize(program)) - -def tokenize(s): - "Convert a string into a list of tokens." - return s.replace('(',' ( ').replace(')',' ) ').split() - -def read_from_tokens(tokens): - "Read an expression from a sequence of tokens." - if len(tokens) == 0: - raise SyntaxError('unexpected EOF while reading') - token = tokens.pop(0) - if '(' == token: - exp = [] - while tokens[0] != ')': - exp.append(read_from_tokens(tokens)) - tokens.pop(0) # discard ')' - return exp - elif ')' == token: - raise SyntaxError('unexpected )') - else: - return parse_atom(token) - - -def parse_atom(token: str): - "Numbers become numbers; every other token is a symbol." - try: - return int(token) - except ValueError: - try: - return float(token) - except ValueError: - return Symbol(token) - - -################ Interaction: A REPL - -def repl(prompt: str = 'lis.py> ') -> None: - "A prompt-read-eval-print loop." - global_env = standard_env() - while True: - val = evaluate(parse(input(prompt)), global_env) - if val is not None: - print(lispstr(val)) - - -def lispstr(exp): - "Convert a Python object back into a Lisp-readable string." - if isinstance(exp, list): - return '(' + ' '.join(map(lispstr, exp)) + ')' - else: - return str(exp) - - -################ eval - -def evaluate(x, env): - "Evaluate an expression in an environment." - if isinstance(x, Symbol): # variable reference - return env[x] - elif not isinstance(x, list): # constant literal - return x - elif x[0] == 'quote': # (quote exp) - (_, exp) = x - return exp - elif x[0] == 'if': # (if test conseq alt) - (_, test, conseq, alt) = x - exp = (conseq if evaluate(test, env) else alt) - return evaluate(exp, env) - elif x[0] == 'define': # (define var exp) - (_, var, exp) = x - env[var] = evaluate(exp, env) - elif x[0] == 'lambda': # (lambda (var...) body) - (_, parms, *body) = x - return Procedure(parms, body, env) - else: # (proc arg...) - proc = evaluate(x[0], env) - args = [evaluate(exp, env) for exp in x[1:]] - return proc(*args) diff --git a/02-array-seq/lispy/py3.9-no-hints/lis_test.py b/02-array-seq/lispy/py3.9-no-hints/lis_test.py deleted file mode 100644 index f5f4f8e..0000000 --- a/02-array-seq/lispy/py3.9-no-hints/lis_test.py +++ /dev/null @@ -1,166 +0,0 @@ -from pytest import mark, fixture - -from lis import parse, evaluate, standard_env - -############################################################# tests for parse - -@mark.parametrize( 'source, expected', [ - ('7', 7), - ('x', 'x'), - ('(sum 1 2 3)', ['sum', 1, 2, 3]), - ('(+ (* 2 100) (* 1 10))', ['+', ['*', 2, 100], ['*', 1, 10]]), - ('99 100', 99), # parse stops at the first complete expression - ('(a)(b)', ['a']), -]) -def test_parse(source: str, expected): - got = parse(source) - assert got == expected - - -########################################################## tests for evaluate - -# Norvig's tests are not isolated: they assume the -# same environment from first to last test. -global_env_for_first_test = standard_env() - -@mark.parametrize( 'source, expected', [ - ("(quote (testing 1 (2.0) -3.14e159))", ['testing', 1, [2.0], -3.14e159]), - ("(+ 2 2)", 4), - ("(+ (* 2 100) (* 1 10))", 210), - ("(if (> 6 5) (+ 1 1) (+ 2 2))", 2), - ("(if (< 6 5) (+ 1 1) (+ 2 2))", 4), - ("(define x 3)", None), - ("x", 3), - ("(+ x x)", 6), - ("((lambda (x) (+ x x)) 5)", 10), - ("(define twice (lambda (x) (* 2 x)))", None), - ("(twice 5)", 10), - ("(define compose (lambda (f g) (lambda (x) (f (g x)))))", None), - ("((compose list twice) 5)", [10]), - ("(define repeat (lambda (f) (compose f f)))", None), - ("((repeat twice) 5)", 20), - ("((repeat (repeat twice)) 5)", 80), - ("(define fact (lambda (n) (if (<= n 1) 1 (* n (fact (- n 1))))))", None), - ("(fact 3)", 6), - ("(fact 50)", 30414093201713378043612608166064768844377641568960512000000000000), - ("(define abs (lambda (n) ((if (> n 0) + -) 0 n)))", None), - ("(list (abs -3) (abs 0) (abs 3))", [3, 0, 3]), - ("""(define combine (lambda (f) - (lambda (x y) - (if (null? x) (quote ()) - (f (list (car x) (car y)) - ((combine f) (cdr x) (cdr y)))))))""", None), - ("(define zip (combine cons))", None), - ("(zip (list 1 2 3 4) (list 5 6 7 8))", [[1, 5], [2, 6], [3, 7], [4, 8]]), - ("""(define riff-shuffle (lambda (deck) - (begin - (define take (lambda (n seq) (if (<= n 0) (quote ()) (cons (car seq) (take (- n 1) (cdr seq)))))) - (define drop (lambda (n seq) (if (<= n 0) seq (drop (- n 1) (cdr seq))))) - (define mid (lambda (seq) (/ (length seq) 2))) - ((combine append) (take (mid deck) deck) (drop (mid deck) deck)))))""", None), - ("(riff-shuffle (list 1 2 3 4 5 6 7 8))", [1, 5, 2, 6, 3, 7, 4, 8]), - ("((repeat riff-shuffle) (list 1 2 3 4 5 6 7 8))", [1, 3, 5, 7, 2, 4, 6, 8]), - ("(riff-shuffle (riff-shuffle (riff-shuffle (list 1 2 3 4 5 6 7 8))))", [1,2,3,4,5,6,7,8]), -]) -def test_evaluate(source, expected): - got = evaluate(parse(source), global_env_for_first_test) - assert got == expected - - -@fixture -def std_env(): - return standard_env() - -# tests for each of the cases in evaluate - -def test_evaluate_variable(): - env = dict(x=10) - source = 'x' - expected = 10 - got = evaluate(parse(source), env) - assert got == expected - - -def test_evaluate_literal(std_env): - source = '3.3' - expected = 3.3 - got = evaluate(parse(source), std_env) - assert got == expected - - -def test_evaluate_quote(std_env): - source = '(quote (1.1 is not 1))' - expected = [1.1, 'is', 'not', 1] - got = evaluate(parse(source), std_env) - assert got == expected - - -def test_evaluate_if_true(std_env) -> None: - source = '(if 1 10 no-such-thing)' - expected = 10 - got = evaluate(parse(source), std_env) - assert got == expected - - -def test_evaluate_if_false(std_env) -> None: - source = '(if 0 no-such-thing 20)' - expected = 20 - got = evaluate(parse(source), std_env) - assert got == expected - - -def test_define(std_env) -> None: - source = '(define answer (* 6 7))' - got = evaluate(parse(source), std_env) - assert got is None - assert std_env['answer'] == 42 - - -def test_lambda(std_env) -> None: - source = '(lambda (a b) (if (>= a b) a b))' - func = evaluate(parse(source), std_env) - assert func.parms == ['a', 'b'] - assert func.body == [['if', ['>=', 'a', 'b'], 'a', 'b']] - assert func.env is std_env - assert func(1, 2) == 2 - assert func(3, 2) == 3 - - -def test_begin(std_env) -> None: - source = """ - (begin - (define x (* 2 3)) - (* x 7) - ) - """ - got = evaluate(parse(source), std_env) - assert got == 42 - - -def test_invocation_builtin_car(std_env) -> None: - source = '(car (quote (11 22 33)))' - got = evaluate(parse(source), std_env) - assert got == 11 - - -def test_invocation_builtin_append(std_env) -> None: - source = '(append (quote (a b)) (quote (c d)))' - got = evaluate(parse(source), std_env) - assert got == ['a', 'b', 'c', 'd'] - - -def test_invocation_builtin_map(std_env) -> None: - source = '(map (lambda (x) (* x 2)) (quote (1 2 3))))' - got = evaluate(parse(source), std_env) - assert got == [2, 4, 6] - - -def test_invocation_user_procedure(std_env): - source = """ - (begin - (define max (lambda (a b) (if (>= a b) a b))) - (max 22 11) - ) - """ - got = evaluate(parse(source), std_env) - assert got == 22 diff --git a/05-data-classes/dataclass/hackerclub.py b/05-data-classes/dataclass/hackerclub.py index 762c2cd..60f8234 100644 --- a/05-data-classes/dataclass/hackerclub.py +++ b/05-data-classes/dataclass/hackerclub.py @@ -6,7 +6,7 @@ >>> anna HackerClubMember(name='Anna Ravenscroft', guests=[], handle='AnnaRaven') -If ``handle`` is ommitted, it's set to the first part of the member's name:: +If ``handle`` is omitted, it's set to the first part of the member's name:: >>> leo = HackerClubMember('Leo Rochael') >>> leo diff --git a/05-data-classes/dataclass/hackerclub_annotated.py b/05-data-classes/dataclass/hackerclub_annotated.py index 2394796..0b87c50 100644 --- a/05-data-classes/dataclass/hackerclub_annotated.py +++ b/05-data-classes/dataclass/hackerclub_annotated.py @@ -6,7 +6,7 @@ >>> anna HackerClubMember(name='Anna Ravenscroft', guests=[], handle='AnnaRaven') -If ``handle`` is ommitted, it's set to the first part of the member's name:: +If ``handle`` is omitted, it's set to the first part of the member's name:: >>> leo = HackerClubMember('Leo Rochael') >>> leo diff --git a/17-it-generator/aritprog_v3.py b/17-it-generator/aritprog_v3.py index 3dd8e18..914f5c9 100644 --- a/17-it-generator/aritprog_v3.py +++ b/17-it-generator/aritprog_v3.py @@ -5,7 +5,7 @@ def aritprog_gen(begin, step, end=None): first = type(begin + step)(begin) ap_gen = itertools.count(first, step) - if end is not None: - ap_gen = itertools.takewhile(lambda n: n < end, ap_gen) - return ap_gen + if end is None: + return ap_gen + return itertools.takewhile(lambda n: n < end, ap_gen) # end::ARITPROG_ITERTOOLS[] diff --git a/17-it-generator/coroaverager.py b/17-it-generator/coroaverager.py new file mode 100644 index 0000000..d976760 --- /dev/null +++ b/17-it-generator/coroaverager.py @@ -0,0 +1,43 @@ +""" +A coroutine to compute a running average + +# tag::CORO_AVERAGER_TEST[] + >>> coro_avg = averager() # <1> + >>> next(coro_avg) # <2> + 0.0 + >>> coro_avg.send(10) # <3> + 10.0 + >>> coro_avg.send(30) + 20.0 + >>> coro_avg.send(5) + 15.0 + +# end::CORO_AVERAGER_TEST[] +# tag::CORO_AVERAGER_TEST_CONT[] + + >>> coro_avg.send(20) # <1> + 16.25 + >>> coro_avg.close() # <2> + >>> coro_avg.close() # <3> + >>> coro_avg.send(5) # <4> + Traceback (most recent call last): + ... + StopIteration + +# end::CORO_AVERAGER_TEST_CONT[] + +""" + +# tag::CORO_AVERAGER[] +from collections.abc import Generator + +def averager() -> Generator[float, float, None]: # <1> + total = 0.0 + count = 0 + average = 0.0 + while True: # <2> + term = yield average # <3> + total += term + count += 1 + average = total/count +# end::CORO_AVERAGER[] diff --git a/17-it-generator/coroaverager2.py b/17-it-generator/coroaverager2.py new file mode 100644 index 0000000..3a15f5e --- /dev/null +++ b/17-it-generator/coroaverager2.py @@ -0,0 +1,96 @@ +""" +A coroutine to compute a running average. + +Testing ``averager2`` by itself:: + +# tag::RETURNING_AVERAGER_DEMO_1[] + + >>> coro_avg = averager2() + >>> next(coro_avg) + >>> coro_avg.send(10) # <1> + >>> coro_avg.send(30) + >>> coro_avg.send(6.5) + >>> coro_avg.close() # <2> + +# end::RETURNING_AVERAGER_DEMO_1[] + +Catching `StopIteration` to extract the value returned by +the coroutine:: + +# tag::RETURNING_AVERAGER_DEMO_2[] + + >>> coro_avg = averager2() + >>> next(coro_avg) + >>> coro_avg.send(10) + >>> coro_avg.send(30) + >>> coro_avg.send(6.5) + >>> try: + ... coro_avg.send(STOP) # <1> + ... except StopIteration as exc: + ... result = exc.value # <2> + ... + >>> result # <3> + Result(count=3, average=15.5) + +# end::RETURNING_AVERAGER_DEMO_2[] + +Using `yield from`: + + +# tag::RETURNING_AVERAGER_DEMO_3[] + + >>> def compute(): + ... res = yield from averager2(True) # <1> + ... print('computed:', res) # <2> + ... return res # <3> + ... + >>> comp = compute() # <4> + >>> for v in [None, 10, 20, 30, STOP]: # <5> + ... try: + ... comp.send(v) # <6> + ... except StopIteration as exc: # <7> + ... result = exc.value + received: 10 + received: 20 + received: 30 + received: + computed: Result(count=3, average=20.0) + >>> result # <8> + Result(count=3, average=20.0) + +# end::RETURNING_AVERAGER_DEMO_3[] +""" + +# tag::RETURNING_AVERAGER_TOP[] +from collections.abc import Generator +from typing import Union, NamedTuple + +class Result(NamedTuple): # <1> + count: int # type: ignore # <2> + average: float + +class Sentinel: # <3> + def __repr__(self): + return f'' + +STOP = Sentinel() # <4> + +SendType = Union[float, Sentinel] # <5> +# end::RETURNING_AVERAGER_TOP[] +# tag::RETURNING_AVERAGER[] +def averager2(verbose: bool = False) -> Generator[None, SendType, Result]: # <1> + total = 0.0 + count = 0 + average = 0.0 + while True: + term = yield # <2> + if verbose: + print('received:', term) + if isinstance(term, Sentinel): # <3> + break + total += term # <4> + count += 1 + average = total / count + return Result(count, average) # <5> + +# end::RETURNING_AVERAGER[] diff --git a/17-it-generator/fibo_gen.py b/17-it-generator/fibo_gen.py new file mode 100644 index 0000000..d7296ac --- /dev/null +++ b/17-it-generator/fibo_gen.py @@ -0,0 +1,7 @@ +from collections.abc import Iterator + +def fibonacci() -> Iterator[int]: + a, b = 0, 1 + while True: + yield a + a, b = b, a + b diff --git a/17-it-generator/sentence_gen.py b/17-it-generator/sentence_gen.py index 3dbc606..1f7ebeb 100644 --- a/17-it-generator/sentence_gen.py +++ b/17-it-generator/sentence_gen.py @@ -21,7 +21,7 @@ def __repr__(self): def __iter__(self): for word in self.words: # <1> yield word # <2> - return # <3> + # <3> # done! <4> diff --git a/18-with-match/lisplus/examples_test.py b/18-with-match/lisplus/examples_test.py deleted file mode 100644 index 38510a3..0000000 --- a/18-with-match/lisplus/examples_test.py +++ /dev/null @@ -1,109 +0,0 @@ -""" -Doctests for `parse`: - ->>> from lis import parse - -# tag::PARSE_DEMO[] ->>> parse('1.5') # <1> -1.5 ->>> parse('set!') # <2> -'set!' ->>> parse('(gcd 18 44)') # <3> -['gcd', 18, 44] ->>> parse('(- m (* n (// m n)))') # <4> -['-', 'm', ['*', 'n', ['//', 'm', 'n']]] - -# end::PARSE_DEMO[] - -""" - -import math - -from lis import run - - -fact_src = """ -(define (! n) - (if (< n 2) - 1 - (* n (! (- n 1))) - ) -) -(! 42) -""" -def test_factorial(): - got = run(fact_src) - assert got == 1405006117752879898543142606244511569936384000000000 - assert got == math.factorial(42) - - -gcd_src = """ -(define (mod m n) - (- m (* n (// m n)))) -(define (gcd m n) - (if (= n 0) - m - (gcd n (mod m n)))) -(gcd 18 45) -""" -def test_gcd(): - got = run(gcd_src) - assert got == 9 - - -quicksort_src = """ -(define (quicksort lst) - (if (null? lst) - lst - (begin - (define pivot (car lst)) - (define rest (cdr lst)) - (append - (quicksort - (filter (lambda (x) (< x pivot)) rest)) - (list pivot) - (quicksort - (filter (lambda (x) (>= x pivot)) rest))) - ) - ) -) -(quicksort (list 2 1 6 3 4 0 8 9 7 5)) -""" -def test_quicksort(): - got = run(quicksort_src) - assert got == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - - -# Example from Structure and Interpretation of Computer Programs -# https://mitpress.mit.edu/sites/default/files/sicp/full-text/sicp/book/node12.html - -newton_src = """ -(define (sqrt x) - (sqrt-iter 1.0 x)) -(define (sqrt-iter guess x) - (if (good-enough? guess x) - guess - (sqrt-iter (improve guess x) x))) -(define (good-enough? guess x) - (< (abs (- (* guess guess) x)) 0.001)) -(define (improve guess x) - (average guess (/ x guess))) -(define (average x y) - (/ (+ x y) 2)) -(sqrt 123454321) -""" -def test_newton(): - got = run(newton_src) - assert math.isclose(got, 11111) - - -closure_src = """ -(define (make-adder increment) - (lambda (x) (+ increment x)) -) -(define inc (make-adder 1)) -(inc 99) -""" -def test_newton(): - got = run(closure_src) - assert got == 100 diff --git a/18-with-match/lisplus/lis.py b/18-with-match/lisplus/lis.py deleted file mode 100644 index 7ae0a9d..0000000 --- a/18-with-match/lisplus/lis.py +++ /dev/null @@ -1,192 +0,0 @@ -################ Lispy: Scheme Interpreter in Python 3.10 - -## (c) Peter Norvig, 2010-18; See http://norvig.com/lispy.html -## Minor edits for Fluent Python, Second Edition (O'Reilly, 2021) -## by Luciano Ramalho, adding type hints and pattern matching. - -################ imports and types - -import math -import operator as op -from collections import ChainMap -from collections.abc import MutableMapping, Iterator -from itertools import chain -from typing import Any, TypeAlias - -Symbol: TypeAlias = str -Atom: TypeAlias = float | int | Symbol -Expression: TypeAlias = Atom | list - -Environment: TypeAlias = MutableMapping[Symbol, object] - - -class Procedure: - "A user-defined Scheme procedure." - - def __init__(self, parms: list[Symbol], body: list[Expression], env: Environment): - self.parms = parms - self.body = body - self.env = env - - def __call__(self, *args: Expression) -> Any: - local_env = dict(zip(self.parms, args)) - env: Environment = ChainMap(local_env, self.env) - for exp in self.body: - result = evaluate(exp, env) - return result - - -################ global environment - - -def standard_env() -> Environment: - "An environment with some Scheme standard procedures." - env: Environment = {} - env.update(vars(math)) # sin, cos, sqrt, pi, ... - env.update({ - '+': op.add, - '-': op.sub, - '*': op.mul, - '/': op.truediv, - '//': op.floordiv, - '>': op.gt, - '<': op.lt, - '>=': op.ge, - '<=': op.le, - '=': op.eq, - 'abs': abs, - 'append': lambda *args: list(chain(*args)), - 'apply': lambda proc, args: proc(*args), - 'begin': lambda *x: x[-1], - 'car': lambda x: x[0], - 'cdr': lambda x: x[1:], - 'cons': lambda x, y: [x] + y, - 'eq?': op.is_, - 'equal?': op.eq, - 'filter': lambda *args: list(filter(*args)), - 'length': len, - 'list': lambda *x: list(x), - 'list?': lambda x: isinstance(x, list), - 'map': lambda *args: list(map(*args)), - 'max': max, - 'min': min, - 'not': op.not_, - 'null?': lambda x: x == [], - 'number?': lambda x: isinstance(x, (int, float)), - 'procedure?': callable, - 'round': round, - 'symbol?': lambda x: isinstance(x, Symbol), - }) - return env - - -################ parse, tokenize, and read_from_tokens - - -def parse(program: str) -> Expression: - "Read a Scheme expression from a string." - return read_from_tokens(tokenize(program)) - - -def tokenize(s: str) -> list[str]: - "Convert a string into a list of tokens." - return s.replace('(', ' ( ').replace(')', ' ) ').split() - - -def read_from_tokens(tokens: list[str]) -> Expression: - "Read an expression from a sequence of tokens." - if len(tokens) == 0: - raise SyntaxError('unexpected EOF while reading') - token = tokens.pop(0) - if '(' == token: - exp = [] - while tokens[0] != ')': - exp.append(read_from_tokens(tokens)) - tokens.pop(0) # discard ')' - return exp - elif ')' == token: - raise SyntaxError('unexpected )') - else: - return parse_atom(token) - - -def parse_atom(token: str) -> Atom: - "Numbers become numbers; every other token is a symbol." - try: - return int(token) - except ValueError: - try: - return float(token) - except ValueError: - return Symbol(token) - - -################ interaction: a REPL - - -def repl(prompt: str = 'lis.py> ') -> None: - "A prompt-read-evaluate-print loop." - global_env: Environment = standard_env() - while True: - val = evaluate(parse(input(prompt)), global_env) - if val is not None: - print(lispstr(val)) - - -def lispstr(exp: object) -> str: - "Convert a Python object back into a Lisp-readable string." - if isinstance(exp, list): - return '(' + ' '.join(map(lispstr, exp)) + ')' - else: - return str(exp) - - -################ eval - -# tag::EVALUATE[] -def evaluate(exp: Expression, env: Environment) -> Any: - "Evaluate an expression in an environment." - match exp: - case int(x) | float(x): - return x - case Symbol(var): - return env[var] - case []: - return [] - case ['quote', exp]: - return exp - case ['if', test, consequence, alternative]: - if evaluate(test, env): - return evaluate(consequence, env) - else: - return evaluate(alternative, env) - case ['define', Symbol(var), value_exp]: - env[var] = evaluate(value_exp, env) - case ['define', [Symbol(name), *parms], *body]: - env[name] = Procedure(parms, body, env) - case ['lambda', [*parms], *body]: - return Procedure(parms, body, env) - case [op, *args]: - proc = evaluate(op, env) - values = [evaluate(arg, env) for arg in args] - return proc(*values) - case _: - raise SyntaxError(repr(exp)) -# end::EVALUATE[] - - -################ non-interactive execution - - -def run_lines(source: str) -> Iterator[Any]: - global_env: Environment = standard_env() - tokens = tokenize(source) - while tokens: - exp = read_from_tokens(tokens) - yield evaluate(exp, global_env) - - -def run(source: str) -> Any: - for result in run_lines(source): - pass - return result diff --git a/18-with-match/lisplus/lis_test.py b/18-with-match/lisplus/lis_test.py deleted file mode 100644 index 3688888..0000000 --- a/18-with-match/lisplus/lis_test.py +++ /dev/null @@ -1,182 +0,0 @@ -from typing import Optional - -from pytest import mark, fixture - -from lis import parse, evaluate, Expression, Environment, standard_env - -############################################################# tests for parse - -@mark.parametrize( 'source, expected', [ - ('7', 7), - ('x', 'x'), - ('(sum 1 2 3)', ['sum', 1, 2, 3]), - ('(+ (* 2 100) (* 1 10))', ['+', ['*', 2, 100], ['*', 1, 10]]), - ('99 100', 99), # parse stops at the first complete expression - ('(a)(b)', ['a']), -]) -def test_parse(source: str, expected: Expression) -> None: - got = parse(source) - assert got == expected - - -########################################################## tests for evaluate - -# Norvig's tests are not isolated: they assume the -# same environment from first to last test. -global_env_for_first_test = standard_env() - -@mark.parametrize( 'source, expected', [ - ("(quote (testing 1 (2.0) -3.14e159))", ['testing', 1, [2.0], -3.14e159]), - ("(+ 2 2)", 4), - ("(+ (* 2 100) (* 1 10))", 210), - ("(if (> 6 5) (+ 1 1) (+ 2 2))", 2), - ("(if (< 6 5) (+ 1 1) (+ 2 2))", 4), - ("(define x 3)", None), - ("x", 3), - ("(+ x x)", 6), - ("((lambda (x) (+ x x)) 5)", 10), - ("(define twice (lambda (x) (* 2 x)))", None), - ("(twice 5)", 10), - ("(define compose (lambda (f g) (lambda (x) (f (g x)))))", None), - ("((compose list twice) 5)", [10]), - ("(define repeat (lambda (f) (compose f f)))", None), - ("((repeat twice) 5)", 20), - ("((repeat (repeat twice)) 5)", 80), - ("(define fact (lambda (n) (if (<= n 1) 1 (* n (fact (- n 1))))))", None), - ("(fact 3)", 6), - ("(fact 50)", 30414093201713378043612608166064768844377641568960512000000000000), - ("(define abs (lambda (n) ((if (> n 0) + -) 0 n)))", None), - ("(list (abs -3) (abs 0) (abs 3))", [3, 0, 3]), - ("""(define combine (lambda (f) - (lambda (x y) - (if (null? x) (quote ()) - (f (list (car x) (car y)) - ((combine f) (cdr x) (cdr y)))))))""", None), - ("(define zip (combine cons))", None), - ("(zip (list 1 2 3 4) (list 5 6 7 8))", [[1, 5], [2, 6], [3, 7], [4, 8]]), - ("""(define riff-shuffle (lambda (deck) - (begin - (define take (lambda (n seq) (if (<= n 0) (quote ()) (cons (car seq) (take (- n 1) (cdr seq)))))) - (define drop (lambda (n seq) (if (<= n 0) seq (drop (- n 1) (cdr seq))))) - (define mid (lambda (seq) (/ (length seq) 2))) - ((combine append) (take (mid deck) deck) (drop (mid deck) deck)))))""", None), - ("(riff-shuffle (list 1 2 3 4 5 6 7 8))", [1, 5, 2, 6, 3, 7, 4, 8]), - ("((repeat riff-shuffle) (list 1 2 3 4 5 6 7 8))", [1, 3, 5, 7, 2, 4, 6, 8]), - ("(riff-shuffle (riff-shuffle (riff-shuffle (list 1 2 3 4 5 6 7 8))))", [1,2,3,4,5,6,7,8]), -]) -def test_evaluate(source: str, expected: Optional[Expression]) -> None: - got = evaluate(parse(source), global_env_for_first_test) - assert got == expected - - -@fixture -def std_env() -> Environment: - return standard_env() - -# tests for each of the cases in evaluate - -def test_evaluate_variable() -> None: - env: Environment = dict(x=10) - source = 'x' - expected = 10 - got = evaluate(parse(source), env) - assert got == expected - - -def test_evaluate_literal(std_env: Environment) -> None: - source = '3.3' - expected = 3.3 - got = evaluate(parse(source), std_env) - assert got == expected - - -def test_evaluate_quote(std_env: Environment) -> None: - source = '(quote (1.1 is not 1))' - expected = [1.1, 'is', 'not', 1] - got = evaluate(parse(source), std_env) - assert got == expected - - -def test_evaluate_if_true(std_env: Environment) -> None: - source = '(if 1 10 no-such-thing)' - expected = 10 - got = evaluate(parse(source), std_env) - assert got == expected - - -def test_evaluate_if_false(std_env: Environment) -> None: - source = '(if 0 no-such-thing 20)' - expected = 20 - got = evaluate(parse(source), std_env) - assert got == expected - - -def test_define(std_env: Environment) -> None: - source = '(define answer (* 6 7))' - got = evaluate(parse(source), std_env) - assert got is None - assert std_env['answer'] == 42 - - -def test_lambda(std_env: Environment) -> None: - source = '(lambda (a b) (if (>= a b) a b))' - func = evaluate(parse(source), std_env) - assert func.parms == ['a', 'b'] - assert func.body == [['if', ['>=', 'a', 'b'], 'a', 'b']] - assert func.env is std_env - assert func(1, 2) == 2 - assert func(3, 2) == 3 - - -def test_begin(std_env: Environment) -> None: - source = """ - (begin - (define x (* 2 3)) - (* x 7) - ) - """ - got = evaluate(parse(source), std_env) - assert got == 42 - - -def test_invocation_builtin_car(std_env: Environment) -> None: - source = '(car (quote (11 22 33)))' - got = evaluate(parse(source), std_env) - assert got == 11 - - -def test_invocation_builtin_append(std_env: Environment) -> None: - source = '(append (quote (a b)) (quote (c d)))' - got = evaluate(parse(source), std_env) - assert got == ['a', 'b', 'c', 'd'] - - -def test_invocation_builtin_map(std_env: Environment) -> None: - source = '(map (lambda (x) (* x 2)) (quote (1 2 3))))' - got = evaluate(parse(source), std_env) - assert got == [2, 4, 6] - - -def test_invocation_user_procedure(std_env: Environment) -> None: - source = """ - (begin - (define max (lambda (a b) (if (>= a b) a b))) - (max 22 11) - ) - """ - got = evaluate(parse(source), std_env) - assert got == 22 - - -###################################### for py3.10/lis.py only - -def test_define_function(std_env: Environment) -> None: - source = '(define (max a b) (if (>= a b) a b))' - got = evaluate(parse(source), std_env) - assert got is None - max_fn = std_env['max'] - assert max_fn.parms == ['a', 'b'] - assert max_fn.body == [['if', ['>=', 'a', 'b'], 'a', 'b']] - assert max_fn.env is std_env - assert max_fn(1, 2) == 2 - assert max_fn(3, 2) == 3 diff --git a/18-with-match/lisplus/meta_test.py b/18-with-match/lisplus/meta_test.py deleted file mode 100644 index cb3d062..0000000 --- a/18-with-match/lisplus/meta_test.py +++ /dev/null @@ -1,64 +0,0 @@ -import operator as op - -from lis import run - -env_scm = """ -(define standard-env (list - (list (quote +) +) - (list (quote -) -) -)) -standard-env -""" - -def test_env_build(): - got = run(env_scm) - assert got == [['+', op.add], ['-', op.sub]] - -scan_scm = """ -(define l (quote (a b c))) -(define (scan what where) - (if (null? where) - () - (if (eq? what (car where)) - what - (scan what (cdr where)))) -) -""" - -def test_scan(): - source = scan_scm + '(scan (quote a) l )' - got = run(source) - assert got == 'a' - - -def test_scan_not_found(): - source = scan_scm + '(scan (quote z) l )' - got = run(source) - assert got == [] - - -lookup_scm = """ -(define env (list - (list (quote +) +) - (list (quote -) -) -)) -(define (lookup what where) - (if (null? where) - () - (if (eq? what (car (car where))) - (car (cdr (car where))) - (lookup what (cdr where)))) -) -""" - -def test_lookup(): - source = lookup_scm + '(lookup (quote +) env)' - got = run(source) - assert got == op.add - - -def test_lookup_not_found(): - source = lookup_scm + '(lookup (quote z) env )' - got = run(source) - assert got == [] - diff --git a/02-array-seq/lispy/LICENSE b/18-with-match/lispy/LICENSE similarity index 100% rename from 02-array-seq/lispy/LICENSE rename to 18-with-match/lispy/LICENSE diff --git a/02-array-seq/lispy/README.md b/18-with-match/lispy/README.md similarity index 100% rename from 02-array-seq/lispy/README.md rename to 18-with-match/lispy/README.md diff --git a/02-array-seq/lispy/original/LICENSE b/18-with-match/lispy/original/LICENSE similarity index 100% rename from 02-array-seq/lispy/original/LICENSE rename to 18-with-match/lispy/original/LICENSE diff --git a/02-array-seq/lispy/original/README.md b/18-with-match/lispy/original/README.md similarity index 100% rename from 02-array-seq/lispy/original/README.md rename to 18-with-match/lispy/original/README.md diff --git a/02-array-seq/lispy/original/lis.py b/18-with-match/lispy/original/lis.py similarity index 100% rename from 02-array-seq/lispy/original/lis.py rename to 18-with-match/lispy/original/lis.py diff --git a/02-array-seq/lispy/original/lispy.py b/18-with-match/lispy/original/lispy.py similarity index 100% rename from 02-array-seq/lispy/original/lispy.py rename to 18-with-match/lispy/original/lispy.py diff --git a/02-array-seq/lispy/original/lispytest.py b/18-with-match/lispy/original/lispytest.py similarity index 100% rename from 02-array-seq/lispy/original/lispytest.py rename to 18-with-match/lispy/original/lispytest.py diff --git a/18-with-match/lispy/py3.10/examples_test.py b/18-with-match/lispy/py3.10/examples_test.py new file mode 100644 index 0000000..ed4b68a --- /dev/null +++ b/18-with-match/lispy/py3.10/examples_test.py @@ -0,0 +1,259 @@ +""" +Doctests for `parse` +-------------------- + +# tag::PARSE_ATOM[] +>>> from lis import parse +>>> parse('1.5') +1.5 +>>> parse('ni!') +'ni!' + +# end::PARSE_ATOM[] + +# tag::PARSE_LIST[] +>>> parse('(gcd 18 45)') +['gcd', 18, 45] +>>> parse(''' +... (define double +... (lambda (n) +... (* n 2))) +... ''') +['define', 'double', ['lambda', ['n'], ['*', 'n', 2]]] + +# end::PARSE_LIST[] + +Doctest for `Environment` +------------------------- + +# tag::ENVIRONMENT[] +>>> from lis import Environment +>>> outer_env = {'a': 0, 'b': 1} +>>> inner_env = {'a': 2} +>>> env = Environment(inner_env, outer_env) +>>> env['a'] = 111 # <1> +>>> env['c'] = 222 +>>> env +Environment({'a': 111, 'c': 222}, {'a': 0, 'b': 1}) +>>> env.change('b', 333) # <2> +>>> env +Environment({'a': 111, 'c': 222}, {'a': 0, 'b': 333}) + +# end::ENVIRONMENT[] + +Doctests for `evaluate` +----------------------- + +# tag::EVAL_NUMBER[] +>>> from lis import parse, evaluate, standard_env +>>> evaluate(parse('1.5'), {}) +1.5 + +# end::EVAL_NUMBER[] + +# tag::EVAL_SYMBOL[] +>>> from lis import standard_env +>>> evaluate(parse('+'), standard_env()) + +>>> evaluate(parse('ni!'), standard_env()) +Traceback (most recent call last): + ... +KeyError: 'ni!' + +# end::EVAL_SYMBOL[] + + +# tag::EVAL_QUOTE[] +>>> evaluate(parse('(quote no-such-name)'), {}) +'no-such-name' +>>> evaluate(parse('(quote (99 bottles of beer))'), {}) +[99, 'bottles', 'of', 'beer'] +>>> evaluate(parse('(quote (/ 10 0))'), {}) +['/', 10, 0] + +# end::EVAL_QUOTE[] + +# tag::EVAL_IF[] +>>> evaluate(parse('(if (= 3 3) 1 0))'), standard_env()) +1 +>>> evaluate(parse('(if (= 3 4) 1 0))'), standard_env()) +0 + +# end::EVAL_IF[] + + +# tag::EVAL_LAMBDA[] +>>> expr = '(lambda (a b) (* (/ a b) 100))' +>>> f = evaluate(parse(expr), standard_env()) +>>> f # doctest: +ELLIPSIS + +>>> f(15, 20) +75.0 + +# end::EVAL_LAMBDA[] + +# tag::EVAL_DEFINE[] +>>> global_env = standard_env() +>>> evaluate(parse('(define answer (* 7 6))'), global_env) +>>> global_env['answer'] +42 + +# end::EVAL_DEFINE[] + +# tag::EVAL_DEFUN[] +>>> global_env = standard_env() +>>> percent = '(define (% a b) (* (/ a b) 100))' +>>> evaluate(parse(percent), global_env) +>>> global_env['%'] # doctest: +ELLIPSIS + +>>> global_env['%'](170, 200) +85.0 + +# end::EVAL_DEFUN[] + +function call: + +# tag::EVAL_CALL[] +>>> evaluate(parse('(% (* 12 14) (- 500 100))'), global_env) +42.0 + +# end::EVAL_CALL[] + +# tag::EVAL_SYNTAX_ERROR[] +>>> evaluate(parse('(lambda is not like this)'), standard_env()) +Traceback (most recent call last): + ... +SyntaxError: (lambda is not like this) + +# end::EVAL_SYNTAX_ERROR[] + +""" + +import math + +from lis import run + + +fact_src = """ +(define (! n) + (if (< n 2) + 1 + (* n (! (- n 1))) + ) +) +(! 42) +""" +def test_factorial(): + got = run(fact_src) + assert got == 1405006117752879898543142606244511569936384000000000 + assert got == math.factorial(42) + + +gcd_src = """ +(define (mod m n) + (- m (* n (// m n)))) +(define (gcd m n) + (if (= n 0) + m + (gcd n (mod m n)))) +(gcd 18 45) +""" +def test_gcd(): + got = run(gcd_src) + assert got == 9 + + +quicksort_src = """ +(define (quicksort lst) + (if (null? lst) + lst + (begin + (define pivot (car lst)) + (define rest (cdr lst)) + (append + (quicksort + (filter (lambda (x) (< x pivot)) rest)) + (list pivot) + (quicksort + (filter (lambda (x) (>= x pivot)) rest))) + ) + ) +) +(quicksort (list 2 1 6 3 4 0 8 9 7 5)) +""" +def test_quicksort(): + got = run(quicksort_src) + assert got == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + + +# Example from Structure and Interpretation of Computer Programs +# https://mitpress.mit.edu/sites/default/files/sicp/full-text/sicp/book/node12.html + +newton_src = """ +(define (sqrt x) + (sqrt-iter 1.0 x)) +(define (sqrt-iter guess x) + (if (good-enough? guess x) + guess + (sqrt-iter (improve guess x) x))) +(define (good-enough? guess x) + (< (abs (- (* guess guess) x)) 0.001)) +(define (improve guess x) + (average guess (/ x guess))) +(define (average x y) + (/ (+ x y) 2)) +(sqrt 123454321) +""" +def test_newton(): + got = run(newton_src) + assert math.isclose(got, 11111) + + +closure_src = """ +(define (make-adder increment) + (lambda (x) (+ increment x)) +) +(define inc (make-adder 1)) +(inc 99) +""" +def test_newton(): + got = run(closure_src) + assert got == 100 + +closure_with_change_src = """ +(define (make-counter) + (define n 0) + (lambda () + (set! n (+ n 1)) + n) +) +(define counter (make-counter)) +(counter) +(counter) +(counter) +""" +def test_closure_with_change(): + got = run(closure_with_change_src) + assert got == 3 + + +# tag::RUN_AVERAGER[] +closure_averager_src = """ +(define (make-averager) + (define count 0) + (define total 0) + (lambda (new-value) + (set! count (+ count 1)) + (set! total (+ total new-value)) + (/ total count) + ) +) +(define avg (make-averager)) +(avg 10) +(avg 11) +(avg 15) +""" +def test_closure_averager(): + got = run(closure_averager_src) + assert got == 12.0 +# end::RUN_AVERAGER[] \ No newline at end of file diff --git a/02-array-seq/lispy/py3.10/lis.py b/18-with-match/lispy/py3.10/lis.py old mode 100644 new mode 100755 similarity index 70% rename from 02-array-seq/lispy/py3.10/lis.py rename to 18-with-match/lispy/py3.10/lis.py index 035481f..4a5195c --- a/02-array-seq/lispy/py3.10/lis.py +++ b/18-with-match/lispy/py3.10/lis.py @@ -1,46 +1,82 @@ +#!/usr/bin/env python + ################ Lispy: Scheme Interpreter in Python 3.10 ## (c) Peter Norvig, 2010-18; See http://norvig.com/lispy.html ## Minor edits for Fluent Python, Second Edition (O'Reilly, 2021) ## by Luciano Ramalho, adding type hints and pattern matching. + ################ Imports and Types +# tag::IMPORTS[] import math import operator as op from collections import ChainMap -from collections.abc import MutableMapping, Iterator from itertools import chain -from typing import Any, TypeAlias +from typing import Any, TypeAlias, NoReturn Symbol: TypeAlias = str Atom: TypeAlias = float | int | Symbol Expression: TypeAlias = Atom | list +# end::IMPORTS[] -Environment: TypeAlias = MutableMapping[Symbol, object] +################ Parsing: parse, tokenize, and read_from_tokens -class Procedure: - "A user-defined Scheme procedure." +def parse(program: str) -> Expression: + "Read a Scheme expression from a string." + return read_from_tokens(tokenize(program)) - def __init__(self, parms: list[Symbol], body: list[Expression], env: Environment): - self.parms = parms - self.body = body - self.env = env +def tokenize(s: str) -> list[str]: + "Convert a string into a list of tokens." + return s.replace('(', ' ( ').replace(')', ' ) ').split() - def __call__(self, *args: Expression) -> Any: - local_env = dict(zip(self.parms, args)) - env: Environment = ChainMap(local_env, self.env) - for exp in self.body: - result = evaluate(exp, env) - return result +def read_from_tokens(tokens: list[str]) -> Expression: + "Read an expression from a sequence of tokens." + if len(tokens) == 0: + raise SyntaxError('unexpected EOF while reading') + token = tokens.pop(0) + if '(' == token: + exp = [] + while tokens[0] != ')': + exp.append(read_from_tokens(tokens)) + tokens.pop(0) # discard ')' + return exp + elif ')' == token: + raise SyntaxError('unexpected )') + else: + return parse_atom(token) +def parse_atom(token: str) -> Atom: + "Numbers become numbers; every other token is a symbol." + try: + return int(token) + except ValueError: + try: + return float(token) + except ValueError: + return Symbol(token) ################ Global Environment +# tag::ENV_CLASS[] +class Environment(ChainMap): + "A ChainMap that allows changing an item in-place." + + def change(self, key: Symbol, value: object) -> None: + "Find where key is defined and change the value there." + for map in self.maps: + if key in map: + map[key] = value + return + raise KeyError(key) +# end::ENV_CLASS[] + + def standard_env() -> Environment: "An environment with some Scheme standard procedures." - env: Environment = {} + env = Environment() env.update(vars(math)) # sin, cos, sqrt, pi, ... env.update({ '+': op.add, @@ -60,6 +96,7 @@ def standard_env() -> Environment: 'car': lambda x: x[0], 'cdr': lambda x: x[1:], 'cons': lambda x, y: [x] + y, + 'display': lambda x: print(lispstr(x)), 'eq?': op.is_, 'equal?': op.eq, 'filter': lambda *args: list(filter(*args)), @@ -78,68 +115,33 @@ def standard_env() -> Environment: }) return env -################ Parsing: parse, tokenize, and read_from_tokens - -def parse(program: str) -> Expression: - "Read a Scheme expression from a string." - return read_from_tokens(tokenize(program)) - - -def tokenize(s: str) -> list[str]: - "Convert a string into a list of tokens." - return s.replace('(', ' ( ').replace(')', ' ) ').split() - - -def read_from_tokens(tokens: list[str]) -> Expression: - "Read an expression from a sequence of tokens." - if len(tokens) == 0: - raise SyntaxError('unexpected EOF while reading') - token = tokens.pop(0) - if '(' == token: - exp = [] - while tokens[0] != ')': - exp.append(read_from_tokens(tokens)) - tokens.pop(0) # discard ')' - return exp - elif ')' == token: - raise SyntaxError('unexpected )') - else: - return parse_atom(token) - - -def parse_atom(token: str) -> Atom: - "Numbers become numbers; every other token is a symbol." - try: - return int(token) - except ValueError: - try: - return float(token) - except ValueError: - return Symbol(token) - ################ Interaction: A REPL -def repl(prompt: str = 'lis.py> ') -> None: - "A prompt-read-evaluate-print loop." +# tag::REPL[] +def repl() -> NoReturn: + "A prompt-read-eval-print loop." global_env = standard_env() while True: - val = evaluate(parse(input(prompt)), global_env) + ast = parse(input('lis.py> ')) + val = evaluate(ast, global_env) if val is not None: print(lispstr(val)) - def lispstr(exp: object) -> str: "Convert a Python object back into a Lisp-readable string." if isinstance(exp, list): return '(' + ' '.join(map(lispstr, exp)) + ')' else: return str(exp) +# end::REPL[] -################ eval +################ Evaluator # tag::EVALUATE[] +KEYWORDS = ['quote', 'if', 'lambda', 'define', 'set!'] + def evaluate(exp: Expression, env: Environment) -> Any: "Evaluate an expression in an environment." match exp: @@ -149,40 +151,66 @@ def evaluate(exp: Expression, env: Environment) -> Any: return env[var] case []: return [] - case ['quote', exp]: - return exp + case ['quote', x]: + return x case ['if', test, consequence, alternative]: if evaluate(test, env): return evaluate(consequence, env) else: return evaluate(alternative, env) + case ['lambda', [*parms], *body] if body: + return Procedure(parms, body, env) case ['define', Symbol(var), value_exp]: env[var] = evaluate(value_exp, env) - case ['define', [Symbol(name), *parms], *body]: + case ['define', [Symbol(name), *parms], *body] if body: env[name] = Procedure(parms, body, env) - case ['lambda', [*parms], *body]: - return Procedure(parms, body, env) - case [op, *args]: + case ['set!', Symbol(var), value_exp]: + env.change(var, evaluate(value_exp, env)) + case [op, *args] if op not in KEYWORDS: proc = evaluate(op, env) values = [evaluate(arg, env) for arg in args] return proc(*values) case _: - raise SyntaxError(repr(exp)) + raise SyntaxError(lispstr(exp)) # end::EVALUATE[] +# tag::PROCEDURE[] +class Procedure: + "A user-defined Scheme procedure." + + def __init__( # <1> + self, parms: list[Symbol], body: list[Expression], env: Environment + ): + self.parms = parms # <2> + self.body = body + self.env = env + + def __call__(self, *args: Expression) -> Any: # <3> + local_env = dict(zip(self.parms, args)) # <4> + env = Environment(local_env, self.env) # <5> + for exp in self.body: # <6> + result = evaluate(exp, env) + return result # <7> +# end::PROCEDURE[] -################ non-interactive execution +################ command-line interface -def run_lines(source: str) -> Iterator[Any]: - global_env: Environment = standard_env() +def run(source: str) -> Any: + global_env = standard_env() tokens = tokenize(source) while tokens: exp = read_from_tokens(tokens) - yield evaluate(exp, global_env) + result = evaluate(exp, global_env) + return result +def main(args: list[str]) -> None: + if len(args) == 1: + with open(args[0]) as fp: + run(fp.read()) + else: + repl() -def run(source: str) -> Any: - for result in run_lines(source): - pass - return result +if __name__ == '__main__': + import sys + main(sys.argv[1:]) diff --git a/02-array-seq/lispy/py3.10/lis_test.py b/18-with-match/lispy/py3.10/lis_test.py similarity index 100% rename from 02-array-seq/lispy/py3.10/lis_test.py rename to 18-with-match/lispy/py3.10/lis_test.py diff --git a/18-with-match/lispy/py3.10/quicksort.scm b/18-with-match/lispy/py3.10/quicksort.scm new file mode 100644 index 0000000..08dd596 --- /dev/null +++ b/18-with-match/lispy/py3.10/quicksort.scm @@ -0,0 +1,17 @@ +(define (quicksort lst) + (if (null? lst) + lst + (begin + (define pivot (car lst)) + (define rest (cdr lst)) + (append + (quicksort + (filter (lambda (x) (< x pivot)) rest)) + (list pivot) + (quicksort + (filter (lambda (x) (>= x pivot)) rest))) + ) + ) +) +(display + (quicksort (list 2 1 6 3 4 0 8 9 7 5))) diff --git a/02-array-seq/lispy/py3.9/README.md b/18-with-match/lispy/py3.9/README.md similarity index 100% rename from 02-array-seq/lispy/py3.9/README.md rename to 18-with-match/lispy/py3.9/README.md diff --git a/02-array-seq/lispy/py3.9/lis.py b/18-with-match/lispy/py3.9/lis.py similarity index 91% rename from 02-array-seq/lispy/py3.9/lis.py rename to 18-with-match/lispy/py3.9/lis.py index 11f4402..9e4dec1 100644 --- a/02-array-seq/lispy/py3.9/lis.py +++ b/18-with-match/lispy/py3.9/lis.py @@ -140,16 +140,18 @@ def evaluate(x: Expression, env: Environment) -> Any: (_, exp) = x return exp elif x[0] == 'if': # (if test conseq alt) - (_, test, conseq, alt) = x - exp = (conseq if evaluate(test, env) else alt) - return evaluate(exp, env) - elif x[0] == 'define': # (define var exp) - (_, var, exp) = x - env[var] = evaluate(exp, env) - elif x[0] == 'lambda': # (lambda (var...) body) + (_, test, consequence, alternative) = x + if evaluate(test, env): + return evaluate(consequence, env) + else: + return evaluate(alternative, env) + elif x[0] == 'define': # (define name exp) + (_, name, exp) = x + env[name] = evaluate(exp, env) + elif x[0] == 'lambda': # (lambda (parm…) body) (_, parms, *body) = x return Procedure(parms, body, env) - else: # (proc arg...) + else: # (proc arg…) proc = evaluate(x[0], env) args = [evaluate(exp, env) for exp in x[1:]] return proc(*args) diff --git a/02-array-seq/lispy/py3.9/lis_test.py b/18-with-match/lispy/py3.9/lis_test.py similarity index 100% rename from 02-array-seq/lispy/py3.9/lis_test.py rename to 18-with-match/lispy/py3.9/lis_test.py diff --git a/18-with-match/mirror.py b/18-with-match/mirror.py index ba31944..841c6ab 100644 --- a/18-with-match/mirror.py +++ b/18-with-match/mirror.py @@ -11,11 +11,11 @@ ... print('Alice, Kitty and Snowdrop') # <2> ... print(what) ... - pordwonS dna yttiK ,ecilA # <3> + pordwonS dna yttiK ,ecilA YKCOWREBBAJ - >>> what # <4> + >>> what # <3> 'JABBERWOCKY' - >>> print('Back to normal.') # <5> + >>> print('Back to normal.') # <4> Back to normal. # end::MIRROR_DEMO_1[] @@ -27,15 +27,15 @@ >>> from mirror import LookingGlass >>> manager = LookingGlass() # <1> - >>> manager - + >>> manager # doctest: +ELLIPSIS + >>> monster = manager.__enter__() # <2> >>> monster == 'JABBERWOCKY' # <3> eurT >>> monster 'YKCOWREBBAJ' - >>> manager - >ca875a2x0 ta tcejbo ssalGgnikooL.rorrim< + >>> manager # doctest: +ELLIPSIS + >... ta tcejbo ssalGgnikooL.rorrim< >>> manager.__exit__(None, None, None) # <4> >>> monster 'JABBERWOCKY' @@ -69,10 +69,11 @@ # tag::MIRROR_EX[] +import sys + class LookingGlass: def __enter__(self): # <1> - import sys self.original_write = sys.stdout.write # <2> sys.stdout.write = self.reverse_write # <3> return 'JABBERWOCKY' # <4> @@ -81,12 +82,9 @@ def reverse_write(self, text): # <5> self.original_write(text[::-1]) def __exit__(self, exc_type, exc_value, traceback): # <6> - import sys # <7> - sys.stdout.write = self.original_write # <8> - if exc_type is ZeroDivisionError: # <9> + sys.stdout.write = self.original_write # <7> + if exc_type is ZeroDivisionError: # <8> print('Please DO NOT divide by zero!') - return True # <10> - # <11> - - + return True # <9> + # <10> # end::MIRROR_EX[] diff --git a/18-with-match/mirror_gen.py b/18-with-match/mirror_gen.py index 457955a..6dfaf02 100644 --- a/18-with-match/mirror_gen.py +++ b/18-with-match/mirror_gen.py @@ -35,22 +35,36 @@ >>> manager # doctest: +ELLIPSIS >...x0 ta tcejbo reganaMtxetnoCrotareneG_.biltxetnoc< >>> manager.__exit__(None, None, None) # <4> + False >>> monster 'JABBERWOCKY' # end::MIRROR_GEN_DEMO_2[] +The decorated generator also works as a decorator: + + +# tag::MIRROR_GEN_DECO[] + >>> @looking_glass() + ... def verse(): + ... print('The time has come') + ... + >>> verse() # <1> + emoc sah emit ehT + >>> print('back to normal') # <2> + back to normal + +# end::MIRROR_GEN_DECO[] + """ # tag::MIRROR_GEN_EX[] - import contextlib - +import sys @contextlib.contextmanager # <1> def looking_glass(): - import sys original_write = sys.stdout.write # <2> def reverse_write(text): # <3> @@ -59,6 +73,4 @@ def reverse_write(text): # <3> sys.stdout.write = reverse_write # <4> yield 'JABBERWOCKY' # <5> sys.stdout.write = original_write # <6> - - # end::MIRROR_GEN_EX[] diff --git a/18-with-match/mirror_gen_exc.py b/18-with-match/mirror_gen_exc.py index c446918..0c20a3b 100644 --- a/18-with-match/mirror_gen_exc.py +++ b/18-with-match/mirror_gen_exc.py @@ -35,6 +35,7 @@ >>> manager # doctest: +ELLIPSIS >...x0 ta tcejbo reganaMtxetnoCrotareneG_.biltxetnoc< >>> manager.__exit__(None, None, None) # <4> + False >>> monster 'JABBERWOCKY' @@ -48,7 +49,7 @@ # tag::MIRROR_GEN_DEMO_3[] - >>> from mirror_gen import looking_glass + >>> from mirror_gen_exc import looking_glass >>> with looking_glass(): ... print('Humpty Dumpty') ... x = 1/0 # <1> @@ -74,13 +75,11 @@ # tag::MIRROR_GEN_EXC[] - import contextlib - +import sys @contextlib.contextmanager def looking_glass(): - import sys original_write = sys.stdout.write def reverse_write(text): @@ -96,6 +95,4 @@ def reverse_write(text): sys.stdout.write = original_write # <3> if msg: print(msg) # <4> - - # end::MIRROR_GEN_EXC[] diff --git a/20-futures/getflags/flags2_asyncio.py b/20-futures/getflags/flags2_asyncio.py index e7a73ac..88a18ed 100755 --- a/20-futures/getflags/flags2_asyncio.py +++ b/20-futures/getflags/flags2_asyncio.py @@ -36,10 +36,10 @@ async def get_flag(session: aiohttp.ClientSession, # <2> resp.raise_for_status() # <3> return bytes() -async def download_one(session: aiohttp.ClientSession, # <4> +async def download_one(session: aiohttp.ClientSession, cc: str, base_url: str, - semaphore: asyncio.Semaphore, + semaphore: asyncio.Semaphore, # <4> verbose: bool) -> Result: try: async with semaphore: # <5> diff --git a/20-futures/getflags/flags3_asyncio.py b/20-futures/getflags/flags3_asyncio.py index 37b5957..04a01e2 100755 --- a/20-futures/getflags/flags3_asyncio.py +++ b/20-futures/getflags/flags3_asyncio.py @@ -36,9 +36,9 @@ async def get_flag(session: aiohttp.ClientSession, return bytes() # tag::FLAGS3_ASYNCIO_GET_COUNTRY[] -async def get_country(session: aiohttp.ClientSession, # <1> +async def get_country(session: aiohttp.ClientSession, base_url: str, - cc: str) -> str: + cc: str) -> str: # <1> url = f'{base_url}/{cc}/metadata.json' async with session.get(url) as resp: if resp.status == 200: diff --git a/20-futures/getflags/requirements.txt b/20-futures/getflags/requirements.txt index 793679b..37baa8d 100644 --- a/20-futures/getflags/requirements.txt +++ b/20-futures/getflags/requirements.txt @@ -1,11 +1,13 @@ -aiohttp==3.7.4 +aiohttp==3.7.4.post0 async-timeout==3.0.1 -attrs==20.3.0 -certifi==2020.12.5 +attrs==21.2.0 +certifi==2021.5.30 chardet==4.0.0 -idna==2.10 -requests==2.25.1 -urllib3==1.26.5 -tqdm==4.56.2 +charset-normalizer==2.0.4 +idna==3.2 multidict==5.1.0 +requests==2.26.0 +tqdm==4.62.2 +typing-extensions==3.10.0.2 +urllib3==1.26.6 yarl==1.6.3 diff --git a/20-futures/getflags/slow_server.py b/20-futures/getflags/slow_server.py index 9d8142b..bede010 100755 --- a/20-futures/getflags/slow_server.py +++ b/20-futures/getflags/slow_server.py @@ -38,6 +38,7 @@ def do_GET(self): """Serve a GET request.""" time.sleep(.5) if random() < self.error_rate: + # HTTPStatus.IM_A_TEAPOT requires Python >= 3.9 self.send_error(HTTPStatus.IM_A_TEAPOT, "I'm a Teapot") else: f = self.send_head() diff --git a/22-dyn-attr-prop/oscon/demo_schedule2.py b/22-dyn-attr-prop/oscon/demo_schedule2.py deleted file mode 100755 index 12fd440..0000000 --- a/22-dyn-attr-prop/oscon/demo_schedule2.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env python3 - -import shelve - -from schedule_v2 import DB_NAME, CONFERENCE, load_db -from schedule_v2 import DbRecord, Event - -with shelve.open(DB_NAME) as db: - if CONFERENCE not in db: - load_db(db) - - DbRecord.set_db(db) - event = DbRecord.fetch('event.33950') - print(event) - print(event.venue) - print(event.venue.name) - for spkr in event.speakers: - print(f'{spkr.serial}:', spkr.name) - - print(repr(Event.venue)) - - event2 = DbRecord.fetch('event.33451') - print(event2) - print(event2.fetch) - print(event2.venue) \ No newline at end of file From 3ecfb212c6273122797c76876d6b373b2cb94fa6 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Sat, 18 Sep 2021 13:18:17 -0300 Subject: [PATCH 07/66] updated from Atlas --- 18-with-match/lispy/py3.10/examples_test.py | 43 ++-- 18-with-match/lispy/py3.10/lis.py | 18 +- 18-with-match/lispy/py3.10/lis_test.py | 6 +- 18-with-match/lispy/py3.9/examples_test.py | 258 ++++++++++++++++++++ 18-with-match/lispy/py3.9/lis.py | 207 ++++++++++------ 18-with-match/lispy/py3.9/lis_test.py | 20 +- 6 files changed, 438 insertions(+), 114 deletions(-) create mode 100644 18-with-match/lispy/py3.9/examples_test.py diff --git a/18-with-match/lispy/py3.10/examples_test.py b/18-with-match/lispy/py3.10/examples_test.py index ed4b68a..ba6bd10 100644 --- a/18-with-match/lispy/py3.10/examples_test.py +++ b/18-with-match/lispy/py3.10/examples_test.py @@ -2,16 +2,12 @@ Doctests for `parse` -------------------- -# tag::PARSE_ATOM[] +# tag::PARSE[] >>> from lis import parse >>> parse('1.5') 1.5 >>> parse('ni!') 'ni!' - -# end::PARSE_ATOM[] - -# tag::PARSE_LIST[] >>> parse('(gcd 18 45)') ['gcd', 18, 45] >>> parse(''' @@ -21,15 +17,15 @@ ... ''') ['define', 'double', ['lambda', ['n'], ['*', 'n', 2]]] -# end::PARSE_LIST[] +# end::PARSE[] Doctest for `Environment` ------------------------- # tag::ENVIRONMENT[] >>> from lis import Environment ->>> outer_env = {'a': 0, 'b': 1} >>> inner_env = {'a': 2} +>>> outer_env = {'a': 0, 'b': 1} >>> env = Environment(inner_env, outer_env) >>> env['a'] = 111 # <1> >>> env['c'] = 222 @@ -64,11 +60,11 @@ # tag::EVAL_QUOTE[] ->>> evaluate(parse('(quote no-such-name)'), {}) +>>> evaluate(parse('(quote no-such-name)'), standard_env()) 'no-such-name' ->>> evaluate(parse('(quote (99 bottles of beer))'), {}) +>>> evaluate(parse('(quote (99 bottles of beer))'), standard_env()) [99, 'bottles', 'of', 'beer'] ->>> evaluate(parse('(quote (/ 10 0))'), {}) +>>> evaluate(parse('(quote (/ 10 0))'), standard_env()) ['/', 10, 0] # end::EVAL_QUOTE[] @@ -156,11 +152,12 @@ def test_factorial(): (if (= n 0) m (gcd n (mod m n)))) -(gcd 18 45) +(display (gcd 18 45)) """ -def test_gcd(): - got = run(gcd_src) - assert got == 9 +def test_gcd(capsys): + run(gcd_src) + captured = capsys.readouterr() + assert captured.out == '9\n' quicksort_src = """ @@ -216,7 +213,7 @@ def test_newton(): (define inc (make-adder 1)) (inc 99) """ -def test_newton(): +def test_closure(): got = run(closure_src) assert got == 100 @@ -228,13 +225,15 @@ def test_newton(): n) ) (define counter (make-counter)) -(counter) -(counter) -(counter) +(display (counter)) +(display (counter)) +(display (counter)) """ -def test_closure_with_change(): - got = run(closure_with_change_src) - assert got == 3 +def test_closure_with_change(capsys): + run(closure_with_change_src) + captured = capsys.readouterr() + assert captured.out == '1\n2\n3\n' + # tag::RUN_AVERAGER[] @@ -256,4 +255,4 @@ def test_closure_with_change(): def test_closure_averager(): got = run(closure_averager_src) assert got == 12.0 -# end::RUN_AVERAGER[] \ No newline at end of file +# end::RUN_AVERAGER[] diff --git a/18-with-match/lispy/py3.10/lis.py b/18-with-match/lispy/py3.10/lis.py index 4a5195c..ff494d1 100755 --- a/18-with-match/lispy/py3.10/lis.py +++ b/18-with-match/lispy/py3.10/lis.py @@ -58,10 +58,11 @@ def parse_atom(token: str) -> Atom: except ValueError: return Symbol(token) + ################ Global Environment # tag::ENV_CLASS[] -class Environment(ChainMap): +class Environment(ChainMap[Symbol, Any]): "A ChainMap that allows changing an item in-place." def change(self, key: Symbol, value: object) -> None: @@ -119,11 +120,11 @@ def standard_env() -> Environment: ################ Interaction: A REPL # tag::REPL[] -def repl() -> NoReturn: +def repl(prompt: str = 'lis.py> ') -> NoReturn: "A prompt-read-eval-print loop." global_env = standard_env() while True: - ast = parse(input('lis.py> ')) + ast = parse(input(prompt)) val = evaluate(ast, global_env) if val is not None: print(lispstr(val)) @@ -140,7 +141,10 @@ def lispstr(exp: object) -> str: ################ Evaluator # tag::EVALUATE[] -KEYWORDS = ['quote', 'if', 'lambda', 'define', 'set!'] +KEYWORDS = {'quote', 'if', 'lambda', 'define', 'set!'} + +def is_keyword(s: Any) -> bool: + return isinstance(s, Symbol) and s in KEYWORDS def evaluate(exp: Expression, env: Environment) -> Any: "Evaluate an expression in an environment." @@ -149,8 +153,6 @@ def evaluate(exp: Expression, env: Environment) -> Any: return x case Symbol(var): return env[var] - case []: - return [] case ['quote', x]: return x case ['if', test, consequence, alternative]: @@ -166,8 +168,8 @@ def evaluate(exp: Expression, env: Environment) -> Any: env[name] = Procedure(parms, body, env) case ['set!', Symbol(var), value_exp]: env.change(var, evaluate(value_exp, env)) - case [op, *args] if op not in KEYWORDS: - proc = evaluate(op, env) + case [func_exp, *args] if not is_keyword(func_exp): + proc = evaluate(func_exp, env) values = [evaluate(arg, env) for arg in args] return proc(*values) case _: diff --git a/18-with-match/lispy/py3.10/lis_test.py b/18-with-match/lispy/py3.10/lis_test.py index 3688888..03dc15c 100644 --- a/18-with-match/lispy/py3.10/lis_test.py +++ b/18-with-match/lispy/py3.10/lis_test.py @@ -73,10 +73,10 @@ def test_evaluate(source: str, expected: Optional[Expression]) -> None: def std_env() -> Environment: return standard_env() -# tests for each of the cases in evaluate +# tests for cases in evaluate def test_evaluate_variable() -> None: - env: Environment = dict(x=10) + env = Environment({'x': 10}) source = 'x' expected = 10 got = evaluate(parse(source), env) @@ -168,8 +168,6 @@ def test_invocation_user_procedure(std_env: Environment) -> None: assert got == 22 -###################################### for py3.10/lis.py only - def test_define_function(std_env: Environment) -> None: source = '(define (max a b) (if (>= a b) a b))' got = evaluate(parse(source), std_env) diff --git a/18-with-match/lispy/py3.9/examples_test.py b/18-with-match/lispy/py3.9/examples_test.py new file mode 100644 index 0000000..c632662 --- /dev/null +++ b/18-with-match/lispy/py3.9/examples_test.py @@ -0,0 +1,258 @@ +""" +Doctests for `parse` +-------------------- + +# tag::PARSE[] +>>> from lis import parse +>>> parse('1.5') +1.5 +>>> parse('ni!') +'ni!' +>>> parse('(gcd 18 45)') +['gcd', 18, 45] +>>> parse(''' +... (define double +... (lambda (n) +... (* n 2))) +... ''') +['define', 'double', ['lambda', ['n'], ['*', 'n', 2]]] + +# end::PARSE[] + +Doctest for `Environment` +------------------------- + +# tag::ENVIRONMENT[] +>>> from lis import Environment +>>> inner_env = {'a': 2} +>>> outer_env = {'a': 0, 'b': 1} +>>> env = Environment(inner_env, outer_env) +>>> env['a'] = 111 # <1> +>>> env['c'] = 222 +>>> env +Environment({'a': 111, 'c': 222}, {'a': 0, 'b': 1}) +>>> env.change('b', 333) # <2> +>>> env +Environment({'a': 111, 'c': 222}, {'a': 0, 'b': 333}) + +# end::ENVIRONMENT[] + +Doctests for `evaluate` +----------------------- + +# tag::EVAL_NUMBER[] +>>> from lis import parse, evaluate, standard_env +>>> evaluate(parse('1.5'), {}) +1.5 + +# end::EVAL_NUMBER[] + +# tag::EVAL_SYMBOL[] +>>> from lis import standard_env +>>> evaluate(parse('+'), standard_env()) + +>>> evaluate(parse('ni!'), standard_env()) +Traceback (most recent call last): + ... +KeyError: 'ni!' + +# end::EVAL_SYMBOL[] + + +# tag::EVAL_QUOTE[] +>>> evaluate(parse('(quote no-such-name)'), standard_env()) +'no-such-name' +>>> evaluate(parse('(quote (99 bottles of beer))'), standard_env()) +[99, 'bottles', 'of', 'beer'] +>>> evaluate(parse('(quote (/ 10 0))'), standard_env()) +['/', 10, 0] + +# end::EVAL_QUOTE[] + +# tag::EVAL_IF[] +>>> evaluate(parse('(if (= 3 3) 1 0))'), standard_env()) +1 +>>> evaluate(parse('(if (= 3 4) 1 0))'), standard_env()) +0 + +# end::EVAL_IF[] + + +# tag::EVAL_LAMBDA[] +>>> expr = '(lambda (a b) (* (/ a b) 100))' +>>> f = evaluate(parse(expr), standard_env()) +>>> f # doctest: +ELLIPSIS + +>>> f(15, 20) +75.0 + +# end::EVAL_LAMBDA[] + +# tag::EVAL_DEFINE[] +>>> global_env = standard_env() +>>> evaluate(parse('(define answer (* 7 6))'), global_env) +>>> global_env['answer'] +42 + +# end::EVAL_DEFINE[] + +# tag::EVAL_DEFUN[] +>>> global_env = standard_env() +>>> percent = '(define (% a b) (* (/ a b) 100))' +>>> evaluate(parse(percent), global_env) +>>> global_env['%'] # doctest: +ELLIPSIS + +>>> global_env['%'](170, 200) +85.0 + +# end::EVAL_DEFUN[] + +function call: + +# tag::EVAL_CALL[] +>>> evaluate(parse('(% (* 12 14) (- 500 100))'), global_env) +42.0 + +# end::EVAL_CALL[] + +# tag::EVAL_SYNTAX_ERROR[] +>>> evaluate(parse('(lambda is not like this)'), standard_env()) +Traceback (most recent call last): + ... +SyntaxError: (lambda is not like this) + +# end::EVAL_SYNTAX_ERROR[] + +""" + +import math + +from lis import run + + +fact_src = """ +(define (! n) + (if (< n 2) + 1 + (* n (! (- n 1))) + ) +) +(! 42) +""" +def test_factorial(): + got = run(fact_src) + assert got == 1405006117752879898543142606244511569936384000000000 + assert got == math.factorial(42) + + +gcd_src = """ +(define (mod m n) + (- m (* n (// m n)))) +(define (gcd m n) + (if (= n 0) + m + (gcd n (mod m n)))) +(display (gcd 18 45)) +""" +def test_gcd(capsys): + run(gcd_src) + captured = capsys.readouterr() + assert captured.out == '9\n' + + +quicksort_src = """ +(define (quicksort lst) + (if (null? lst) + lst + (begin + (define pivot (car lst)) + (define rest (cdr lst)) + (append + (quicksort + (filter (lambda (x) (< x pivot)) rest)) + (list pivot) + (quicksort + (filter (lambda (x) (>= x pivot)) rest))) + ) + ) +) +(quicksort (list 2 1 6 3 4 0 8 9 7 5)) +""" +def test_quicksort(): + got = run(quicksort_src) + assert got == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + + +# Example from Structure and Interpretation of Computer Programs +# https://mitpress.mit.edu/sites/default/files/sicp/full-text/sicp/book/node12.html + +newton_src = """ +(define (sqrt x) + (sqrt-iter 1.0 x)) +(define (sqrt-iter guess x) + (if (good-enough? guess x) + guess + (sqrt-iter (improve guess x) x))) +(define (good-enough? guess x) + (< (abs (- (* guess guess) x)) 0.001)) +(define (improve guess x) + (average guess (/ x guess))) +(define (average x y) + (/ (+ x y) 2)) +(sqrt 123454321) +""" +def test_newton(): + got = run(newton_src) + assert math.isclose(got, 11111) + + +closure_src = """ +(define (make-adder increment) + (lambda (x) (+ increment x)) +) +(define inc (make-adder 1)) +(inc 99) +""" +def test_closure(): + got = run(closure_src) + assert got == 100 + +closure_with_change_src = """ +(define (make-counter) + (define n 0) + (lambda () + (set! n (+ n 1)) + n) +) +(define counter (make-counter)) +(display (counter)) +(display (counter)) +(display (counter)) +""" +def test_closure_with_change(capsys): + run(closure_with_change_src) + captured = capsys.readouterr() + assert captured.out == '1\n2\n3\n' + + + +# tag::RUN_AVERAGER[] +closure_averager_src = """ +(define (make-averager) + (define count 0) + (define total 0) + (lambda (new-value) + (set! count (+ count 1)) + (set! total (+ total new-value)) + (/ total count) + ) +) +(define avg (make-averager)) +(avg 10) +(avg 11) +(avg 15) +""" +def test_closure_averager(): + got = run(closure_averager_src) + assert got == 12.0 +# end::RUN_AVERAGER[] \ No newline at end of file diff --git a/18-with-match/lispy/py3.9/lis.py b/18-with-match/lispy/py3.9/lis.py index 9e4dec1..e8881cd 100644 --- a/18-with-match/lispy/py3.9/lis.py +++ b/18-with-match/lispy/py3.9/lis.py @@ -1,73 +1,24 @@ +#!/usr/bin/env python + ################ Lispy: Scheme Interpreter in Python 3.9 ## (c) Peter Norvig, 2010-18; See http://norvig.com/lispy.html ## Minor edits for Fluent Python, Second Edition (O'Reilly, 2021) ## by Luciano Ramalho, adding type hints and pattern matching. + ################ Imports and Types import math import operator as op from collections import ChainMap -from collections.abc import MutableMapping, Iterator from itertools import chain -from typing import Any, Union +from typing import Any, Union, NoReturn Symbol = str Atom = Union[float, int, Symbol] Expression = Union[Atom, list] -Environment = MutableMapping[Symbol, object] - - -class Procedure: - "A user-defined Scheme procedure." - - def __init__(self, parms: list[Symbol], body: list[Expression], env: Environment): - self.parms = parms - self.body = body - self.env = env - - def __call__(self, *args: Expression) -> Any: - local_env = dict(zip(self.parms, args)) - env: Environment = ChainMap(local_env, self.env) - for exp in self.body: - result = evaluate(exp, env) - return result - - -################ Global Environment - -def standard_env() -> Environment: - "An environment with some Scheme standard procedures." - env: Environment = {} - env.update(vars(math)) # sin, cos, sqrt, pi, ... - env.update({ - '+':op.add, '-':op.sub, '*':op.mul, '/':op.truediv, - '>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq, - 'abs': abs, - 'append': op.add, - 'apply': lambda proc, args: proc(*args), - 'begin': lambda *x: x[-1], - 'car': lambda x: x[0], - 'cdr': lambda x: x[1:], - 'cons': lambda x,y: [x] + y, - 'eq?': op.is_, - 'equal?': op.eq, - 'length': len, - 'list': lambda *x: list(x), - 'list?': lambda x: isinstance(x,list), - 'map': lambda *args: list(map(*args)), - 'max': max, - 'min': min, - 'not': op.not_, - 'null?': lambda x: x == [], - 'number?': lambda x: isinstance(x, (int, float)), - 'procedure?': callable, - 'round': round, - 'symbol?': lambda x: isinstance(x, Symbol), - }) - return env ################ Parsing: parse, tokenize, and read_from_tokens @@ -75,12 +26,10 @@ def parse(program: str) -> Expression: "Read a Scheme expression from a string." return read_from_tokens(tokenize(program)) - def tokenize(s: str) -> list[str]: "Convert a string into a list of tokens." return s.replace('(', ' ( ').replace(')', ' ) ').split() - def read_from_tokens(tokens: list[str]) -> Expression: "Read an expression from a sequence of tokens." if len(tokens) == 0: @@ -97,7 +46,6 @@ def read_from_tokens(tokens: list[str]) -> Expression: else: return parse_atom(token) - def parse_atom(token: str) -> Atom: "Numbers become numbers; every other token is a symbol." try: @@ -109,17 +57,73 @@ def parse_atom(token: str) -> Atom: return Symbol(token) +################ Global Environment + +class Environment(ChainMap[Symbol, Any]): + "A ChainMap that allows changing an item in-place." + + def change(self, key: Symbol, value: object) -> None: + "Find where key is defined and change the value there." + for map in self.maps: + if key in map: + map[key] = value # type: ignore[index] + return + raise KeyError(key) + + +def standard_env() -> Environment: + "An environment with some Scheme standard procedures." + env = Environment() + env.update(vars(math)) # sin, cos, sqrt, pi, ... + env.update({ + '+': op.add, + '-': op.sub, + '*': op.mul, + '/': op.truediv, + '//': op.floordiv, + '>': op.gt, + '<': op.lt, + '>=': op.ge, + '<=': op.le, + '=': op.eq, + 'abs': abs, + 'append': lambda *args: list(chain(*args)), + 'apply': lambda proc, args: proc(*args), + 'begin': lambda *x: x[-1], + 'car': lambda x: x[0], + 'cdr': lambda x: x[1:], + 'cons': lambda x, y: [x] + y, + 'display': lambda x: print(lispstr(x)), + 'eq?': op.is_, + 'equal?': op.eq, + 'filter': lambda *args: list(filter(*args)), + 'length': len, + 'list': lambda *x: list(x), + 'list?': lambda x: isinstance(x, list), + 'map': lambda *args: list(map(*args)), + 'max': max, + 'min': min, + 'not': op.not_, + 'null?': lambda x: x == [], + 'number?': lambda x: isinstance(x, (int, float)), + 'procedure?': callable, + 'round': round, + 'symbol?': lambda x: isinstance(x, Symbol), + }) + return env + + ################ Interaction: A REPL -def repl(prompt: str = 'lis.py> ') -> None: +def repl(prompt: str = 'lis.py> ') -> NoReturn: "A prompt-read-eval-print loop." global_env = standard_env() while True: - val = evaluate(parse(input(prompt)), global_env) + ast = parse(input(prompt)) + val = evaluate(ast, global_env) if val is not None: print(lispstr(val)) - def lispstr(exp: object) -> str: "Convert a Python object back into a Lisp-readable string." if isinstance(exp, list): @@ -128,30 +132,81 @@ def lispstr(exp: object) -> str: return str(exp) -################ eval +################ Evaluator -def evaluate(x: Expression, env: Environment) -> Any: +def evaluate(exp: Expression, env: Environment) -> Any: "Evaluate an expression in an environment." - if isinstance(x, Symbol): # variable reference - return env[x] - elif not isinstance(x, list): # constant literal - return x - elif x[0] == 'quote': # (quote exp) - (_, exp) = x + if isinstance(exp, Symbol): # variable reference + return env[exp] + elif not isinstance(exp, list): # constant literal return exp - elif x[0] == 'if': # (if test conseq alt) - (_, test, consequence, alternative) = x + elif exp[0] == 'quote': # (quote exp) + (_, x) = exp + return x + elif exp[0] == 'if': # (if test conseq alt) + (_, test, consequence, alternative) = exp if evaluate(test, env): return evaluate(consequence, env) else: return evaluate(alternative, env) - elif x[0] == 'define': # (define name exp) - (_, name, exp) = x - env[name] = evaluate(exp, env) - elif x[0] == 'lambda': # (lambda (parm…) body) - (_, parms, *body) = x + elif exp[0] == 'lambda': # (lambda (parm…) body…) + (_, parms, *body) = exp + if not isinstance(parms, list): + raise SyntaxError(lispstr(exp)) return Procedure(parms, body, env) + elif exp[0] == 'define': + (_, name_exp, *rest) = exp + if isinstance(name_exp, Symbol): # (define name exp) + value_exp = rest[0] + env[name_exp] = evaluate(value_exp, env) + else: # (define (name parm…) body…) + name, *parms = name_exp + env[name] = Procedure(parms, rest, env) + elif exp[0] == 'set!': + (_, var, value_exp) = exp + env.change(var, evaluate(value_exp, env)) else: # (proc arg…) - proc = evaluate(x[0], env) - args = [evaluate(exp, env) for exp in x[1:]] + (func_exp, *args) = exp + proc = evaluate(func_exp, env) + args = [evaluate(arg, env) for arg in args] return proc(*args) + + +class Procedure: + "A user-defined Scheme procedure." + + def __init__( + self, parms: list[Symbol], body: list[Expression], env: Environment + ): + self.parms = parms + self.body = body + self.env = env + + def __call__(self, *args: Expression) -> Any: + local_env = dict(zip(self.parms, args)) + env = Environment(local_env, self.env) + for exp in self.body: + result = evaluate(exp, env) + return result + + +################ command-line interface + +def run(source: str) -> Any: + global_env = standard_env() + tokens = tokenize(source) + while tokens: + exp = read_from_tokens(tokens) + result = evaluate(exp, global_env) + return result + +def main(args: list[str]) -> None: + if len(args) == 1: + with open(args[0]) as fp: + run(fp.read()) + else: + repl() + +if __name__ == '__main__': + import sys + main(sys.argv[1:]) diff --git a/18-with-match/lispy/py3.9/lis_test.py b/18-with-match/lispy/py3.9/lis_test.py index 106ac24..03dc15c 100644 --- a/18-with-match/lispy/py3.9/lis_test.py +++ b/18-with-match/lispy/py3.9/lis_test.py @@ -1,8 +1,8 @@ -from typing import Any, Optional +from typing import Optional from pytest import mark, fixture -from lis import parse, evaluate, standard_env, Symbol, Environment, Expression +from lis import parse, evaluate, Expression, Environment, standard_env ############################################################# tests for parse @@ -73,10 +73,10 @@ def test_evaluate(source: str, expected: Optional[Expression]) -> None: def std_env() -> Environment: return standard_env() -# tests for each of the cases in evaluate +# tests for cases in evaluate def test_evaluate_variable() -> None: - env: Environment = dict(x=10) + env = Environment({'x': 10}) source = 'x' expected = 10 got = evaluate(parse(source), env) @@ -166,3 +166,15 @@ def test_invocation_user_procedure(std_env: Environment) -> None: """ got = evaluate(parse(source), std_env) assert got == 22 + + +def test_define_function(std_env: Environment) -> None: + source = '(define (max a b) (if (>= a b) a b))' + got = evaluate(parse(source), std_env) + assert got is None + max_fn = std_env['max'] + assert max_fn.parms == ['a', 'b'] + assert max_fn.body == [['if', ['>=', 'a', 'b'], 'a', 'b']] + assert max_fn.env is std_env + assert max_fn(1, 2) == 2 + assert max_fn(3, 2) == 3 From 2f2f87d4fb297869cb5763ec9b2ffcad3e841d20 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Mon, 20 Sep 2021 10:37:26 -0300 Subject: [PATCH 08/66] sync from Atlas --- 02-array-seq/lispy/py3.10/examples_test.py | 258 ++++++++++++++++++++ 02-array-seq/lispy/py3.10/lis.py | 219 +++++++++++++++++ 02-array-seq/lispy/py3.10/lis_test.py | 180 ++++++++++++++ 02-array-seq/lispy/py3.10/quicksort.scm | 17 ++ 02-array-seq/lispy/py3.9/README.md | 33 +++ 02-array-seq/lispy/py3.9/examples_test.py | 196 +++++++++++++++ 02-array-seq/lispy/py3.9/lis.py | 209 ++++++++++++++++ 02-array-seq/lispy/py3.9/lis_test.py | 180 ++++++++++++++ 18-with-match/lispy/py3.10/examples_test.py | 43 ++-- 18-with-match/lispy/py3.10/lis.py | 14 +- 18-with-match/lispy/py3.10/lis_test.py | 6 +- 18-with-match/lispy/py3.9/examples_test.py | 258 ++++++++++++++++++++ 18-with-match/lispy/py3.9/lis.py | 207 ++++++++++------ 18-with-match/lispy/py3.9/lis_test.py | 20 +- 18-with-match/mirror_gen.py | 3 + 22-dyn-attr-prop/doc_property.py | 2 +- 16 files changed, 1730 insertions(+), 115 deletions(-) create mode 100644 02-array-seq/lispy/py3.10/examples_test.py create mode 100755 02-array-seq/lispy/py3.10/lis.py create mode 100644 02-array-seq/lispy/py3.10/lis_test.py create mode 100644 02-array-seq/lispy/py3.10/quicksort.scm create mode 100644 02-array-seq/lispy/py3.9/README.md create mode 100644 02-array-seq/lispy/py3.9/examples_test.py create mode 100644 02-array-seq/lispy/py3.9/lis.py create mode 100644 02-array-seq/lispy/py3.9/lis_test.py create mode 100644 18-with-match/lispy/py3.9/examples_test.py diff --git a/02-array-seq/lispy/py3.10/examples_test.py b/02-array-seq/lispy/py3.10/examples_test.py new file mode 100644 index 0000000..ba6bd10 --- /dev/null +++ b/02-array-seq/lispy/py3.10/examples_test.py @@ -0,0 +1,258 @@ +""" +Doctests for `parse` +-------------------- + +# tag::PARSE[] +>>> from lis import parse +>>> parse('1.5') +1.5 +>>> parse('ni!') +'ni!' +>>> parse('(gcd 18 45)') +['gcd', 18, 45] +>>> parse(''' +... (define double +... (lambda (n) +... (* n 2))) +... ''') +['define', 'double', ['lambda', ['n'], ['*', 'n', 2]]] + +# end::PARSE[] + +Doctest for `Environment` +------------------------- + +# tag::ENVIRONMENT[] +>>> from lis import Environment +>>> inner_env = {'a': 2} +>>> outer_env = {'a': 0, 'b': 1} +>>> env = Environment(inner_env, outer_env) +>>> env['a'] = 111 # <1> +>>> env['c'] = 222 +>>> env +Environment({'a': 111, 'c': 222}, {'a': 0, 'b': 1}) +>>> env.change('b', 333) # <2> +>>> env +Environment({'a': 111, 'c': 222}, {'a': 0, 'b': 333}) + +# end::ENVIRONMENT[] + +Doctests for `evaluate` +----------------------- + +# tag::EVAL_NUMBER[] +>>> from lis import parse, evaluate, standard_env +>>> evaluate(parse('1.5'), {}) +1.5 + +# end::EVAL_NUMBER[] + +# tag::EVAL_SYMBOL[] +>>> from lis import standard_env +>>> evaluate(parse('+'), standard_env()) + +>>> evaluate(parse('ni!'), standard_env()) +Traceback (most recent call last): + ... +KeyError: 'ni!' + +# end::EVAL_SYMBOL[] + + +# tag::EVAL_QUOTE[] +>>> evaluate(parse('(quote no-such-name)'), standard_env()) +'no-such-name' +>>> evaluate(parse('(quote (99 bottles of beer))'), standard_env()) +[99, 'bottles', 'of', 'beer'] +>>> evaluate(parse('(quote (/ 10 0))'), standard_env()) +['/', 10, 0] + +# end::EVAL_QUOTE[] + +# tag::EVAL_IF[] +>>> evaluate(parse('(if (= 3 3) 1 0))'), standard_env()) +1 +>>> evaluate(parse('(if (= 3 4) 1 0))'), standard_env()) +0 + +# end::EVAL_IF[] + + +# tag::EVAL_LAMBDA[] +>>> expr = '(lambda (a b) (* (/ a b) 100))' +>>> f = evaluate(parse(expr), standard_env()) +>>> f # doctest: +ELLIPSIS + +>>> f(15, 20) +75.0 + +# end::EVAL_LAMBDA[] + +# tag::EVAL_DEFINE[] +>>> global_env = standard_env() +>>> evaluate(parse('(define answer (* 7 6))'), global_env) +>>> global_env['answer'] +42 + +# end::EVAL_DEFINE[] + +# tag::EVAL_DEFUN[] +>>> global_env = standard_env() +>>> percent = '(define (% a b) (* (/ a b) 100))' +>>> evaluate(parse(percent), global_env) +>>> global_env['%'] # doctest: +ELLIPSIS + +>>> global_env['%'](170, 200) +85.0 + +# end::EVAL_DEFUN[] + +function call: + +# tag::EVAL_CALL[] +>>> evaluate(parse('(% (* 12 14) (- 500 100))'), global_env) +42.0 + +# end::EVAL_CALL[] + +# tag::EVAL_SYNTAX_ERROR[] +>>> evaluate(parse('(lambda is not like this)'), standard_env()) +Traceback (most recent call last): + ... +SyntaxError: (lambda is not like this) + +# end::EVAL_SYNTAX_ERROR[] + +""" + +import math + +from lis import run + + +fact_src = """ +(define (! n) + (if (< n 2) + 1 + (* n (! (- n 1))) + ) +) +(! 42) +""" +def test_factorial(): + got = run(fact_src) + assert got == 1405006117752879898543142606244511569936384000000000 + assert got == math.factorial(42) + + +gcd_src = """ +(define (mod m n) + (- m (* n (// m n)))) +(define (gcd m n) + (if (= n 0) + m + (gcd n (mod m n)))) +(display (gcd 18 45)) +""" +def test_gcd(capsys): + run(gcd_src) + captured = capsys.readouterr() + assert captured.out == '9\n' + + +quicksort_src = """ +(define (quicksort lst) + (if (null? lst) + lst + (begin + (define pivot (car lst)) + (define rest (cdr lst)) + (append + (quicksort + (filter (lambda (x) (< x pivot)) rest)) + (list pivot) + (quicksort + (filter (lambda (x) (>= x pivot)) rest))) + ) + ) +) +(quicksort (list 2 1 6 3 4 0 8 9 7 5)) +""" +def test_quicksort(): + got = run(quicksort_src) + assert got == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + + +# Example from Structure and Interpretation of Computer Programs +# https://mitpress.mit.edu/sites/default/files/sicp/full-text/sicp/book/node12.html + +newton_src = """ +(define (sqrt x) + (sqrt-iter 1.0 x)) +(define (sqrt-iter guess x) + (if (good-enough? guess x) + guess + (sqrt-iter (improve guess x) x))) +(define (good-enough? guess x) + (< (abs (- (* guess guess) x)) 0.001)) +(define (improve guess x) + (average guess (/ x guess))) +(define (average x y) + (/ (+ x y) 2)) +(sqrt 123454321) +""" +def test_newton(): + got = run(newton_src) + assert math.isclose(got, 11111) + + +closure_src = """ +(define (make-adder increment) + (lambda (x) (+ increment x)) +) +(define inc (make-adder 1)) +(inc 99) +""" +def test_closure(): + got = run(closure_src) + assert got == 100 + +closure_with_change_src = """ +(define (make-counter) + (define n 0) + (lambda () + (set! n (+ n 1)) + n) +) +(define counter (make-counter)) +(display (counter)) +(display (counter)) +(display (counter)) +""" +def test_closure_with_change(capsys): + run(closure_with_change_src) + captured = capsys.readouterr() + assert captured.out == '1\n2\n3\n' + + + +# tag::RUN_AVERAGER[] +closure_averager_src = """ +(define (make-averager) + (define count 0) + (define total 0) + (lambda (new-value) + (set! count (+ count 1)) + (set! total (+ total new-value)) + (/ total count) + ) +) +(define avg (make-averager)) +(avg 10) +(avg 11) +(avg 15) +""" +def test_closure_averager(): + got = run(closure_averager_src) + assert got == 12.0 +# end::RUN_AVERAGER[] diff --git a/02-array-seq/lispy/py3.10/lis.py b/02-array-seq/lispy/py3.10/lis.py new file mode 100755 index 0000000..cffb9a1 --- /dev/null +++ b/02-array-seq/lispy/py3.10/lis.py @@ -0,0 +1,219 @@ +#!/usr/bin/env python + +################ Lispy: Scheme Interpreter in Python 3.10 + +## (c) Peter Norvig, 2010-18; See http://norvig.com/lispy.html +## Minor edits for Fluent Python, Second Edition (O'Reilly, 2021) +## by Luciano Ramalho, adding type hints and pattern matching. + + +################ Imports and Types + +# tag::IMPORTS[] +import math +import operator as op +from collections import ChainMap +from itertools import chain +from typing import Any, TypeAlias, NoReturn + +Symbol: TypeAlias = str +Atom: TypeAlias = float | int | Symbol +Expression: TypeAlias = Atom | list +# end::IMPORTS[] + + +################ Parsing: parse, tokenize, and read_from_tokens + +def parse(program: str) -> Expression: + "Read a Scheme expression from a string." + return read_from_tokens(tokenize(program)) + +def tokenize(s: str) -> list[str]: + "Convert a string into a list of tokens." + return s.replace('(', ' ( ').replace(')', ' ) ').split() + +def read_from_tokens(tokens: list[str]) -> Expression: + "Read an expression from a sequence of tokens." + if len(tokens) == 0: + raise SyntaxError('unexpected EOF while reading') + token = tokens.pop(0) + if '(' == token: + exp = [] + while tokens[0] != ')': + exp.append(read_from_tokens(tokens)) + tokens.pop(0) # discard ')' + return exp + elif ')' == token: + raise SyntaxError('unexpected )') + else: + return parse_atom(token) + +def parse_atom(token: str) -> Atom: + "Numbers become numbers; every other token is a symbol." + try: + return int(token) + except ValueError: + try: + return float(token) + except ValueError: + return Symbol(token) + + +################ Global Environment + +# tag::ENV_CLASS[] +class Environment(ChainMap[Symbol, Any]): + "A ChainMap that allows changing an item in-place." + + def change(self, key: Symbol, value: object) -> None: + "Find where key is defined and change the value there." + for map in self.maps: + if key in map: + map[key] = value + return + raise KeyError(key) +# end::ENV_CLASS[] + + +def standard_env() -> Environment: + "An environment with some Scheme standard procedures." + env = Environment() + env.update(vars(math)) # sin, cos, sqrt, pi, ... + env.update({ + '+': op.add, + '-': op.sub, + '*': op.mul, + '/': op.truediv, + '//': op.floordiv, + '>': op.gt, + '<': op.lt, + '>=': op.ge, + '<=': op.le, + '=': op.eq, + 'abs': abs, + 'append': lambda *args: list(chain(*args)), + 'apply': lambda proc, args: proc(*args), + 'begin': lambda *x: x[-1], + 'car': lambda x: x[0], + 'cdr': lambda x: x[1:], + 'cons': lambda x, y: [x] + y, + 'display': lambda x: print(lispstr(x)), + 'eq?': op.is_, + 'equal?': op.eq, + 'filter': lambda *args: list(filter(*args)), + 'length': len, + 'list': lambda *x: list(x), + 'list?': lambda x: isinstance(x, list), + 'map': lambda *args: list(map(*args)), + 'max': max, + 'min': min, + 'not': op.not_, + 'null?': lambda x: x == [], + 'number?': lambda x: isinstance(x, (int, float)), + 'procedure?': callable, + 'round': round, + 'symbol?': lambda x: isinstance(x, Symbol), + }) + return env + + +################ Interaction: A REPL + +# tag::REPL[] +def repl(prompt: str = 'lis.py> ') -> NoReturn: + "A prompt-read-eval-print loop." + global_env = standard_env() + while True: + ast = parse(input(prompt)) + val = evaluate(ast, global_env) + if val is not None: + print(lispstr(val)) + +def lispstr(exp: object) -> str: + "Convert a Python object back into a Lisp-readable string." + if isinstance(exp, list): + return '(' + ' '.join(map(lispstr, exp)) + ')' + else: + return str(exp) +# end::REPL[] + + +################ Evaluator + +KEYWORDS = ['quote', 'if', 'lambda', 'define', 'set!'] + +# tag::EVAL_MATCH_TOP[] +def evaluate(exp: Expression, env: Environment) -> Any: + "Evaluate an expression in an environment." + match exp: +# end::EVAL_MATCH_TOP[] + case int(x) | float(x): + return x + case Symbol(name): + return env[name] +# tag::EVAL_MATCH_MIDDLE[] + case ['quote', x]: # <1> + return x + case ['if', test, consequence, alternative]: # <2> + if evaluate(test, env): + return evaluate(consequence, env) + else: + return evaluate(alternative, env) + case ['lambda', [*parms], *body] if body: # <3> + return Procedure(parms, body, env) + case ['define', Symbol(name), value_exp]: # <4> + env[name] = evaluate(value_exp, env) +# end::EVAL_MATCH_MIDDLE[] + case ['define', [Symbol(name), *parms], *body] if body: + env[name] = Procedure(parms, body, env) + case ['set!', Symbol(name), value_exp]: + env.change(name, evaluate(value_exp, env)) + case [func_exp, *args] if func_exp not in KEYWORDS: + proc = evaluate(func_exp, env) + values = [evaluate(arg, env) for arg in args] + return proc(*values) +# tag::EVAL_MATCH_BOTTOM[] + case _: # <5> + raise SyntaxError(lispstr(exp)) +# end::EVAL_MATCH_BOTTOM[] + +# tag::PROCEDURE[] +class Procedure: + "A user-defined Scheme procedure." + + def __init__( # <1> + self, parms: list[Symbol], body: list[Expression], env: Environment + ): + self.parms = parms # <2> + self.body = body + self.env = env + + def __call__(self, *args: Expression) -> Any: # <3> + local_env = dict(zip(self.parms, args)) # <4> + env = Environment(local_env, self.env) # <5> + for exp in self.body: # <6> + result = evaluate(exp, env) + return result # <7> +# end::PROCEDURE[] + + +################ command-line interface + +def run(source: str) -> Any: + global_env = standard_env() + tokens = tokenize(source) + while tokens: + exp = read_from_tokens(tokens) + result = evaluate(exp, global_env) + return result + +def main(args: list[str]) -> None: + if len(args) == 1: + with open(args[0]) as fp: + run(fp.read()) + else: + repl() + +if __name__ == '__main__': + import sys + main(sys.argv[1:]) diff --git a/02-array-seq/lispy/py3.10/lis_test.py b/02-array-seq/lispy/py3.10/lis_test.py new file mode 100644 index 0000000..03dc15c --- /dev/null +++ b/02-array-seq/lispy/py3.10/lis_test.py @@ -0,0 +1,180 @@ +from typing import Optional + +from pytest import mark, fixture + +from lis import parse, evaluate, Expression, Environment, standard_env + +############################################################# tests for parse + +@mark.parametrize( 'source, expected', [ + ('7', 7), + ('x', 'x'), + ('(sum 1 2 3)', ['sum', 1, 2, 3]), + ('(+ (* 2 100) (* 1 10))', ['+', ['*', 2, 100], ['*', 1, 10]]), + ('99 100', 99), # parse stops at the first complete expression + ('(a)(b)', ['a']), +]) +def test_parse(source: str, expected: Expression) -> None: + got = parse(source) + assert got == expected + + +########################################################## tests for evaluate + +# Norvig's tests are not isolated: they assume the +# same environment from first to last test. +global_env_for_first_test = standard_env() + +@mark.parametrize( 'source, expected', [ + ("(quote (testing 1 (2.0) -3.14e159))", ['testing', 1, [2.0], -3.14e159]), + ("(+ 2 2)", 4), + ("(+ (* 2 100) (* 1 10))", 210), + ("(if (> 6 5) (+ 1 1) (+ 2 2))", 2), + ("(if (< 6 5) (+ 1 1) (+ 2 2))", 4), + ("(define x 3)", None), + ("x", 3), + ("(+ x x)", 6), + ("((lambda (x) (+ x x)) 5)", 10), + ("(define twice (lambda (x) (* 2 x)))", None), + ("(twice 5)", 10), + ("(define compose (lambda (f g) (lambda (x) (f (g x)))))", None), + ("((compose list twice) 5)", [10]), + ("(define repeat (lambda (f) (compose f f)))", None), + ("((repeat twice) 5)", 20), + ("((repeat (repeat twice)) 5)", 80), + ("(define fact (lambda (n) (if (<= n 1) 1 (* n (fact (- n 1))))))", None), + ("(fact 3)", 6), + ("(fact 50)", 30414093201713378043612608166064768844377641568960512000000000000), + ("(define abs (lambda (n) ((if (> n 0) + -) 0 n)))", None), + ("(list (abs -3) (abs 0) (abs 3))", [3, 0, 3]), + ("""(define combine (lambda (f) + (lambda (x y) + (if (null? x) (quote ()) + (f (list (car x) (car y)) + ((combine f) (cdr x) (cdr y)))))))""", None), + ("(define zip (combine cons))", None), + ("(zip (list 1 2 3 4) (list 5 6 7 8))", [[1, 5], [2, 6], [3, 7], [4, 8]]), + ("""(define riff-shuffle (lambda (deck) + (begin + (define take (lambda (n seq) (if (<= n 0) (quote ()) (cons (car seq) (take (- n 1) (cdr seq)))))) + (define drop (lambda (n seq) (if (<= n 0) seq (drop (- n 1) (cdr seq))))) + (define mid (lambda (seq) (/ (length seq) 2))) + ((combine append) (take (mid deck) deck) (drop (mid deck) deck)))))""", None), + ("(riff-shuffle (list 1 2 3 4 5 6 7 8))", [1, 5, 2, 6, 3, 7, 4, 8]), + ("((repeat riff-shuffle) (list 1 2 3 4 5 6 7 8))", [1, 3, 5, 7, 2, 4, 6, 8]), + ("(riff-shuffle (riff-shuffle (riff-shuffle (list 1 2 3 4 5 6 7 8))))", [1,2,3,4,5,6,7,8]), +]) +def test_evaluate(source: str, expected: Optional[Expression]) -> None: + got = evaluate(parse(source), global_env_for_first_test) + assert got == expected + + +@fixture +def std_env() -> Environment: + return standard_env() + +# tests for cases in evaluate + +def test_evaluate_variable() -> None: + env = Environment({'x': 10}) + source = 'x' + expected = 10 + got = evaluate(parse(source), env) + assert got == expected + + +def test_evaluate_literal(std_env: Environment) -> None: + source = '3.3' + expected = 3.3 + got = evaluate(parse(source), std_env) + assert got == expected + + +def test_evaluate_quote(std_env: Environment) -> None: + source = '(quote (1.1 is not 1))' + expected = [1.1, 'is', 'not', 1] + got = evaluate(parse(source), std_env) + assert got == expected + + +def test_evaluate_if_true(std_env: Environment) -> None: + source = '(if 1 10 no-such-thing)' + expected = 10 + got = evaluate(parse(source), std_env) + assert got == expected + + +def test_evaluate_if_false(std_env: Environment) -> None: + source = '(if 0 no-such-thing 20)' + expected = 20 + got = evaluate(parse(source), std_env) + assert got == expected + + +def test_define(std_env: Environment) -> None: + source = '(define answer (* 6 7))' + got = evaluate(parse(source), std_env) + assert got is None + assert std_env['answer'] == 42 + + +def test_lambda(std_env: Environment) -> None: + source = '(lambda (a b) (if (>= a b) a b))' + func = evaluate(parse(source), std_env) + assert func.parms == ['a', 'b'] + assert func.body == [['if', ['>=', 'a', 'b'], 'a', 'b']] + assert func.env is std_env + assert func(1, 2) == 2 + assert func(3, 2) == 3 + + +def test_begin(std_env: Environment) -> None: + source = """ + (begin + (define x (* 2 3)) + (* x 7) + ) + """ + got = evaluate(parse(source), std_env) + assert got == 42 + + +def test_invocation_builtin_car(std_env: Environment) -> None: + source = '(car (quote (11 22 33)))' + got = evaluate(parse(source), std_env) + assert got == 11 + + +def test_invocation_builtin_append(std_env: Environment) -> None: + source = '(append (quote (a b)) (quote (c d)))' + got = evaluate(parse(source), std_env) + assert got == ['a', 'b', 'c', 'd'] + + +def test_invocation_builtin_map(std_env: Environment) -> None: + source = '(map (lambda (x) (* x 2)) (quote (1 2 3))))' + got = evaluate(parse(source), std_env) + assert got == [2, 4, 6] + + +def test_invocation_user_procedure(std_env: Environment) -> None: + source = """ + (begin + (define max (lambda (a b) (if (>= a b) a b))) + (max 22 11) + ) + """ + got = evaluate(parse(source), std_env) + assert got == 22 + + +def test_define_function(std_env: Environment) -> None: + source = '(define (max a b) (if (>= a b) a b))' + got = evaluate(parse(source), std_env) + assert got is None + max_fn = std_env['max'] + assert max_fn.parms == ['a', 'b'] + assert max_fn.body == [['if', ['>=', 'a', 'b'], 'a', 'b']] + assert max_fn.env is std_env + assert max_fn(1, 2) == 2 + assert max_fn(3, 2) == 3 diff --git a/02-array-seq/lispy/py3.10/quicksort.scm b/02-array-seq/lispy/py3.10/quicksort.scm new file mode 100644 index 0000000..08dd596 --- /dev/null +++ b/02-array-seq/lispy/py3.10/quicksort.scm @@ -0,0 +1,17 @@ +(define (quicksort lst) + (if (null? lst) + lst + (begin + (define pivot (car lst)) + (define rest (cdr lst)) + (append + (quicksort + (filter (lambda (x) (< x pivot)) rest)) + (list pivot) + (quicksort + (filter (lambda (x) (>= x pivot)) rest))) + ) + ) +) +(display + (quicksort (list 2 1 6 3 4 0 8 9 7 5))) diff --git a/02-array-seq/lispy/py3.9/README.md b/02-array-seq/lispy/py3.9/README.md new file mode 100644 index 0000000..fdb1f08 --- /dev/null +++ b/02-array-seq/lispy/py3.9/README.md @@ -0,0 +1,33 @@ +# Changes from the original + +While adapting Peter Norvig's [lis.py](https://github.com/norvig/pytudes/blob/705c0a335c1811a203e79587d7d41865cf7f41c7/py/lis.py) for +use in _Fluent Python, Second Edition_, I made a few changes for didactic reasons. + +_Luciano Ramalho_ + +## Major changes + +* Make the `lambda` form accept more than one expression as the body. This is consistent with [_Scheme_ syntax](https://web.mit.edu/scheme_v9.2/doc/mit-scheme-ref/Lambda-Expressions.html), and provides a useful example for the book. To implement this: + * In `Procedure.__call__`: evaluate `self.body` as a list of expressions, instead of a single expression. Return the value of the last expression. + * In `evaluate()`: when processing `lambda`, unpack expression into `(_, parms, *body)`, to accept a list of expressions as the body. +* Remove the `global_env` global `dict`. It is only used as a default value for the `env` parameter in `evaluate()`, but it is unsafe to use mutable data structures as parameter default values. To implement this: + * In `repl()`: create local variable `global_env` and pass it as the `env` paramater of `evaluate()`. + * In `evaluate()`, remove `global_env` default value for `env`. +* Rewrite the custom test script +[lispytest.py](https://github.com/norvig/pytudes/blob/705c0a335c1811a203e79587d7d41865cf7f41c7/py/lispytest.py) as +[lis_test.py](https://github.com/fluentpython/example-code-2e/blob/master/02-array-seq/lispy/py3.9/lis_test.py): +a standard [pytest](https://docs.pytest.org) test suite including new test cases, preserving all Norvig's test cases for +[lis.py](https://github.com/norvig/pytudes/blob/705c0a335c1811a203e79587d7d41865cf7f41c7/py/lis.py) +but removing the test cases for the features implemented only in +[lispy.py](https://github.com/norvig/pytudes/blob/705c0a335c1811a203e79587d7d41865cf7f41c7/py/lispy.py). + + +## Minor changes + +Cosmetic changes to make the code look more familiar to +Python programmers, the audience of _Fluent Python_. + +* Rename `eval()` to `evaluate()`, to avoid confusion with Python's `eval` built-in function. +* Refer to the list class as `list` instead of aliasing as `List`, to avoid confusion with `typing.List` which is often imported as `List`. +* Import `collections.ChainMap` as `ChainMap` instead of `Environment`. + diff --git a/02-array-seq/lispy/py3.9/examples_test.py b/02-array-seq/lispy/py3.9/examples_test.py new file mode 100644 index 0000000..bdcda48 --- /dev/null +++ b/02-array-seq/lispy/py3.9/examples_test.py @@ -0,0 +1,196 @@ +""" +Doctests for `parse` +-------------------- + +# tag::PARSE[] +>>> from lis import parse +>>> parse('1.5') +1.5 +>>> parse('ni!') +'ni!' +>>> parse('(gcd 18 45)') +['gcd', 18, 45] +>>> parse(''' +... (define double +... (lambda (n) +... (* n 2))) +... ''') +['define', 'double', ['lambda', ['n'], ['*', 'n', 2]]] + +# end::PARSE[] + +Doctest for `Environment` +------------------------- + +# tag::ENVIRONMENT[] +>>> from lis import Environment +>>> inner_env = {'a': 2} +>>> outer_env = {'a': 0, 'b': 1} +>>> env = Environment(inner_env, outer_env) +>>> env['a'] = 111 # <1> +>>> env['c'] = 222 +>>> env +Environment({'a': 111, 'c': 222}, {'a': 0, 'b': 1}) +>>> env.change('b', 333) # <2> +>>> env +Environment({'a': 111, 'c': 222}, {'a': 0, 'b': 333}) + +# end::ENVIRONMENT[] + +Doctests for `evaluate` +----------------------- + +# tag::EVAL_NUMBER[] +>>> from lis import parse, evaluate, standard_env +>>> evaluate(parse('1.5'), {}) +1.5 + +# end::EVAL_NUMBER[] + +# tag::EVAL_SYMBOL[] +>>> from lis import standard_env +>>> evaluate(parse('+'), standard_env()) + +>>> evaluate(parse('ni!'), standard_env()) +Traceback (most recent call last): + ... +KeyError: 'ni!' + +# end::EVAL_SYMBOL[] + + +# tag::EVAL_QUOTE[] +>>> evaluate(parse('(quote no-such-name)'), standard_env()) +'no-such-name' +>>> evaluate(parse('(quote (99 bottles of beer))'), standard_env()) +[99, 'bottles', 'of', 'beer'] +>>> evaluate(parse('(quote (/ 10 0))'), standard_env()) +['/', 10, 0] + +# end::EVAL_QUOTE[] + +# tag::EVAL_IF[] +>>> evaluate(parse('(if (= 3 3) 1 0))'), standard_env()) +1 +>>> evaluate(parse('(if (= 3 4) 1 0))'), standard_env()) +0 + +# end::EVAL_IF[] + + +# tag::EVAL_LAMBDA[] +>>> expr = '(lambda (a b) (* (/ a b) 100))' +>>> f = evaluate(parse(expr), standard_env()) +>>> f # doctest: +ELLIPSIS + +>>> f(15, 20) +75.0 + +# end::EVAL_LAMBDA[] + +# tag::EVAL_DEFINE[] +>>> global_env = standard_env() +>>> evaluate(parse('(define answer (* 7 6))'), global_env) +>>> global_env['answer'] +42 + +# end::EVAL_DEFINE[] + +# tag::EVAL_DEFUN[] +>>> global_env = standard_env() +>>> percent = '(define % (lambda (a b) (* (/ a b) 100)))' +>>> evaluate(parse(percent), global_env) +>>> global_env['%'] # doctest: +ELLIPSIS + +>>> global_env['%'](170, 200) +85.0 + +# end::EVAL_DEFUN[] + +function call: + +# tag::EVAL_CALL[] +>>> evaluate(parse('(% (* 12 14) (- 500 100))'), global_env) +42.0 + +# end::EVAL_CALL[] + +""" + +import math + +from lis import run + + +fact_src = """ +(define ! + (lambda (n) + (if (< n 2) + 1 + (* n (! (- n 1))) + ) + ) +) +(! 42) +""" +def test_factorial(): + got = run(fact_src) + assert got == 1405006117752879898543142606244511569936384000000000 + assert got == math.factorial(42) + +closure_src = """ +(define make-adder + (lambda (increment) + (lambda (x) (+ increment x)) + ) +) +(define inc (make-adder 1)) +(inc 99) +""" +def test_closure(): + got = run(closure_src) + assert got == 100 + +closure_with_change_src = """ +(define make-counter + (lambda () + (define n 0) + (lambda () + (set! n (+ n 1)) + n) + ) +) +(define counter (make-counter)) +(display (counter)) +(display (counter)) +(display (counter)) +""" +def test_closure_with_change(capsys): + run(closure_with_change_src) + captured = capsys.readouterr() + assert captured.out == '1\n2\n3\n' + + + +# tag::RUN_AVERAGER[] +closure_averager_src = """ +(define make-averager + (lambda () + (define count 0) + (define total 0) + (lambda (new-value) + (set! count (+ count 1)) + (set! total (+ total new-value)) + (/ total count) + ) + ) +) +(define avg (make-averager)) +(avg 10) +(avg 11) +(avg 15) +""" +def test_closure_averager(): + got = run(closure_averager_src) + assert got == 12.0 +# end::RUN_AVERAGER[] \ No newline at end of file diff --git a/02-array-seq/lispy/py3.9/lis.py b/02-array-seq/lispy/py3.9/lis.py new file mode 100644 index 0000000..843d4cc --- /dev/null +++ b/02-array-seq/lispy/py3.9/lis.py @@ -0,0 +1,209 @@ +#!/usr/bin/env python + +################ Lispy: Scheme Interpreter in Python 3.9 + +## (c) Peter Norvig, 2010-18; See http://norvig.com/lispy.html +## Minor edits for Fluent Python, Second Edition (O'Reilly, 2021) +## by Luciano Ramalho, adding type hints and pattern matching. + + +################ Imports and Types + +import math +import operator as op +from collections import ChainMap +from itertools import chain +from typing import Any, Union, NoReturn + +Symbol = str +Atom = Union[float, int, Symbol] +Expression = Union[Atom, list] + + +################ Parsing: parse, tokenize, and read_from_tokens + +def parse(program: str) -> Expression: + "Read a Scheme expression from a string." + return read_from_tokens(tokenize(program)) + +def tokenize(s: str) -> list[str]: + "Convert a string into a list of tokens." + return s.replace('(', ' ( ').replace(')', ' ) ').split() + +def read_from_tokens(tokens: list[str]) -> Expression: + "Read an expression from a sequence of tokens." + if len(tokens) == 0: + raise SyntaxError('unexpected EOF while reading') + token = tokens.pop(0) + if '(' == token: + exp = [] + while tokens[0] != ')': + exp.append(read_from_tokens(tokens)) + tokens.pop(0) # discard ')' + return exp + elif ')' == token: + raise SyntaxError('unexpected )') + else: + return parse_atom(token) + +def parse_atom(token: str) -> Atom: + "Numbers become numbers; every other token is a symbol." + try: + return int(token) + except ValueError: + try: + return float(token) + except ValueError: + return Symbol(token) + + +################ Global Environment + +class Environment(ChainMap[Symbol, Any]): + "A ChainMap that allows changing an item in-place." + + def change(self, key: Symbol, value: object) -> None: + "Find where key is defined and change the value there." + for map in self.maps: + if key in map: + map[key] = value # type: ignore[index] + return + raise KeyError(key) + + +def standard_env() -> Environment: + "An environment with some Scheme standard procedures." + env = Environment() + env.update(vars(math)) # sin, cos, sqrt, pi, ... + env.update({ + '+': op.add, + '-': op.sub, + '*': op.mul, + '/': op.truediv, + '//': op.floordiv, + '>': op.gt, + '<': op.lt, + '>=': op.ge, + '<=': op.le, + '=': op.eq, + 'abs': abs, + 'append': lambda *args: list(chain(*args)), + 'apply': lambda proc, args: proc(*args), + 'begin': lambda *x: x[-1], + 'car': lambda x: x[0], + 'cdr': lambda x: x[1:], + 'cons': lambda x, y: [x] + y, + 'display': lambda x: print(lispstr(x)), + 'eq?': op.is_, + 'equal?': op.eq, + 'filter': lambda *args: list(filter(*args)), + 'length': len, + 'list': lambda *x: list(x), + 'list?': lambda x: isinstance(x, list), + 'map': lambda *args: list(map(*args)), + 'max': max, + 'min': min, + 'not': op.not_, + 'null?': lambda x: x == [], + 'number?': lambda x: isinstance(x, (int, float)), + 'procedure?': callable, + 'round': round, + 'symbol?': lambda x: isinstance(x, Symbol), + }) + return env + + +################ Interaction: A REPL + +def repl(prompt: str = 'lis.py> ') -> NoReturn: + "A prompt-read-eval-print loop." + global_env = standard_env() + while True: + ast = parse(input(prompt)) + val = evaluate(ast, global_env) + if val is not None: + print(lispstr(val)) + +def lispstr(exp: object) -> str: + "Convert a Python object back into a Lisp-readable string." + if isinstance(exp, list): + return '(' + ' '.join(map(lispstr, exp)) + ')' + else: + return str(exp) + + +################ Evaluator + +# tag::EVAL_IF_TOP[] +def evaluate(exp: Expression, env: Environment) -> Any: + "Evaluate an expression in an environment." + if isinstance(exp, Symbol): # variable reference + return env[exp] +# end::EVAL_IF_TOP[] + elif not isinstance(exp, list): # constant literal + return exp +# tag::EVAL_IF_MIDDLE[] + elif exp[0] == 'quote': # (quote exp) + (_, x) = exp + return x + elif exp[0] == 'if': # (if test conseq alt) + (_, test, consequence, alternative) = exp + if evaluate(test, env): + return evaluate(consequence, env) + else: + return evaluate(alternative, env) + elif exp[0] == 'lambda': # (lambda (parm…) body…) + (_, parms, *body) = exp + return Procedure(parms, body, env) + elif exp[0] == 'define': + (_, name, value_exp) = exp + env[name] = evaluate(value_exp, env) +# end::EVAL_IF_MIDDLE[] + elif exp[0] == 'set!': + (_, name, value_exp) = exp + env.change(name, evaluate(value_exp, env)) + else: # (proc arg…) + (func_exp, *args) = exp + proc = evaluate(func_exp, env) + args = [evaluate(arg, env) for arg in args] + return proc(*args) + + +class Procedure: + "A user-defined Scheme procedure." + + def __init__( + self, parms: list[Symbol], body: list[Expression], env: Environment + ): + self.parms = parms + self.body = body + self.env = env + + def __call__(self, *args: Expression) -> Any: + local_env = dict(zip(self.parms, args)) + env = Environment(local_env, self.env) + for exp in self.body: + result = evaluate(exp, env) + return result + + +################ command-line interface + +def run(source: str) -> Any: + global_env = standard_env() + tokens = tokenize(source) + while tokens: + exp = read_from_tokens(tokens) + result = evaluate(exp, global_env) + return result + +def main(args: list[str]) -> None: + if len(args) == 1: + with open(args[0]) as fp: + run(fp.read()) + else: + repl() + +if __name__ == '__main__': + import sys + main(sys.argv[1:]) diff --git a/02-array-seq/lispy/py3.9/lis_test.py b/02-array-seq/lispy/py3.9/lis_test.py new file mode 100644 index 0000000..64bafb4 --- /dev/null +++ b/02-array-seq/lispy/py3.9/lis_test.py @@ -0,0 +1,180 @@ +from typing import Optional + +from pytest import mark, fixture + +from lis import parse, evaluate, Expression, Environment, standard_env + +############################################################# tests for parse + +@mark.parametrize( 'source, expected', [ + ('7', 7), + ('x', 'x'), + ('(sum 1 2 3)', ['sum', 1, 2, 3]), + ('(+ (* 2 100) (* 1 10))', ['+', ['*', 2, 100], ['*', 1, 10]]), + ('99 100', 99), # parse stops at the first complete expression + ('(a)(b)', ['a']), +]) +def test_parse(source: str, expected: Expression) -> None: + got = parse(source) + assert got == expected + + +########################################################## tests for evaluate + +# Norvig's tests are not isolated: they assume the +# same environment from first to last test. +global_env_for_first_test = standard_env() + +@mark.parametrize( 'source, expected', [ + ("(quote (testing 1 (2.0) -3.14e159))", ['testing', 1, [2.0], -3.14e159]), + ("(+ 2 2)", 4), + ("(+ (* 2 100) (* 1 10))", 210), + ("(if (> 6 5) (+ 1 1) (+ 2 2))", 2), + ("(if (< 6 5) (+ 1 1) (+ 2 2))", 4), + ("(define x 3)", None), + ("x", 3), + ("(+ x x)", 6), + ("((lambda (x) (+ x x)) 5)", 10), + ("(define twice (lambda (x) (* 2 x)))", None), + ("(twice 5)", 10), + ("(define compose (lambda (f g) (lambda (x) (f (g x)))))", None), + ("((compose list twice) 5)", [10]), + ("(define repeat (lambda (f) (compose f f)))", None), + ("((repeat twice) 5)", 20), + ("((repeat (repeat twice)) 5)", 80), + ("(define fact (lambda (n) (if (<= n 1) 1 (* n (fact (- n 1))))))", None), + ("(fact 3)", 6), + ("(fact 50)", 30414093201713378043612608166064768844377641568960512000000000000), + ("(define abs (lambda (n) ((if (> n 0) + -) 0 n)))", None), + ("(list (abs -3) (abs 0) (abs 3))", [3, 0, 3]), + ("""(define combine (lambda (f) + (lambda (x y) + (if (null? x) (quote ()) + (f (list (car x) (car y)) + ((combine f) (cdr x) (cdr y)))))))""", None), + ("(define zip (combine cons))", None), + ("(zip (list 1 2 3 4) (list 5 6 7 8))", [[1, 5], [2, 6], [3, 7], [4, 8]]), + ("""(define riff-shuffle (lambda (deck) + (begin + (define take (lambda (n seq) (if (<= n 0) (quote ()) (cons (car seq) (take (- n 1) (cdr seq)))))) + (define drop (lambda (n seq) (if (<= n 0) seq (drop (- n 1) (cdr seq))))) + (define mid (lambda (seq) (/ (length seq) 2))) + ((combine append) (take (mid deck) deck) (drop (mid deck) deck)))))""", None), + ("(riff-shuffle (list 1 2 3 4 5 6 7 8))", [1, 5, 2, 6, 3, 7, 4, 8]), + ("((repeat riff-shuffle) (list 1 2 3 4 5 6 7 8))", [1, 3, 5, 7, 2, 4, 6, 8]), + ("(riff-shuffle (riff-shuffle (riff-shuffle (list 1 2 3 4 5 6 7 8))))", [1,2,3,4,5,6,7,8]), +]) +def test_evaluate(source: str, expected: Optional[Expression]) -> None: + got = evaluate(parse(source), global_env_for_first_test) + assert got == expected + + +@fixture +def std_env() -> Environment: + return standard_env() + +# tests for cases in evaluate + +def test_evaluate_variable() -> None: + env = Environment({'x': 10}) + source = 'x' + expected = 10 + got = evaluate(parse(source), env) + assert got == expected + + +def test_evaluate_literal(std_env: Environment) -> None: + source = '3.3' + expected = 3.3 + got = evaluate(parse(source), std_env) + assert got == expected + + +def test_evaluate_quote(std_env: Environment) -> None: + source = '(quote (1.1 is not 1))' + expected = [1.1, 'is', 'not', 1] + got = evaluate(parse(source), std_env) + assert got == expected + + +def test_evaluate_if_true(std_env: Environment) -> None: + source = '(if 1 10 no-such-thing)' + expected = 10 + got = evaluate(parse(source), std_env) + assert got == expected + + +def test_evaluate_if_false(std_env: Environment) -> None: + source = '(if 0 no-such-thing 20)' + expected = 20 + got = evaluate(parse(source), std_env) + assert got == expected + + +def test_define(std_env: Environment) -> None: + source = '(define answer (* 6 7))' + got = evaluate(parse(source), std_env) + assert got is None + assert std_env['answer'] == 42 + + +def test_lambda(std_env: Environment) -> None: + source = '(lambda (a b) (if (>= a b) a b))' + func = evaluate(parse(source), std_env) + assert func.parms == ['a', 'b'] + assert func.body == [['if', ['>=', 'a', 'b'], 'a', 'b']] + assert func.env is std_env + assert func(1, 2) == 2 + assert func(3, 2) == 3 + + +def test_begin(std_env: Environment) -> None: + source = """ + (begin + (define x (* 2 3)) + (* x 7) + ) + """ + got = evaluate(parse(source), std_env) + assert got == 42 + + +def test_invocation_builtin_car(std_env: Environment) -> None: + source = '(car (quote (11 22 33)))' + got = evaluate(parse(source), std_env) + assert got == 11 + + +def test_invocation_builtin_append(std_env: Environment) -> None: + source = '(append (quote (a b)) (quote (c d)))' + got = evaluate(parse(source), std_env) + assert got == ['a', 'b', 'c', 'd'] + + +def test_invocation_builtin_map(std_env: Environment) -> None: + source = '(map (lambda (x) (* x 2)) (quote (1 2 3))))' + got = evaluate(parse(source), std_env) + assert got == [2, 4, 6] + + +def test_invocation_user_procedure(std_env: Environment) -> None: + source = """ + (begin + (define max (lambda (a b) (if (>= a b) a b))) + (max 22 11) + ) + """ + got = evaluate(parse(source), std_env) + assert got == 22 + + +def test_define_function(std_env: Environment) -> None: + source = '(define max (lambda (a b) (if (>= a b) a b)))' + got = evaluate(parse(source), std_env) + assert got is None + max_fn = std_env['max'] + assert max_fn.parms == ['a', 'b'] + assert max_fn.body == [['if', ['>=', 'a', 'b'], 'a', 'b']] + assert max_fn.env is std_env + assert max_fn(1, 2) == 2 + assert max_fn(3, 2) == 3 diff --git a/18-with-match/lispy/py3.10/examples_test.py b/18-with-match/lispy/py3.10/examples_test.py index ed4b68a..ba6bd10 100644 --- a/18-with-match/lispy/py3.10/examples_test.py +++ b/18-with-match/lispy/py3.10/examples_test.py @@ -2,16 +2,12 @@ Doctests for `parse` -------------------- -# tag::PARSE_ATOM[] +# tag::PARSE[] >>> from lis import parse >>> parse('1.5') 1.5 >>> parse('ni!') 'ni!' - -# end::PARSE_ATOM[] - -# tag::PARSE_LIST[] >>> parse('(gcd 18 45)') ['gcd', 18, 45] >>> parse(''' @@ -21,15 +17,15 @@ ... ''') ['define', 'double', ['lambda', ['n'], ['*', 'n', 2]]] -# end::PARSE_LIST[] +# end::PARSE[] Doctest for `Environment` ------------------------- # tag::ENVIRONMENT[] >>> from lis import Environment ->>> outer_env = {'a': 0, 'b': 1} >>> inner_env = {'a': 2} +>>> outer_env = {'a': 0, 'b': 1} >>> env = Environment(inner_env, outer_env) >>> env['a'] = 111 # <1> >>> env['c'] = 222 @@ -64,11 +60,11 @@ # tag::EVAL_QUOTE[] ->>> evaluate(parse('(quote no-such-name)'), {}) +>>> evaluate(parse('(quote no-such-name)'), standard_env()) 'no-such-name' ->>> evaluate(parse('(quote (99 bottles of beer))'), {}) +>>> evaluate(parse('(quote (99 bottles of beer))'), standard_env()) [99, 'bottles', 'of', 'beer'] ->>> evaluate(parse('(quote (/ 10 0))'), {}) +>>> evaluate(parse('(quote (/ 10 0))'), standard_env()) ['/', 10, 0] # end::EVAL_QUOTE[] @@ -156,11 +152,12 @@ def test_factorial(): (if (= n 0) m (gcd n (mod m n)))) -(gcd 18 45) +(display (gcd 18 45)) """ -def test_gcd(): - got = run(gcd_src) - assert got == 9 +def test_gcd(capsys): + run(gcd_src) + captured = capsys.readouterr() + assert captured.out == '9\n' quicksort_src = """ @@ -216,7 +213,7 @@ def test_newton(): (define inc (make-adder 1)) (inc 99) """ -def test_newton(): +def test_closure(): got = run(closure_src) assert got == 100 @@ -228,13 +225,15 @@ def test_newton(): n) ) (define counter (make-counter)) -(counter) -(counter) -(counter) +(display (counter)) +(display (counter)) +(display (counter)) """ -def test_closure_with_change(): - got = run(closure_with_change_src) - assert got == 3 +def test_closure_with_change(capsys): + run(closure_with_change_src) + captured = capsys.readouterr() + assert captured.out == '1\n2\n3\n' + # tag::RUN_AVERAGER[] @@ -256,4 +255,4 @@ def test_closure_with_change(): def test_closure_averager(): got = run(closure_averager_src) assert got == 12.0 -# end::RUN_AVERAGER[] \ No newline at end of file +# end::RUN_AVERAGER[] diff --git a/18-with-match/lispy/py3.10/lis.py b/18-with-match/lispy/py3.10/lis.py index 4a5195c..e05ee9c 100755 --- a/18-with-match/lispy/py3.10/lis.py +++ b/18-with-match/lispy/py3.10/lis.py @@ -58,10 +58,11 @@ def parse_atom(token: str) -> Atom: except ValueError: return Symbol(token) + ################ Global Environment # tag::ENV_CLASS[] -class Environment(ChainMap): +class Environment(ChainMap[Symbol, Any]): "A ChainMap that allows changing an item in-place." def change(self, key: Symbol, value: object) -> None: @@ -73,7 +74,6 @@ def change(self, key: Symbol, value: object) -> None: raise KeyError(key) # end::ENV_CLASS[] - def standard_env() -> Environment: "An environment with some Scheme standard procedures." env = Environment() @@ -119,11 +119,11 @@ def standard_env() -> Environment: ################ Interaction: A REPL # tag::REPL[] -def repl() -> NoReturn: +def repl(prompt: str = 'lis.py> ') -> NoReturn: "A prompt-read-eval-print loop." global_env = standard_env() while True: - ast = parse(input('lis.py> ')) + ast = parse(input(prompt)) val = evaluate(ast, global_env) if val is not None: print(lispstr(val)) @@ -149,8 +149,6 @@ def evaluate(exp: Expression, env: Environment) -> Any: return x case Symbol(var): return env[var] - case []: - return [] case ['quote', x]: return x case ['if', test, consequence, alternative]: @@ -166,8 +164,8 @@ def evaluate(exp: Expression, env: Environment) -> Any: env[name] = Procedure(parms, body, env) case ['set!', Symbol(var), value_exp]: env.change(var, evaluate(value_exp, env)) - case [op, *args] if op not in KEYWORDS: - proc = evaluate(op, env) + case [func_exp, *args] if func_exp not in KEYWORDS: + proc = evaluate(func_exp, env) values = [evaluate(arg, env) for arg in args] return proc(*values) case _: diff --git a/18-with-match/lispy/py3.10/lis_test.py b/18-with-match/lispy/py3.10/lis_test.py index 3688888..03dc15c 100644 --- a/18-with-match/lispy/py3.10/lis_test.py +++ b/18-with-match/lispy/py3.10/lis_test.py @@ -73,10 +73,10 @@ def test_evaluate(source: str, expected: Optional[Expression]) -> None: def std_env() -> Environment: return standard_env() -# tests for each of the cases in evaluate +# tests for cases in evaluate def test_evaluate_variable() -> None: - env: Environment = dict(x=10) + env = Environment({'x': 10}) source = 'x' expected = 10 got = evaluate(parse(source), env) @@ -168,8 +168,6 @@ def test_invocation_user_procedure(std_env: Environment) -> None: assert got == 22 -###################################### for py3.10/lis.py only - def test_define_function(std_env: Environment) -> None: source = '(define (max a b) (if (>= a b) a b))' got = evaluate(parse(source), std_env) diff --git a/18-with-match/lispy/py3.9/examples_test.py b/18-with-match/lispy/py3.9/examples_test.py new file mode 100644 index 0000000..c632662 --- /dev/null +++ b/18-with-match/lispy/py3.9/examples_test.py @@ -0,0 +1,258 @@ +""" +Doctests for `parse` +-------------------- + +# tag::PARSE[] +>>> from lis import parse +>>> parse('1.5') +1.5 +>>> parse('ni!') +'ni!' +>>> parse('(gcd 18 45)') +['gcd', 18, 45] +>>> parse(''' +... (define double +... (lambda (n) +... (* n 2))) +... ''') +['define', 'double', ['lambda', ['n'], ['*', 'n', 2]]] + +# end::PARSE[] + +Doctest for `Environment` +------------------------- + +# tag::ENVIRONMENT[] +>>> from lis import Environment +>>> inner_env = {'a': 2} +>>> outer_env = {'a': 0, 'b': 1} +>>> env = Environment(inner_env, outer_env) +>>> env['a'] = 111 # <1> +>>> env['c'] = 222 +>>> env +Environment({'a': 111, 'c': 222}, {'a': 0, 'b': 1}) +>>> env.change('b', 333) # <2> +>>> env +Environment({'a': 111, 'c': 222}, {'a': 0, 'b': 333}) + +# end::ENVIRONMENT[] + +Doctests for `evaluate` +----------------------- + +# tag::EVAL_NUMBER[] +>>> from lis import parse, evaluate, standard_env +>>> evaluate(parse('1.5'), {}) +1.5 + +# end::EVAL_NUMBER[] + +# tag::EVAL_SYMBOL[] +>>> from lis import standard_env +>>> evaluate(parse('+'), standard_env()) + +>>> evaluate(parse('ni!'), standard_env()) +Traceback (most recent call last): + ... +KeyError: 'ni!' + +# end::EVAL_SYMBOL[] + + +# tag::EVAL_QUOTE[] +>>> evaluate(parse('(quote no-such-name)'), standard_env()) +'no-such-name' +>>> evaluate(parse('(quote (99 bottles of beer))'), standard_env()) +[99, 'bottles', 'of', 'beer'] +>>> evaluate(parse('(quote (/ 10 0))'), standard_env()) +['/', 10, 0] + +# end::EVAL_QUOTE[] + +# tag::EVAL_IF[] +>>> evaluate(parse('(if (= 3 3) 1 0))'), standard_env()) +1 +>>> evaluate(parse('(if (= 3 4) 1 0))'), standard_env()) +0 + +# end::EVAL_IF[] + + +# tag::EVAL_LAMBDA[] +>>> expr = '(lambda (a b) (* (/ a b) 100))' +>>> f = evaluate(parse(expr), standard_env()) +>>> f # doctest: +ELLIPSIS + +>>> f(15, 20) +75.0 + +# end::EVAL_LAMBDA[] + +# tag::EVAL_DEFINE[] +>>> global_env = standard_env() +>>> evaluate(parse('(define answer (* 7 6))'), global_env) +>>> global_env['answer'] +42 + +# end::EVAL_DEFINE[] + +# tag::EVAL_DEFUN[] +>>> global_env = standard_env() +>>> percent = '(define (% a b) (* (/ a b) 100))' +>>> evaluate(parse(percent), global_env) +>>> global_env['%'] # doctest: +ELLIPSIS + +>>> global_env['%'](170, 200) +85.0 + +# end::EVAL_DEFUN[] + +function call: + +# tag::EVAL_CALL[] +>>> evaluate(parse('(% (* 12 14) (- 500 100))'), global_env) +42.0 + +# end::EVAL_CALL[] + +# tag::EVAL_SYNTAX_ERROR[] +>>> evaluate(parse('(lambda is not like this)'), standard_env()) +Traceback (most recent call last): + ... +SyntaxError: (lambda is not like this) + +# end::EVAL_SYNTAX_ERROR[] + +""" + +import math + +from lis import run + + +fact_src = """ +(define (! n) + (if (< n 2) + 1 + (* n (! (- n 1))) + ) +) +(! 42) +""" +def test_factorial(): + got = run(fact_src) + assert got == 1405006117752879898543142606244511569936384000000000 + assert got == math.factorial(42) + + +gcd_src = """ +(define (mod m n) + (- m (* n (// m n)))) +(define (gcd m n) + (if (= n 0) + m + (gcd n (mod m n)))) +(display (gcd 18 45)) +""" +def test_gcd(capsys): + run(gcd_src) + captured = capsys.readouterr() + assert captured.out == '9\n' + + +quicksort_src = """ +(define (quicksort lst) + (if (null? lst) + lst + (begin + (define pivot (car lst)) + (define rest (cdr lst)) + (append + (quicksort + (filter (lambda (x) (< x pivot)) rest)) + (list pivot) + (quicksort + (filter (lambda (x) (>= x pivot)) rest))) + ) + ) +) +(quicksort (list 2 1 6 3 4 0 8 9 7 5)) +""" +def test_quicksort(): + got = run(quicksort_src) + assert got == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + + +# Example from Structure and Interpretation of Computer Programs +# https://mitpress.mit.edu/sites/default/files/sicp/full-text/sicp/book/node12.html + +newton_src = """ +(define (sqrt x) + (sqrt-iter 1.0 x)) +(define (sqrt-iter guess x) + (if (good-enough? guess x) + guess + (sqrt-iter (improve guess x) x))) +(define (good-enough? guess x) + (< (abs (- (* guess guess) x)) 0.001)) +(define (improve guess x) + (average guess (/ x guess))) +(define (average x y) + (/ (+ x y) 2)) +(sqrt 123454321) +""" +def test_newton(): + got = run(newton_src) + assert math.isclose(got, 11111) + + +closure_src = """ +(define (make-adder increment) + (lambda (x) (+ increment x)) +) +(define inc (make-adder 1)) +(inc 99) +""" +def test_closure(): + got = run(closure_src) + assert got == 100 + +closure_with_change_src = """ +(define (make-counter) + (define n 0) + (lambda () + (set! n (+ n 1)) + n) +) +(define counter (make-counter)) +(display (counter)) +(display (counter)) +(display (counter)) +""" +def test_closure_with_change(capsys): + run(closure_with_change_src) + captured = capsys.readouterr() + assert captured.out == '1\n2\n3\n' + + + +# tag::RUN_AVERAGER[] +closure_averager_src = """ +(define (make-averager) + (define count 0) + (define total 0) + (lambda (new-value) + (set! count (+ count 1)) + (set! total (+ total new-value)) + (/ total count) + ) +) +(define avg (make-averager)) +(avg 10) +(avg 11) +(avg 15) +""" +def test_closure_averager(): + got = run(closure_averager_src) + assert got == 12.0 +# end::RUN_AVERAGER[] \ No newline at end of file diff --git a/18-with-match/lispy/py3.9/lis.py b/18-with-match/lispy/py3.9/lis.py index 9e4dec1..e8881cd 100644 --- a/18-with-match/lispy/py3.9/lis.py +++ b/18-with-match/lispy/py3.9/lis.py @@ -1,73 +1,24 @@ +#!/usr/bin/env python + ################ Lispy: Scheme Interpreter in Python 3.9 ## (c) Peter Norvig, 2010-18; See http://norvig.com/lispy.html ## Minor edits for Fluent Python, Second Edition (O'Reilly, 2021) ## by Luciano Ramalho, adding type hints and pattern matching. + ################ Imports and Types import math import operator as op from collections import ChainMap -from collections.abc import MutableMapping, Iterator from itertools import chain -from typing import Any, Union +from typing import Any, Union, NoReturn Symbol = str Atom = Union[float, int, Symbol] Expression = Union[Atom, list] -Environment = MutableMapping[Symbol, object] - - -class Procedure: - "A user-defined Scheme procedure." - - def __init__(self, parms: list[Symbol], body: list[Expression], env: Environment): - self.parms = parms - self.body = body - self.env = env - - def __call__(self, *args: Expression) -> Any: - local_env = dict(zip(self.parms, args)) - env: Environment = ChainMap(local_env, self.env) - for exp in self.body: - result = evaluate(exp, env) - return result - - -################ Global Environment - -def standard_env() -> Environment: - "An environment with some Scheme standard procedures." - env: Environment = {} - env.update(vars(math)) # sin, cos, sqrt, pi, ... - env.update({ - '+':op.add, '-':op.sub, '*':op.mul, '/':op.truediv, - '>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq, - 'abs': abs, - 'append': op.add, - 'apply': lambda proc, args: proc(*args), - 'begin': lambda *x: x[-1], - 'car': lambda x: x[0], - 'cdr': lambda x: x[1:], - 'cons': lambda x,y: [x] + y, - 'eq?': op.is_, - 'equal?': op.eq, - 'length': len, - 'list': lambda *x: list(x), - 'list?': lambda x: isinstance(x,list), - 'map': lambda *args: list(map(*args)), - 'max': max, - 'min': min, - 'not': op.not_, - 'null?': lambda x: x == [], - 'number?': lambda x: isinstance(x, (int, float)), - 'procedure?': callable, - 'round': round, - 'symbol?': lambda x: isinstance(x, Symbol), - }) - return env ################ Parsing: parse, tokenize, and read_from_tokens @@ -75,12 +26,10 @@ def parse(program: str) -> Expression: "Read a Scheme expression from a string." return read_from_tokens(tokenize(program)) - def tokenize(s: str) -> list[str]: "Convert a string into a list of tokens." return s.replace('(', ' ( ').replace(')', ' ) ').split() - def read_from_tokens(tokens: list[str]) -> Expression: "Read an expression from a sequence of tokens." if len(tokens) == 0: @@ -97,7 +46,6 @@ def read_from_tokens(tokens: list[str]) -> Expression: else: return parse_atom(token) - def parse_atom(token: str) -> Atom: "Numbers become numbers; every other token is a symbol." try: @@ -109,17 +57,73 @@ def parse_atom(token: str) -> Atom: return Symbol(token) +################ Global Environment + +class Environment(ChainMap[Symbol, Any]): + "A ChainMap that allows changing an item in-place." + + def change(self, key: Symbol, value: object) -> None: + "Find where key is defined and change the value there." + for map in self.maps: + if key in map: + map[key] = value # type: ignore[index] + return + raise KeyError(key) + + +def standard_env() -> Environment: + "An environment with some Scheme standard procedures." + env = Environment() + env.update(vars(math)) # sin, cos, sqrt, pi, ... + env.update({ + '+': op.add, + '-': op.sub, + '*': op.mul, + '/': op.truediv, + '//': op.floordiv, + '>': op.gt, + '<': op.lt, + '>=': op.ge, + '<=': op.le, + '=': op.eq, + 'abs': abs, + 'append': lambda *args: list(chain(*args)), + 'apply': lambda proc, args: proc(*args), + 'begin': lambda *x: x[-1], + 'car': lambda x: x[0], + 'cdr': lambda x: x[1:], + 'cons': lambda x, y: [x] + y, + 'display': lambda x: print(lispstr(x)), + 'eq?': op.is_, + 'equal?': op.eq, + 'filter': lambda *args: list(filter(*args)), + 'length': len, + 'list': lambda *x: list(x), + 'list?': lambda x: isinstance(x, list), + 'map': lambda *args: list(map(*args)), + 'max': max, + 'min': min, + 'not': op.not_, + 'null?': lambda x: x == [], + 'number?': lambda x: isinstance(x, (int, float)), + 'procedure?': callable, + 'round': round, + 'symbol?': lambda x: isinstance(x, Symbol), + }) + return env + + ################ Interaction: A REPL -def repl(prompt: str = 'lis.py> ') -> None: +def repl(prompt: str = 'lis.py> ') -> NoReturn: "A prompt-read-eval-print loop." global_env = standard_env() while True: - val = evaluate(parse(input(prompt)), global_env) + ast = parse(input(prompt)) + val = evaluate(ast, global_env) if val is not None: print(lispstr(val)) - def lispstr(exp: object) -> str: "Convert a Python object back into a Lisp-readable string." if isinstance(exp, list): @@ -128,30 +132,81 @@ def lispstr(exp: object) -> str: return str(exp) -################ eval +################ Evaluator -def evaluate(x: Expression, env: Environment) -> Any: +def evaluate(exp: Expression, env: Environment) -> Any: "Evaluate an expression in an environment." - if isinstance(x, Symbol): # variable reference - return env[x] - elif not isinstance(x, list): # constant literal - return x - elif x[0] == 'quote': # (quote exp) - (_, exp) = x + if isinstance(exp, Symbol): # variable reference + return env[exp] + elif not isinstance(exp, list): # constant literal return exp - elif x[0] == 'if': # (if test conseq alt) - (_, test, consequence, alternative) = x + elif exp[0] == 'quote': # (quote exp) + (_, x) = exp + return x + elif exp[0] == 'if': # (if test conseq alt) + (_, test, consequence, alternative) = exp if evaluate(test, env): return evaluate(consequence, env) else: return evaluate(alternative, env) - elif x[0] == 'define': # (define name exp) - (_, name, exp) = x - env[name] = evaluate(exp, env) - elif x[0] == 'lambda': # (lambda (parm…) body) - (_, parms, *body) = x + elif exp[0] == 'lambda': # (lambda (parm…) body…) + (_, parms, *body) = exp + if not isinstance(parms, list): + raise SyntaxError(lispstr(exp)) return Procedure(parms, body, env) + elif exp[0] == 'define': + (_, name_exp, *rest) = exp + if isinstance(name_exp, Symbol): # (define name exp) + value_exp = rest[0] + env[name_exp] = evaluate(value_exp, env) + else: # (define (name parm…) body…) + name, *parms = name_exp + env[name] = Procedure(parms, rest, env) + elif exp[0] == 'set!': + (_, var, value_exp) = exp + env.change(var, evaluate(value_exp, env)) else: # (proc arg…) - proc = evaluate(x[0], env) - args = [evaluate(exp, env) for exp in x[1:]] + (func_exp, *args) = exp + proc = evaluate(func_exp, env) + args = [evaluate(arg, env) for arg in args] return proc(*args) + + +class Procedure: + "A user-defined Scheme procedure." + + def __init__( + self, parms: list[Symbol], body: list[Expression], env: Environment + ): + self.parms = parms + self.body = body + self.env = env + + def __call__(self, *args: Expression) -> Any: + local_env = dict(zip(self.parms, args)) + env = Environment(local_env, self.env) + for exp in self.body: + result = evaluate(exp, env) + return result + + +################ command-line interface + +def run(source: str) -> Any: + global_env = standard_env() + tokens = tokenize(source) + while tokens: + exp = read_from_tokens(tokens) + result = evaluate(exp, global_env) + return result + +def main(args: list[str]) -> None: + if len(args) == 1: + with open(args[0]) as fp: + run(fp.read()) + else: + repl() + +if __name__ == '__main__': + import sys + main(sys.argv[1:]) diff --git a/18-with-match/lispy/py3.9/lis_test.py b/18-with-match/lispy/py3.9/lis_test.py index 106ac24..03dc15c 100644 --- a/18-with-match/lispy/py3.9/lis_test.py +++ b/18-with-match/lispy/py3.9/lis_test.py @@ -1,8 +1,8 @@ -from typing import Any, Optional +from typing import Optional from pytest import mark, fixture -from lis import parse, evaluate, standard_env, Symbol, Environment, Expression +from lis import parse, evaluate, Expression, Environment, standard_env ############################################################# tests for parse @@ -73,10 +73,10 @@ def test_evaluate(source: str, expected: Optional[Expression]) -> None: def std_env() -> Environment: return standard_env() -# tests for each of the cases in evaluate +# tests for cases in evaluate def test_evaluate_variable() -> None: - env: Environment = dict(x=10) + env = Environment({'x': 10}) source = 'x' expected = 10 got = evaluate(parse(source), env) @@ -166,3 +166,15 @@ def test_invocation_user_procedure(std_env: Environment) -> None: """ got = evaluate(parse(source), std_env) assert got == 22 + + +def test_define_function(std_env: Environment) -> None: + source = '(define (max a b) (if (>= a b) a b))' + got = evaluate(parse(source), std_env) + assert got is None + max_fn = std_env['max'] + assert max_fn.parms == ['a', 'b'] + assert max_fn.body == [['if', ['>=', 'a', 'b'], 'a', 'b']] + assert max_fn.env is std_env + assert max_fn(1, 2) == 2 + assert max_fn(3, 2) == 3 diff --git a/18-with-match/mirror_gen.py b/18-with-match/mirror_gen.py index 6dfaf02..2758045 100644 --- a/18-with-match/mirror_gen.py +++ b/18-with-match/mirror_gen.py @@ -15,6 +15,9 @@ YKCOWREBBAJ >>> what 'JABBERWOCKY' + >>> print('back to normal') + back to normal + # end::MIRROR_GEN_DEMO_1[] diff --git a/22-dyn-attr-prop/doc_property.py b/22-dyn-attr-prop/doc_property.py index b1ba351..5b653ef 100644 --- a/22-dyn-attr-prop/doc_property.py +++ b/22-dyn-attr-prop/doc_property.py @@ -14,7 +14,7 @@ class Foo: @property def bar(self): - '''The bar attribute''' + """The bar attribute""" return self.__dict__['bar'] @bar.setter From ade9577a55f1337ee5ca2b85d40f8eafc161d648 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Mon, 20 Sep 2021 23:31:45 -0300 Subject: [PATCH 09/66] sync from Atlas --- 02-array-seq/lispy/py3.10/lis.py | 4 ++-- 02-array-seq/lispy/py3.9/lis.py | 4 ++-- 18-with-match/lispy/py3.10/examples_test.py | 1 - 18-with-match/lispy/py3.10/lis.py | 21 +++++++------------ 18-with-match/lispy/py3.9/lis.py | 4 ++-- .../primes/spinner_prime_async_nap.py | 15 ++++++------- 6 files changed, 21 insertions(+), 28 deletions(-) diff --git a/02-array-seq/lispy/py3.10/lis.py b/02-array-seq/lispy/py3.10/lis.py index cffb9a1..150fca7 100755 --- a/02-array-seq/lispy/py3.10/lis.py +++ b/02-array-seq/lispy/py3.10/lis.py @@ -122,7 +122,7 @@ def standard_env() -> Environment: # tag::REPL[] def repl(prompt: str = 'lis.py> ') -> NoReturn: "A prompt-read-eval-print loop." - global_env = standard_env() + global_env = Environment({}, standard_env()) while True: ast = parse(input(prompt)) val = evaluate(ast, global_env) @@ -200,7 +200,7 @@ def __call__(self, *args: Expression) -> Any: # <3> ################ command-line interface def run(source: str) -> Any: - global_env = standard_env() + global_env = Environment({}, standard_env()) tokens = tokenize(source) while tokens: exp = read_from_tokens(tokens) diff --git a/02-array-seq/lispy/py3.9/lis.py b/02-array-seq/lispy/py3.9/lis.py index 843d4cc..201b41e 100644 --- a/02-array-seq/lispy/py3.9/lis.py +++ b/02-array-seq/lispy/py3.9/lis.py @@ -117,7 +117,7 @@ def standard_env() -> Environment: def repl(prompt: str = 'lis.py> ') -> NoReturn: "A prompt-read-eval-print loop." - global_env = standard_env() + global_env = Environment({}, standard_env()) while True: ast = parse(input(prompt)) val = evaluate(ast, global_env) @@ -190,7 +190,7 @@ def __call__(self, *args: Expression) -> Any: ################ command-line interface def run(source: str) -> Any: - global_env = standard_env() + global_env = Environment({}, standard_env()) tokens = tokenize(source) while tokens: exp = read_from_tokens(tokens) diff --git a/18-with-match/lispy/py3.10/examples_test.py b/18-with-match/lispy/py3.10/examples_test.py index ba6bd10..2807596 100644 --- a/18-with-match/lispy/py3.10/examples_test.py +++ b/18-with-match/lispy/py3.10/examples_test.py @@ -48,7 +48,6 @@ # end::EVAL_NUMBER[] # tag::EVAL_SYMBOL[] ->>> from lis import standard_env >>> evaluate(parse('+'), standard_env()) >>> evaluate(parse('ni!'), standard_env()) diff --git a/18-with-match/lispy/py3.10/lis.py b/18-with-match/lispy/py3.10/lis.py index 0feeadc..30ad8a8 100755 --- a/18-with-match/lispy/py3.10/lis.py +++ b/18-with-match/lispy/py3.10/lis.py @@ -121,7 +121,7 @@ def standard_env() -> Environment: # tag::REPL[] def repl(prompt: str = 'lis.py> ') -> NoReturn: "A prompt-read-eval-print loop." - global_env = standard_env() + global_env = Environment({}, standard_env()) while True: ast = parse(input(prompt)) val = evaluate(ast, global_env) @@ -140,10 +140,7 @@ def lispstr(exp: object) -> str: ################ Evaluator # tag::EVALUATE[] -KEYWORDS = {'quote', 'if', 'lambda', 'define', 'set!'} - -def is_keyword(s: Any) -> bool: - return isinstance(s, Symbol) and s in KEYWORDS +KEYWORDS = ['quote', 'if', 'lambda', 'define', 'set!'] def evaluate(exp: Expression, env: Environment) -> Any: "Evaluate an expression in an environment." @@ -161,17 +158,13 @@ def evaluate(exp: Expression, env: Environment) -> Any: return evaluate(alternative, env) case ['lambda', [*parms], *body] if body: return Procedure(parms, body, env) - case ['define', Symbol(var), value_exp]: - env[var] = evaluate(value_exp, env) + case ['define', Symbol(name), value_exp]: + env[name] = evaluate(value_exp, env) case ['define', [Symbol(name), *parms], *body] if body: env[name] = Procedure(parms, body, env) - case ['set!', Symbol(var), value_exp]: - env.change(var, evaluate(value_exp, env)) -<<<<<<< HEAD + case ['set!', Symbol(name), value_exp]: + env.change(name, evaluate(value_exp, env)) case [func_exp, *args] if func_exp not in KEYWORDS: -======= - case [func_exp, *args] if not is_keyword(func_exp): ->>>>>>> 3ecfb212c6273122797c76876d6b373b2cb94fa6 proc = evaluate(func_exp, env) values = [evaluate(arg, env) for arg in args] return proc(*values) @@ -202,7 +195,7 @@ def __call__(self, *args: Expression) -> Any: # <3> ################ command-line interface def run(source: str) -> Any: - global_env = standard_env() + global_env = Environment({}, standard_env()) tokens = tokenize(source) while tokens: exp = read_from_tokens(tokens) diff --git a/18-with-match/lispy/py3.9/lis.py b/18-with-match/lispy/py3.9/lis.py index e8881cd..6ab8a19 100644 --- a/18-with-match/lispy/py3.9/lis.py +++ b/18-with-match/lispy/py3.9/lis.py @@ -117,7 +117,7 @@ def standard_env() -> Environment: def repl(prompt: str = 'lis.py> ') -> NoReturn: "A prompt-read-eval-print loop." - global_env = standard_env() + global_env = Environment({}, standard_env()) while True: ast = parse(input(prompt)) val = evaluate(ast, global_env) @@ -193,7 +193,7 @@ def __call__(self, *args: Expression) -> Any: ################ command-line interface def run(source: str) -> Any: - global_env = standard_env() + global_env = Environment({}, standard_env()) tokens = tokenize(source) while tokens: exp = read_from_tokens(tokens) diff --git a/19-concurrency/primes/spinner_prime_async_nap.py b/19-concurrency/primes/spinner_prime_async_nap.py index 4d6fa47..b6e6518 100644 --- a/19-concurrency/primes/spinner_prime_async_nap.py +++ b/19-concurrency/primes/spinner_prime_async_nap.py @@ -7,6 +7,7 @@ import asyncio import itertools import math +import functools # tag::PRIME_NAP[] async def is_prime(n): @@ -21,8 +22,8 @@ async def is_prime(n): for i in range(3, root + 1, 2): if n % i == 0: return False - if i % 100_000 == 1: # <2> - await asyncio.sleep(0) + if i % 100_000 == 1: + await asyncio.sleep(0) # <1> return True # end::PRIME_NAP[] @@ -39,13 +40,13 @@ async def spin(msg: str) -> None: print(f'\r{blanks}\r', end='') async def check(n: int) -> int: - return await is_prime(n) # <4> + return await is_prime(n) async def supervisor(n: int) -> int: - spinner = asyncio.create_task(spin('thinking!')) # <1> - print('spinner object:', spinner) # <2> - result = await check(n) # <3> - spinner.cancel() # <5> + spinner = asyncio.create_task(spin('thinking!')) + print('spinner object:', spinner) + result = await check(n) + spinner.cancel() return result def main() -> None: From 2c1230579db99738a5e5e6802063bda585f6476d Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Tue, 21 Sep 2021 18:03:34 -0300 Subject: [PATCH 10/66] ch19: fixed race condition in procs.py --- 19-concurrency/primes/procs.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/19-concurrency/primes/procs.py b/19-concurrency/primes/procs.py index fc84049..8624958 100644 --- a/19-concurrency/primes/procs.py +++ b/19-concurrency/primes/procs.py @@ -30,6 +30,7 @@ def check(n: int) -> PrimeResult: # <6> def worker(jobs: JobQueue, results: ResultQueue) -> None: # <7> while n := jobs.get(): # <8> results.put(check(n)) # <9> + results.put(PrimeResult(0, False, 0.0)) # <10> # end::PRIMES_PROC_TOP[] # tag::PRIMES_PROC_MAIN[] @@ -53,15 +54,19 @@ def main() -> None: proc.start() # <5> jobs.put(0) # <6> - while True: - n, prime, elapsed = results.get() # <7> - label = 'P' if prime else ' ' - print(f'{n:16} {label} {elapsed:9.6f}s') # <8> - if jobs.empty(): # <9> - break + workers_done = 0 + checked = 0 + while workers_done < workers: # <7> + n, prime, elapsed = results.get() # <8> + if n == 0: + workers_done += 1 # <9> + else: + checked += 1 + label = 'P' if prime else ' ' + print(f'{n:16} {label} {elapsed:9.6f}s') # <10> elapsed = perf_counter() - t0 - print(f'Total time: {elapsed:.2f}s') + print(f'{checked} checks in {elapsed:.2f}s') # <11> if __name__ == '__main__': main() From 4f4f759229cca84b10170809607849f463891358 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Tue, 21 Sep 2021 23:31:27 -0300 Subject: [PATCH 11/66] sync from Atlas --- 18-with-match/lispy/py3.10/lis.py | 2 +- 19-concurrency/primes/procs.py | 54 +++++++++++++------------ 19-concurrency/primes/threads.py | 66 +++++++++++++++++-------------- 3 files changed, 67 insertions(+), 55 deletions(-) diff --git a/18-with-match/lispy/py3.10/lis.py b/18-with-match/lispy/py3.10/lis.py index 30ad8a8..0faf6d2 100755 --- a/18-with-match/lispy/py3.10/lis.py +++ b/18-with-match/lispy/py3.10/lis.py @@ -69,7 +69,7 @@ def change(self, key: Symbol, value: object) -> None: "Find where key is defined and change the value there." for map in self.maps: if key in map: - map[key] = value + map[key] = value # type: ignore[index] return raise KeyError(key) # end::ENV_CLASS[] diff --git a/19-concurrency/primes/procs.py b/19-concurrency/primes/procs.py index 8624958..09f75e3 100644 --- a/19-concurrency/primes/procs.py +++ b/19-concurrency/primes/procs.py @@ -33,40 +33,44 @@ def worker(jobs: JobQueue, results: ResultQueue) -> None: # <7> results.put(PrimeResult(0, False, 0.0)) # <10> # end::PRIMES_PROC_TOP[] -# tag::PRIMES_PROC_MAIN[] -def main() -> None: - if len(sys.argv) < 2: # <1> - workers = cpu_count() - else: - workers = int(sys.argv[1]) - - print(f'Checking {len(NUMBERS)} numbers with {workers} processes:') - - jobs: JobQueue = SimpleQueue() # <2> - results: ResultQueue = SimpleQueue() - t0 = perf_counter() - - for n in NUMBERS: # <3> - jobs.put(n) - +# tag::PRIMES_PROC_MIDDLE[] +def start_jobs(workers: int, jobs: JobQueue, results: ResultQueue) -> None: + for n in NUMBERS: + jobs.put(n) # <1> for _ in range(workers): - proc = Process(target=worker, args=(jobs, results)) # <4> - proc.start() # <5> - jobs.put(0) # <6> + proc = Process(target=worker, args=(jobs, results)) # <2> + proc.start() # <3> + jobs.put(0) # <4> - workers_done = 0 +def report(workers: int, results: ResultQueue) -> int: checked = 0 - while workers_done < workers: # <7> - n, prime, elapsed = results.get() # <8> + workers_done = 0 + while workers_done < workers: + n, prime, elapsed = results.get() if n == 0: - workers_done += 1 # <9> + workers_done += 1 else: checked += 1 label = 'P' if prime else ' ' - print(f'{n:16} {label} {elapsed:9.6f}s') # <10> + print(f'{n:16} {label} {elapsed:9.6f}s') + return checked +# end::PRIMES_PROC_MIDDLE[] +# tag::PRIMES_PROC_MAIN[] +def main() -> None: + if len(sys.argv) < 2: + workers = cpu_count() + else: + workers = int(sys.argv[1]) + + print(f'Checking {len(NUMBERS)} numbers with {workers} processes:') + t0 = perf_counter() + jobs: JobQueue = SimpleQueue() + results: ResultQueue = SimpleQueue() + start_jobs(workers, jobs, results) + checked = report(workers, results) elapsed = perf_counter() - t0 - print(f'{checked} checks in {elapsed:.2f}s') # <11> + print(f'{checked} checks in {elapsed:.2f}s') if __name__ == '__main__': main() diff --git a/19-concurrency/primes/threads.py b/19-concurrency/primes/threads.py index 0161dd7..ea00bbe 100644 --- a/19-concurrency/primes/threads.py +++ b/19-concurrency/primes/threads.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 """ -threads.py: shows that Python threads are slower than -sequential code for CPU-intensive work. +threads.py: shows that Python threads are slower +than sequential code for CPU-intensive work. """ import os @@ -14,52 +14,60 @@ from primes import is_prime, NUMBERS -class PrimeResult(NamedTuple): # <3> +class PrimeResult(NamedTuple): n: int prime: bool elapsed: float -JobQueue = SimpleQueue[int] -ResultQueue = SimpleQueue[PrimeResult] +JobQueue = SimpleQueue[int] # <4> +ResultQueue = SimpleQueue[PrimeResult] # <5> -def check(n: int) -> PrimeResult: +def check(n: int) -> PrimeResult: # <6> t0 = perf_counter() res = is_prime(n) return PrimeResult(n, res, perf_counter() - t0) -def worker(jobs: JobQueue, results: ResultQueue) -> None: - while n := jobs.get(): - results.put(check(n)) - -def main() -> None: - if len(sys.argv) < 2: # <1> - workers = os.cpu_count() or 1 # make mypy happy - else: - workers = int(sys.argv[1]) - - print(f'Checking {len(NUMBERS)} numbers with {workers} threads:') - - jobs: JobQueue = SimpleQueue() # <2> - results: ResultQueue = SimpleQueue() - t0 = perf_counter() +def worker(jobs: JobQueue, results: ResultQueue) -> None: # <7> + while n := jobs.get(): # <8> + results.put(check(n)) # <9> + results.put(PrimeResult(0, False, 0.0)) +def start_jobs(workers: int, jobs: JobQueue, results: ResultQueue) -> None: for n in NUMBERS: # <3> jobs.put(n) - for _ in range(workers): proc = Thread(target=worker, args=(jobs, results)) # <4> proc.start() # <5> jobs.put(0) # <6> - while True: - n, prime, elapsed = results.get() # <7> - label = 'P' if prime else ' ' - print(f'{n:16} {label} {elapsed:9.6f}s') - if jobs.empty(): # <8> - break +def report(workers: int, results: ResultQueue) -> int: + checked = 0 + workers_done = 0 + while workers_done < workers: + n, prime, elapsed = results.get() + if n == 0: + workers_done += 1 + else: + checked += 1 + label = 'P' if prime else ' ' + print(f'{n:16} {label} {elapsed:9.6f}s') + return checked + +def main() -> None: + if len(sys.argv) < 2: + workers = os.cpu_count() + else: + workers = int(sys.argv[1]) + print(f'Checking {len(NUMBERS)} numbers with {workers} threads:') + t0 = perf_counter() + jobs: JobQueue = SimpleQueue() + results: ResultQueue = SimpleQueue() + start_jobs(workers, jobs, results) + checked = report(workers, results) elapsed = perf_counter() - t0 - print(f'Total time: {elapsed:.2f}s') + print(f'{checked} checks in {elapsed:.2f}s') if __name__ == '__main__': main() + From 4fad21e6b0434d814fab582440a44add48456f04 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Thu, 23 Sep 2021 03:07:15 -0300 Subject: [PATCH 12/66] added README.md to 19-concurrency/primes/ --- 19-concurrency/primes/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 19-concurrency/primes/README.md diff --git a/19-concurrency/primes/README.md b/19-concurrency/primes/README.md new file mode 100644 index 0000000..772592a --- /dev/null +++ b/19-concurrency/primes/README.md @@ -0,0 +1,16 @@ +# Race condition in orignal procs.py + +Thanks to reader Michael Albert who noticed the code I published during the Early Release had a race condition in `proc.py`. + +If you are curious, +[this diff](https://github.com/fluentpython/example-code-2e/commit/2c1230579db99738a5e5e6802063bda585f6476d) +shows the bug and how I fixed it—but note that I later refactored +the example to delegate parts of `main` to the `start_jobs` and `report` functions. + +The problem was that I ended the `while` loop that retrieved the results when the `jobs` queue was empty. +However, it was possible that the queue was empty but there were still processes working. +If that happened, one or more results would not be reported. +I did not notice the problem when I tested my original code, +but Albert showed that adding a `sleep(1)` call before the `if jobs.empty()` line made the bug occur frequently. +I adopted one of his solutions: have the `worker` function send back a `PrimeResult` with `n = 0` as a sentinel, +to let the main loop know that the process had completed, ending the loop when all processes were done. \ No newline at end of file From 4002c57728bd5b4874b320ca91284697f708743c Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Mon, 27 Sep 2021 15:05:01 -0300 Subject: [PATCH 13/66] added README.adoc --- 20-futures/getflags/README.adoc | 72 +++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 20-futures/getflags/README.adoc diff --git a/20-futures/getflags/README.adoc b/20-futures/getflags/README.adoc new file mode 100644 index 0000000..14ecec4 --- /dev/null +++ b/20-futures/getflags/README.adoc @@ -0,0 +1,72 @@ += Running the flags2* examples + +== Setting up a test server + +If you don't already have a local HTTP server for testing, +here are the steps to experiment using only Python ≥ 3.9—no external libraries: + +. Clone or download the https://github.com/fluentpython/example-code-2e[_Fluent Python 2e_ code repository]. +. Open your shell and go to the _20-futures/getflags/_ directory of your local copy of the repository. +. Unzip the _flags.zip_ file, creating a _flags_ directory at _20-futures/getflags/flags/_. +. Open a second shell, go to the _20-futures/getflags/_ directory and run `python3 -m http.server`. This will start a `ThreadingHTTPServer` listening to port 8000, serving the local files. If you open the URL http://localhost:8000/flags/[http://localhost:8000/flags/] with your browser, you'll see a long list of directories named with two-letter country codes from `ad/` to `zw/`. +. Now you can go back to the first shell and run the _flags2*.py_ examples with the default `--server LOCAL` option. +. To test with the `--server DELAY` option, go to _20-futures/getflags/_ and run `python3 slow_server.py 8001`. This will add a .5s delay before each response. +. To test with the `--server ERROR` option, go to _20-futures/getflags/_ and run `python3 slow_server.py 8002 --error-rate .25`. Each request will have a 25% probability of getting a https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/418[418 I'm a teapot] response, and all responses will be delayed .5s. + +I wrote _slow_server.py_ reusing code from Python's +https://github.com/python/cpython/blob/917eca700aa341f8544ace43b75d41b477e98b72/Lib/http/server.py[`http.server`] standard library module, +which "is not recommended for production"—according to the +https://docs.python.org/3/library/http.server.html[documentation]. +To set up a more reliable testing environment, I recommend configuring +https://www.nginx.com/[NGINX] and +https://github.com/shopify/toxiproxy[Toxiproxy] with equivalent parameters. + +== Running a flags2* example + +The `flags2*` examples provide a command-line interface. +All three scripts accept the same options, +and you can see them by running any of the scripts with the `-h` option. +<> shows the help text. + +[[flags2_help_demo]] +.Help screen for the scripts in the flags2 series +==== +[source, text] +---- +$ python3 flags2_threadpool.py -h +usage: flags2_threadpool.py [-h] [-a] [-e] [-l N] [-m CONCURRENT] [-s LABEL] + [-v] + [CC [CC ...]] + +Download flags for country codes. Default: top 20 countries by population. + +positional arguments: + CC country code or 1st letter (eg. B for BA...BZ) + +optional arguments: + -h, --help show this help message and exit + -a, --all get all available flags (AD to ZW) + -e, --every get flags for every possible code (AA...ZZ) + -l N, --limit N limit to N first codes + -m CONCURRENT, --max_req CONCURRENT + maximum concurrent requests (default=30) + -s LABEL, --server LABEL + Server to hit; one of DELAY, ERROR, LOCAL, REMOTE + (default=LOCAL) + -v, --verbose output detailed progress info + +---- +==== + +All arguments are optional. The most important arguments are discussed next. + +One option you can't ignore is `-s/--server`: it lets you choose which HTTP server and base URL will be used in the test. You can pass one of four strings to determine where the script will look for the flags (the strings are case insensitive): + +`LOCAL`:: Use `http://localhost:8000/flags`; this is the default. You should configure a local HTTP server to answer at port 8000. See <> for instructions. + +`REMOTE`:: Use `http://fluentpython.com/data/flags`; that is a public website owned by me, hosted on a shared server. Please do not pound it with too many concurrent requests. The `fluentpython.com` domain is handled by the http://www.cloudflare.com/[Cloudflare] CDN (Content Delivery Network) so you may notice that the first downloads are slower, but they get faster when the CDN cache warms up.footnote:[Before configuring Cloudflare, I got HTTP 503 errors--Service Temporarily Unavailable--when testing the scripts with a few dozen concurrent requests on my inexpensive shared host account. Now those errors are gone.] + +`DELAY`:: Use `http://localhost:8001/flags`; a server delaying HTTP responses should be listening to port 8001. I wrote _slow_server.py_ to make it easier to experiment. You'll find it in the _20-futures/getflags/_ directory of the https://github.com/fluentpython/example-code-2e[_Fluent Python 2e_ code repository]. See <> for instructions. + +`ERROR`:: Use `http://localhost:8002/flags`; a server introducing HTTP errors and delaying responses should be installed at port 8002. Running _slow_server.py_ is an easy way to do it. See <>. + From f7bf5b0d2ad4fb0f5156bc2bb7ca43991fc6719a Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Mon, 27 Sep 2021 15:06:49 -0300 Subject: [PATCH 14/66] added README.adoc --- 20-futures/getflags/README.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/20-futures/getflags/README.adoc b/20-futures/getflags/README.adoc index 14ecec4..38cf3df 100644 --- a/20-futures/getflags/README.adoc +++ b/20-futures/getflags/README.adoc @@ -1,4 +1,4 @@ -= Running the flags2* examples += Experimenting with the `flags2*` examples == Setting up a test server @@ -21,7 +21,7 @@ To set up a more reliable testing environment, I recommend configuring https://www.nginx.com/[NGINX] and https://github.com/shopify/toxiproxy[Toxiproxy] with equivalent parameters. -== Running a flags2* example +== Running a `flags2*` script The `flags2*` examples provide a command-line interface. All three scripts accept the same options, From 1e5940056e21b350f2601e5df3f0b24b829d351c Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Mon, 27 Sep 2021 19:35:38 -0300 Subject: [PATCH 15/66] ch20: README.adoc --- 20-futures/getflags/README.adoc | 38 +++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/20-futures/getflags/README.adoc b/20-futures/getflags/README.adoc index 38cf3df..ed0b5e9 100644 --- a/20-futures/getflags/README.adoc +++ b/20-futures/getflags/README.adoc @@ -1,25 +1,51 @@ = Experimenting with the `flags2*` examples +== Install SSL Certificates (for MacOS) + +On Macos, depending on how in installed Python you may need to manually run a command +after Python's installer finishes, to install SSL certificates for HTTPS connections. + +Using the Finder, open the `Python 3.X` folder inside `/Applications` folder +and double-click "Install Certificates" or "Install Certificates.command". + +Using the terminal, you can type for example: + +[source, text] +---- +$ open /Applications/Python 3.10/"Install Certificates.command" +---- + + == Setting up a test server If you don't already have a local HTTP server for testing, -here are the steps to experiment using only Python ≥ 3.9—no external libraries: +here are the steps to experiment using only Python ≥ 3.9: -. Clone or download the https://github.com/fluentpython/example-code-2e[_Fluent Python 2e_ code repository]. -. Open your shell and go to the _20-futures/getflags/_ directory of your local copy of the repository. +. Clone or download the https://github.com/fluentpython/example-code-2e[_Fluent Python 2e_ code repository] (this repo!). +. Open your shell and go to the _20-futures/getflags/_ directory of your local copy of the repository (this directory!) . Unzip the _flags.zip_ file, creating a _flags_ directory at _20-futures/getflags/flags/_. . Open a second shell, go to the _20-futures/getflags/_ directory and run `python3 -m http.server`. This will start a `ThreadingHTTPServer` listening to port 8000, serving the local files. If you open the URL http://localhost:8000/flags/[http://localhost:8000/flags/] with your browser, you'll see a long list of directories named with two-letter country codes from `ad/` to `zw/`. . Now you can go back to the first shell and run the _flags2*.py_ examples with the default `--server LOCAL` option. -. To test with the `--server DELAY` option, go to _20-futures/getflags/_ and run `python3 slow_server.py 8001`. This will add a .5s delay before each response. -. To test with the `--server ERROR` option, go to _20-futures/getflags/_ and run `python3 slow_server.py 8002 --error-rate .25`. Each request will have a 25% probability of getting a https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/418[418 I'm a teapot] response, and all responses will be delayed .5s. +. To test with the `--server DELAY` option, go to _20-futures/getflags/_ and run `python3 slow_server.py`. This bind to port 8001 by default. It will add a .5s delay before each response. +. To test with the `--server ERROR` option, go to _20-futures/getflags/_ and run `python3 slow_server.py 8002 --error-rate .25`. +Each request will have a 25% probability of getting a +https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/418[418 I'm a teapot] response, +and all responses will be delayed .5s. I wrote _slow_server.py_ reusing code from Python's https://github.com/python/cpython/blob/917eca700aa341f8544ace43b75d41b477e98b72/Lib/http/server.py[`http.server`] standard library module, which "is not recommended for production"—according to the https://docs.python.org/3/library/http.server.html[documentation]. -To set up a more reliable testing environment, I recommend configuring + +[NOTE] +==== +This is a simple testing environment that does nor require any external libraries or +tools—apart from the libraries used in the `flags2*` scripts themselves, as discussed in the book. + +For a more robust testing environment, I recommend configuring https://www.nginx.com/[NGINX] and https://github.com/shopify/toxiproxy[Toxiproxy] with equivalent parameters. +==== == Running a `flags2*` script From f45806361f7f7d958c6a61dfb62c04bfb39e8c60 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Mon, 27 Sep 2021 19:46:25 -0300 Subject: [PATCH 16/66] ch20: README.adoc --- 20-futures/getflags/README.adoc | 55 +++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/20-futures/getflags/README.adoc b/20-futures/getflags/README.adoc index ed0b5e9..b744c15 100644 --- a/20-futures/getflags/README.adoc +++ b/20-futures/getflags/README.adoc @@ -1,25 +1,25 @@ = Experimenting with the `flags2*` examples -== Install SSL Certificates (for MacOS) +The `flags2*` examples enhance the `flags*` examples with error handling and reporting. +Therefore, we need a server that generates errors and delays to test them. -On Macos, depending on how in installed Python you may need to manually run a command -after Python's installer finishes, to install SSL certificates for HTTPS connections. +The main reason for these instructions is to document how to configure one such server +in your machine, and how to run the clients to use it. -Using the Finder, open the `Python 3.X` folder inside `/Applications` folder -and double-click "Install Certificates" or "Install Certificates.command". +The other reason is to alert of an installation step that MacOS users sometimes overlook. -Using the terminal, you can type for example: - -[source, text] ----- -$ open /Applications/Python 3.10/"Install Certificates.command" ----- +Contents: +* <> +* <> +* <> +[[server_setup]] == Setting up a test server If you don't already have a local HTTP server for testing, -here are the steps to experiment using only Python ≥ 3.9: +here are the steps to experiment with the `flags2*` examples +using just the Python ≥ 3.9 distribution and . Clone or download the https://github.com/fluentpython/example-code-2e[_Fluent Python 2e_ code repository] (this repo!). . Open your shell and go to the _20-futures/getflags/_ directory of your local copy of the repository (this directory!) @@ -39,7 +39,7 @@ https://docs.python.org/3/library/http.server.html[documentation]. [NOTE] ==== -This is a simple testing environment that does nor require any external libraries or +This is a simple testing environment that does not require any external libraries or tools—apart from the libraries used in the `flags2*` scripts themselves, as discussed in the book. For a more robust testing environment, I recommend configuring @@ -47,6 +47,7 @@ https://www.nginx.com/[NGINX] and https://github.com/shopify/toxiproxy[Toxiproxy] with equivalent parameters. ==== +[[client_setup]] == Running a `flags2*` script The `flags2*` examples provide a command-line interface. @@ -86,13 +87,35 @@ optional arguments: All arguments are optional. The most important arguments are discussed next. -One option you can't ignore is `-s/--server`: it lets you choose which HTTP server and base URL will be used in the test. You can pass one of four strings to determine where the script will look for the flags (the strings are case insensitive): +One option you can't ignore is `-s/--server`: it lets you choose which HTTP server and base URL will be used in the test. +You can pass one of four strings to determine where the script will look for the flags (the strings are case insensitive): -`LOCAL`:: Use `http://localhost:8000/flags`; this is the default. You should configure a local HTTP server to answer at port 8000. See <> for instructions. +`LOCAL`:: Use `http://localhost:8000/flags`; this is the default. +You should configure a local HTTP server to answer at port 8000. See <> for instructions. -`REMOTE`:: Use `http://fluentpython.com/data/flags`; that is a public website owned by me, hosted on a shared server. Please do not pound it with too many concurrent requests. The `fluentpython.com` domain is handled by the http://www.cloudflare.com/[Cloudflare] CDN (Content Delivery Network) so you may notice that the first downloads are slower, but they get faster when the CDN cache warms up.footnote:[Before configuring Cloudflare, I got HTTP 503 errors--Service Temporarily Unavailable--when testing the scripts with a few dozen concurrent requests on my inexpensive shared host account. Now those errors are gone.] +`REMOTE`:: Use `http://fluentpython.com/data/flags`; that is a public website owned by me, hosted on a shared server. +Please do not pound it with too many concurrent requests. +The `fluentpython.com` domain is handled by the http://www.cloudflare.com/[Cloudflare] CDN (Content Delivery Network) +so you may notice that the first downloads are slower, but they get faster when the CDN cache warms +up.footnote:[Before configuring Cloudflare, I got HTTP 503 errors--Service Temporarily Unavailable--when +testing the scripts with a few dozen concurrent requests on my inexpensive shared host account. Now those errors are gone.] `DELAY`:: Use `http://localhost:8001/flags`; a server delaying HTTP responses should be listening to port 8001. I wrote _slow_server.py_ to make it easier to experiment. You'll find it in the _20-futures/getflags/_ directory of the https://github.com/fluentpython/example-code-2e[_Fluent Python 2e_ code repository]. See <> for instructions. `ERROR`:: Use `http://localhost:8002/flags`; a server introducing HTTP errors and delaying responses should be installed at port 8002. Running _slow_server.py_ is an easy way to do it. See <>. +[[macos_certificates]] +== Install SSL Certificates (for MacOS) + +On Macos, depending on how in installed Python you may need to manually run a command +after Python's installer finishes, to install SSL certificates for HTTPS connections. + +Using the Finder, open the `Python 3.X` folder inside `/Applications` folder +and double-click "Install Certificates" or "Install Certificates.command". + +Using the terminal, you can type for example: + +[source, text] +---- +$ open /Applications/Python 3.10/"Install Certificates.command" +---- From 69f326dd3dfef93565a185ee9daa9cbf9a69d09a Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Mon, 27 Sep 2021 19:55:48 -0300 Subject: [PATCH 17/66] ch20: README.adoc --- 20-futures/getflags/README.adoc | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/20-futures/getflags/README.adoc b/20-futures/getflags/README.adoc index b744c15..cfbb255 100644 --- a/20-futures/getflags/README.adoc +++ b/20-futures/getflags/README.adoc @@ -1,11 +1,10 @@ = Experimenting with the `flags2*` examples The `flags2*` examples enhance the `flags*` examples with error handling and reporting. -Therefore, we need a server that generates errors and delays to test them. +Therefore, we need a server that generates errors and delays to experiment with them. The main reason for these instructions is to document how to configure one such server -in your machine, and how to run the clients to use it. - +in your machine, and how to tell the `flags2*` clients to access it. The other reason is to alert of an installation step that MacOS users sometimes overlook. Contents: @@ -19,14 +18,14 @@ Contents: If you don't already have a local HTTP server for testing, here are the steps to experiment with the `flags2*` examples -using just the Python ≥ 3.9 distribution and +using just the Python ≥ 3.9 distribution: . Clone or download the https://github.com/fluentpython/example-code-2e[_Fluent Python 2e_ code repository] (this repo!). . Open your shell and go to the _20-futures/getflags/_ directory of your local copy of the repository (this directory!) . Unzip the _flags.zip_ file, creating a _flags_ directory at _20-futures/getflags/flags/_. . Open a second shell, go to the _20-futures/getflags/_ directory and run `python3 -m http.server`. This will start a `ThreadingHTTPServer` listening to port 8000, serving the local files. If you open the URL http://localhost:8000/flags/[http://localhost:8000/flags/] with your browser, you'll see a long list of directories named with two-letter country codes from `ad/` to `zw/`. . Now you can go back to the first shell and run the _flags2*.py_ examples with the default `--server LOCAL` option. -. To test with the `--server DELAY` option, go to _20-futures/getflags/_ and run `python3 slow_server.py`. This bind to port 8001 by default. It will add a .5s delay before each response. +. To test with the `--server DELAY` option, go to _20-futures/getflags/_ and run `python3 slow_server.py`. This binds to port 8001 by default. It will add a .5s delay before each response. . To test with the `--server ERROR` option, go to _20-futures/getflags/_ and run `python3 slow_server.py 8002 --error-rate .25`. Each request will have a 25% probability of getting a https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/418[418 I'm a teapot] response, @@ -52,8 +51,7 @@ https://github.com/shopify/toxiproxy[Toxiproxy] with equivalent parameters. The `flags2*` examples provide a command-line interface. All three scripts accept the same options, -and you can see them by running any of the scripts with the `-h` option. -<> shows the help text. +and you can see them by running any of the scripts with the `-h` option: [[flags2_help_demo]] .Help screen for the scripts in the flags2 series @@ -91,18 +89,21 @@ One option you can't ignore is `-s/--server`: it lets you choose which HTTP serv You can pass one of four strings to determine where the script will look for the flags (the strings are case insensitive): `LOCAL`:: Use `http://localhost:8000/flags`; this is the default. -You should configure a local HTTP server to answer at port 8000. See <> for instructions. +You should configure a local HTTP server to answer at port 8000. See <> for instructions. +Feel free to hit this as hard as you can. It's your machine! `REMOTE`:: Use `http://fluentpython.com/data/flags`; that is a public website owned by me, hosted on a shared server. -Please do not pound it with too many concurrent requests. +Please do not hit it with too many concurrent requests. The `fluentpython.com` domain is handled by the http://www.cloudflare.com/[Cloudflare] CDN (Content Delivery Network) so you may notice that the first downloads are slower, but they get faster when the CDN cache warms up.footnote:[Before configuring Cloudflare, I got HTTP 503 errors--Service Temporarily Unavailable--when testing the scripts with a few dozen concurrent requests on my inexpensive shared host account. Now those errors are gone.] -`DELAY`:: Use `http://localhost:8001/flags`; a server delaying HTTP responses should be listening to port 8001. I wrote _slow_server.py_ to make it easier to experiment. You'll find it in the _20-futures/getflags/_ directory of the https://github.com/fluentpython/example-code-2e[_Fluent Python 2e_ code repository]. See <> for instructions. +`DELAY`:: Use `http://localhost:8001/flags`; a server delaying HTTP responses should be listening to port 8001. +I wrote _slow_server.py_ to make it easier to experiment. See <> for instructions. -`ERROR`:: Use `http://localhost:8002/flags`; a server introducing HTTP errors and delaying responses should be installed at port 8002. Running _slow_server.py_ is an easy way to do it. See <>. +`ERROR`:: Use `http://localhost:8002/flags`; a server introducing HTTP errors and delaying responses should be installed at port 8002. +Running _slow_server.py_ is an easy way to do it. See <>. [[macos_certificates]] == Install SSL Certificates (for MacOS) From 7985fda09f4c2f644540a258d141be92161c5eaf Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Mon, 27 Sep 2021 19:58:16 -0300 Subject: [PATCH 18/66] ch20: README.adoc --- 20-futures/getflags/README.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/20-futures/getflags/README.adoc b/20-futures/getflags/README.adoc index cfbb255..b4b3cc2 100644 --- a/20-futures/getflags/README.adoc +++ b/20-futures/getflags/README.adoc @@ -108,8 +108,8 @@ Running _slow_server.py_ is an easy way to do it. See <>. [[macos_certificates]] == Install SSL Certificates (for MacOS) -On Macos, depending on how in installed Python you may need to manually run a command -after Python's installer finishes, to install SSL certificates for HTTPS connections. +On Macos, depending on how you installed Python you may need to manually run a command +after Python's installer finishes, to install the SSL certificates Python uses to make HTTPS connections. Using the Finder, open the `Python 3.X` folder inside `/Applications` folder and double-click "Install Certificates" or "Install Certificates.command". From 4f1392d21c87e2519bd212fef8d9cbe280f7533a Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Sat, 2 Oct 2021 17:12:42 -0300 Subject: [PATCH 19/66] sequential, threaded & async HTTP clients using HTTPX --- 20-futures/getflags/README.adoc | 6 +- 20-futures/getflags/flags.py | 21 ++-- 20-futures/getflags/flags2_asyncio.py | 89 +++++++------- .../getflags/flags2_asyncio_executor.py | 115 +++++++++--------- 20-futures/getflags/flags2_common.py | 30 ++--- 20-futures/getflags/flags2_sequential.py | 59 ++++----- 20-futures/getflags/flags2_threadpool.py | 51 ++++---- 20-futures/getflags/flags3_asyncio.py | 25 ++-- 20-futures/getflags/flags_asyncio.py | 26 ++-- 20-futures/getflags/requirements.txt | 19 ++- 20-futures/getflags/slow_server.py | 20 ++- 20-futures/getflags/tree.py | 38 ++++++ 12 files changed, 273 insertions(+), 226 deletions(-) create mode 100644 20-futures/getflags/tree.py diff --git a/20-futures/getflags/README.adoc b/20-futures/getflags/README.adoc index b4b3cc2..a649994 100644 --- a/20-futures/getflags/README.adoc +++ b/20-futures/getflags/README.adoc @@ -14,7 +14,7 @@ Contents: * <> [[server_setup]] -== Setting up a test server +== Setting up test servers If you don't already have a local HTTP server for testing, here are the steps to experiment with the `flags2*` examples @@ -25,7 +25,7 @@ using just the Python ≥ 3.9 distribution: . Unzip the _flags.zip_ file, creating a _flags_ directory at _20-futures/getflags/flags/_. . Open a second shell, go to the _20-futures/getflags/_ directory and run `python3 -m http.server`. This will start a `ThreadingHTTPServer` listening to port 8000, serving the local files. If you open the URL http://localhost:8000/flags/[http://localhost:8000/flags/] with your browser, you'll see a long list of directories named with two-letter country codes from `ad/` to `zw/`. . Now you can go back to the first shell and run the _flags2*.py_ examples with the default `--server LOCAL` option. -. To test with the `--server DELAY` option, go to _20-futures/getflags/_ and run `python3 slow_server.py`. This binds to port 8001 by default. It will add a .5s delay before each response. +. To test with the `--server DELAY` option, go to _20-futures/getflags/_ and run `python3 slow_server.py`. This binds to port 8001 by default. It will add a random delay of .5s to 5s before each response. . To test with the `--server ERROR` option, go to _20-futures/getflags/_ and run `python3 slow_server.py 8002 --error-rate .25`. Each request will have a 25% probability of getting a https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/418[418 I'm a teapot] response, @@ -86,7 +86,7 @@ optional arguments: All arguments are optional. The most important arguments are discussed next. One option you can't ignore is `-s/--server`: it lets you choose which HTTP server and base URL will be used in the test. -You can pass one of four strings to determine where the script will look for the flags (the strings are case insensitive): +You can pass one of four labels to determine where the script will look for the flags (the labels are case-insensitive): `LOCAL`:: Use `http://localhost:8000/flags`; this is the default. You should configure a local HTTP server to answer at port 8000. See <> for instructions. diff --git a/20-futures/getflags/flags.py b/20-futures/getflags/flags.py index 3d6d36f..2311125 100755 --- a/20-futures/getflags/flags.py +++ b/20-futures/getflags/flags.py @@ -21,12 +21,12 @@ from pathlib import Path from typing import Callable -import requests # <1> +import httpx # <1> POP20_CC = ('CN IN US ID BR PK NG BD RU JP ' 'MX PH VN ET EG DE IR TR CD FR').split() # <2> -BASE_URL = 'http://fluentpython.com/data/flags' # <3> +BASE_URL = 'https://www.fluentpython.com/data/flags' # <3> DEST_DIR = Path('downloaded') # <4> def save_flag(img: bytes, filename: str) -> None: # <5> @@ -34,22 +34,25 @@ def save_flag(img: bytes, filename: str) -> None: # <5> def get_flag(cc: str) -> bytes: # <6> url = f'{BASE_URL}/{cc}/{cc}.gif'.lower() - resp = requests.get(url) + resp = httpx.get(url, timeout=6.1, # <7> + follow_redirects=True) # <8> + resp.raise_for_status() # <9> return resp.content -def download_many(cc_list: list[str]) -> int: # <7> - for cc in sorted(cc_list): # <8> +def download_many(cc_list: list[str]) -> int: # <10> + for cc in sorted(cc_list): # <11> image = get_flag(cc) save_flag(image, f'{cc}.gif') - print(cc, end=' ', flush=True) # <9> + print(cc, end=' ', flush=True) # <12> return len(cc_list) -def main(downloader: Callable[[list[str]], int]) -> None: # <10> - t0 = time.perf_counter() # <11> +def main(downloader: Callable[[list[str]], int]) -> None: # <13> + DEST_DIR.mkdir(exist_ok=True) # <14> + t0 = time.perf_counter() # <15> count = downloader(POP20_CC) elapsed = time.perf_counter() - t0 print(f'\n{count} downloads in {elapsed:.2f}s') if __name__ == '__main__': - main(download_many) # <12> + main(download_many) # <16> # end::FLAGS_PY[] diff --git a/20-futures/getflags/flags2_asyncio.py b/20-futures/getflags/flags2_asyncio.py index 88a18ed..a2bb6ff 100755 --- a/20-futures/getflags/flags2_asyncio.py +++ b/20-futures/getflags/flags2_asyncio.py @@ -8,65 +8,60 @@ # tag::FLAGS2_ASYNCIO_TOP[] import asyncio from collections import Counter +from http import HTTPStatus +from pathlib import Path -import aiohttp +import httpx import tqdm # type: ignore -from flags2_common import main, HTTPStatus, Result, save_flag +from flags2_common import main, DownloadStatus, save_flag # default set low to avoid errors from remote site, such as # 503 - Service Temporarily Unavailable DEFAULT_CONCUR_REQ = 5 MAX_CONCUR_REQ = 1000 - -class FetchError(Exception): # <1> - def __init__(self, country_code: str): - self.country_code = country_code - - -async def get_flag(session: aiohttp.ClientSession, # <2> +async def get_flag(session: httpx.AsyncClient, # <2> base_url: str, cc: str) -> bytes: url = f'{base_url}/{cc}/{cc}.gif'.lower() - async with session.get(url) as resp: - if resp.status == 200: - return await resp.read() - else: - resp.raise_for_status() # <3> - return bytes() + resp = await session.get(url, timeout=3.1, follow_redirects=True) # <3> + resp.raise_for_status() + return resp.content -async def download_one(session: aiohttp.ClientSession, +async def download_one(session: httpx.AsyncClient, cc: str, base_url: str, semaphore: asyncio.Semaphore, # <4> - verbose: bool) -> Result: + verbose: bool) -> DownloadStatus: try: async with semaphore: # <5> image = await get_flag(session, base_url, cc) - except aiohttp.ClientResponseError as exc: - if exc.status == 404: # <6> - status = HTTPStatus.not_found - msg = 'not found' + except httpx.HTTPStatusError as exc: # <4> + res = exc.response + if res.status_code == HTTPStatus.NOT_FOUND: + status = DownloadStatus.NOT_FOUND # <5> + msg = f'not found: {res.url}' else: - raise FetchError(cc) from exc # <7> + raise + else: - save_flag(image, f'{cc}.gif') - status = HTTPStatus.ok + await asyncio.to_thread(save_flag, image, f'{cc}.gif') + status = DownloadStatus.OK msg = 'OK' if verbose and msg: print(cc, msg) - return Result(status, cc) + return status # end::FLAGS2_ASYNCIO_TOP[] # tag::FLAGS2_ASYNCIO_START[] async def supervisor(cc_list: list[str], base_url: str, verbose: bool, - concur_req: int) -> Counter[HTTPStatus]: # <1> - counter: Counter[HTTPStatus] = Counter() + concur_req: int) -> Counter[DownloadStatus]: # <1> + counter: Counter[DownloadStatus] = Counter() semaphore = asyncio.Semaphore(concur_req) # <2> - async with aiohttp.ClientSession() as session: + async with httpx.AsyncClient() as session: to_do = [download_one(session, cc, base_url, semaphore, verbose) for cc in sorted(cc_list)] # <3> to_do_iter = asyncio.as_completed(to_do) # <4> @@ -74,25 +69,33 @@ async def supervisor(cc_list: list[str], to_do_iter = tqdm.tqdm(to_do_iter, total=len(cc_list)) # <5> for coro in to_do_iter: # <6> try: - res = await coro # <7> - except FetchError as exc: # <8> - country_code = exc.country_code # <9> - try: - error_msg = exc.__cause__.message # type: ignore # <10> - except AttributeError: - error_msg = 'Unknown cause' # <11> - if verbose and error_msg: - print(f'*** Error for {country_code}: {error_msg}') - status = HTTPStatus.error - else: - status = res.status - counter[status] += 1 # <12> - return counter # <13> + status = await coro # <7> + except httpx.HTTPStatusError as exc: # <8> + error_msg = 'HTTP error {resp.status_code} - {resp.reason_phrase}' + error_msg = error_msg.format(resp=exc.response) + error = exc + except httpx.RequestError as exc: # <9> + error_msg = f'{exc} {type(exc)}'.strip() + error = exc + except KeyboardInterrupt: # <10> + break + else: # <11> + error = None + + if error: + status = DownloadStatus.ERROR # <12> + if verbose: + url = str(error.request.url) # <13> + cc = Path(url).stem.upper() # <14> + print(f'{cc} error: {error_msg}') + counter[status] += 1 + + return counter def download_many(cc_list: list[str], base_url: str, verbose: bool, - concur_req: int) -> Counter[HTTPStatus]: + concur_req: int) -> Counter[DownloadStatus]: coro = supervisor(cc_list, base_url, verbose, concur_req) counts = asyncio.run(coro) # <14> diff --git a/20-futures/getflags/flags2_asyncio_executor.py b/20-futures/getflags/flags2_asyncio_executor.py index 5b75d59..7143b46 100755 --- a/20-futures/getflags/flags2_asyncio_executor.py +++ b/20-futures/getflags/flags2_asyncio_executor.py @@ -2,17 +2,19 @@ """Download flags of countries (with error handling). -asyncio async/await version using run_in_executor for save_flag. +asyncio async/await version """ - +# tag::FLAGS2_ASYNCIO_TOP[] import asyncio from collections import Counter +from http import HTTPStatus +from pathlib import Path -import aiohttp +import httpx import tqdm # type: ignore -from flags2_common import main, HTTPStatus, Result, save_flag +from flags2_common import main, DownloadStatus, save_flag # default set low to avoid errors from remote site, such as # 503 - Service Temporarily Unavailable @@ -20,90 +22,87 @@ MAX_CONCUR_REQ = 1000 -class FetchError(Exception): - def __init__(self, country_code: str): - self.country_code = country_code - - -async def get_flag(session: aiohttp.ClientSession, +async def get_flag(session: httpx.AsyncClient, # <2> base_url: str, cc: str) -> bytes: url = f'{base_url}/{cc}/{cc}.gif'.lower() - async with session.get(url) as resp: - if resp.status == 200: - return await resp.read() - else: - resp.raise_for_status() - return bytes() + resp = await session.get(url, timeout=3.1, follow_redirects=True) # <3> + resp.raise_for_status() + return resp.content -# tag::FLAGS2_ASYNCIO_EXECUTOR[] -async def download_one(session: aiohttp.ClientSession, + +async def download_one(session: httpx.AsyncClient, cc: str, base_url: str, semaphore: asyncio.Semaphore, - verbose: bool) -> Result: + verbose: bool) -> DownloadStatus: try: async with semaphore: image = await get_flag(session, base_url, cc) - except aiohttp.ClientResponseError as exc: - if exc.status == 404: - status = HTTPStatus.not_found - msg = 'not found' + except httpx.HTTPStatusError as exc: + res = exc.response + if res.status_code == HTTPStatus.NOT_FOUND: + status = DownloadStatus.NOT_FOUND + msg = f'not found: {res.url}' else: - raise FetchError(cc) from exc + raise else: - loop = asyncio.get_running_loop() # <1> - loop.run_in_executor(None, # <2> - save_flag, image, f'{cc}.gif') # <3> - status = HTTPStatus.ok +# tag::FLAGS2_ASYNCIO_EXECUTOR[] + loop = asyncio.get_running_loop() # <1> + loop.run_in_executor(None, save_flag, # <2> + image, f'{cc}.gif') # <3> +# end::FLAGS2_ASYNCIO_EXECUTOR[] + status = DownloadStatus.OK msg = 'OK' if verbose and msg: print(cc, msg) - return Result(status, cc) -# end::FLAGS2_ASYNCIO_EXECUTOR[] + return status async def supervisor(cc_list: list[str], base_url: str, verbose: bool, - concur_req: int) -> Counter[HTTPStatus]: - counter: Counter[HTTPStatus] = Counter() - semaphore = asyncio.Semaphore(concur_req) - async with aiohttp.ClientSession() as session: + concur_req: int) -> Counter[DownloadStatus]: # <1> + counter: Counter[DownloadStatus] = Counter() + semaphore = asyncio.Semaphore(concur_req) # <2> + async with httpx.AsyncClient() as session: to_do = [download_one(session, cc, base_url, semaphore, verbose) - for cc in sorted(cc_list)] - - to_do_iter = asyncio.as_completed(to_do) + for cc in sorted(cc_list)] # <3> + to_do_iter = asyncio.as_completed(to_do) # <4> if not verbose: - to_do_iter = tqdm.tqdm(to_do_iter, total=len(cc_list)) - for coro in to_do_iter: + to_do_iter = tqdm.tqdm(to_do_iter, total=len(cc_list)) # <5> + for coro in to_do_iter: # <6> try: - res = await coro - except FetchError as exc: - country_code = exc.country_code - try: - error_msg = exc.__cause__.message # type: ignore - except AttributeError: - error_msg = 'Unknown cause' - if verbose and error_msg: - print(f'*** Error for {country_code}: {error_msg}') - status = HTTPStatus.error - else: - status = res.status - - counter[status] += 1 - - return counter - + status = await coro # <7> + except httpx.HTTPStatusError as exc: # <13> + error_msg = 'HTTP error {resp.status_code} - {resp.reason_phrase}' + error_msg = error_msg.format(resp=exc.response) + error = exc + except httpx.RequestError as exc: # <15> + error_msg = f'{exc} {type(exc)}'.strip() + error = exc + except KeyboardInterrupt: # <7> + break + else: # <8> + error = None + + if error: + status = DownloadStatus.ERROR # <9> + if verbose: # <11> + cc = Path(str(error.request.url)).stem.upper() + print(f'{cc} error: {error_msg}') + counter[status] += 1 # <10> + + return counter # <12> def download_many(cc_list: list[str], base_url: str, verbose: bool, - concur_req: int) -> Counter[HTTPStatus]: + concur_req: int) -> Counter[DownloadStatus]: coro = supervisor(cc_list, base_url, verbose, concur_req) counts = asyncio.run(coro) # <14> return counts - if __name__ == '__main__': main(download_many, DEFAULT_CONCUR_REQ, MAX_CONCUR_REQ) +# end::FLAGS2_ASYNCIO_START[] diff --git a/20-futures/getflags/flags2_common.py b/20-futures/getflags/flags2_common.py index 74cd888..1ad05d3 100644 --- a/20-futures/getflags/flags2_common.py +++ b/20-futures/getflags/flags2_common.py @@ -5,13 +5,11 @@ import string import sys import time -from collections import namedtuple, Counter +from collections import Counter from enum import Enum from pathlib import Path -Result = namedtuple('Result', 'status data') - -HTTPStatus = Enum('HTTPStatus', 'ok not_found error') +DownloadStatus = Enum('DownloadStatus', 'OK NOT_FOUND ERROR') POP20_CC = ('CN IN US ID BR PK NG BD RU JP ' 'MX PH VN ET EG DE IR TR CD FR').split() @@ -20,7 +18,7 @@ MAX_CONCUR_REQ = 1 SERVERS = { - 'REMOTE': 'http://fluentpython.com/data/flags', + 'REMOTE': 'https://www.fluentpython.com/data/flags', 'LOCAL': 'http://localhost:8000/flags', 'DELAY': 'http://localhost:8001/flags', 'ERROR': 'http://localhost:8002/flags', @@ -52,17 +50,17 @@ def initial_report(cc_list: list[str], def final_report(cc_list: list[str], - counter: Counter[HTTPStatus], + counter: Counter[DownloadStatus], start_time: float) -> None: elapsed = time.perf_counter() - start_time print('-' * 20) - plural = 's' if counter[HTTPStatus.ok] != 1 else '' - print(f'{counter[HTTPStatus.ok]} flag{plural} downloaded.') - if counter[HTTPStatus.not_found]: - print(f'{counter[HTTPStatus.not_found]} not found.') - if counter[HTTPStatus.error]: - plural = 's' if counter[HTTPStatus.error] != 1 else '' - print(f'{counter[HTTPStatus.error]} error{plural}.') + plural = 's' if counter[DownloadStatus.OK] != 1 else '' + print(f'{counter[DownloadStatus.OK]:3} flag{plural} downloaded.') + if counter[DownloadStatus.NOT_FOUND]: + print(f'{counter[DownloadStatus.NOT_FOUND]:3} not found.') + if counter[DownloadStatus.ERROR]: + plural = 's' if counter[DownloadStatus.ERROR] != 1 else '' + print(f'{counter[DownloadStatus.ERROR]:3} error{plural}.') print(f'Elapsed time: {elapsed:.2f}s') @@ -142,7 +140,7 @@ def process_args(default_concur_req): sys.exit(2) # command line usage error if not cc_list: - cc_list = sorted(POP20_CC) + cc_list = sorted(POP20_CC)[:args.limit] return args, cc_list @@ -151,9 +149,7 @@ def main(download_many, default_concur_req, max_concur_req): actual_req = min(args.max_req, max_concur_req, len(cc_list)) initial_report(cc_list, actual_req, args.server) base_url = SERVERS[args.server] + DEST_DIR.mkdir(exist_ok=True) t0 = time.perf_counter() counter = download_many(cc_list, base_url, args.verbose, actual_req) - assert sum(counter.values()) == len(cc_list), ( - 'some downloads are unaccounted for' - ) final_report(cc_list, counter, t0) diff --git a/20-futures/getflags/flags2_sequential.py b/20-futures/getflags/flags2_sequential.py index 2e30856..e4358a3 100755 --- a/20-futures/getflags/flags2_sequential.py +++ b/20-futures/getflags/flags2_sequential.py @@ -17,71 +17,72 @@ """ +# tag::FLAGS2_BASIC_HTTP_FUNCTIONS[] from collections import Counter +from http import HTTPStatus -import requests -import tqdm # type: ignore +import httpx +import tqdm # type: ignore # <1> -from flags2_common import main, save_flag, HTTPStatus, Result +from flags2_common import main, save_flag, DownloadStatus # <2> DEFAULT_CONCUR_REQ = 1 MAX_CONCUR_REQ = 1 -# tag::FLAGS2_BASIC_HTTP_FUNCTIONS[] def get_flag(base_url: str, cc: str) -> bytes: url = f'{base_url}/{cc}/{cc}.gif'.lower() - resp = requests.get(url) - if resp.status_code != 200: # <1> - resp.raise_for_status() + resp = httpx.get(url, timeout=3.1, follow_redirects=True) + resp.raise_for_status() # <3> return resp.content -def download_one(cc: str, base_url: str, verbose: bool = False): +def download_one(cc: str, base_url: str, verbose: bool = False) -> DownloadStatus: try: image = get_flag(base_url, cc) - except requests.exceptions.HTTPError as exc: # <2> + except httpx.HTTPStatusError as exc: # <4> res = exc.response - if res.status_code == 404: - status = HTTPStatus.not_found # <3> - msg = 'not found' - else: # <4> - raise + if res.status_code == HTTPStatus.NOT_FOUND: + status = DownloadStatus.NOT_FOUND # <5> + msg = f'not found: {res.url}' + else: + raise # <6> else: save_flag(image, f'{cc}.gif') - status = HTTPStatus.ok + status = DownloadStatus.OK msg = 'OK' - if verbose: # <5> + if verbose: # <7> print(cc, msg) - return Result(status, cc) # <6> + return status # end::FLAGS2_BASIC_HTTP_FUNCTIONS[] # tag::FLAGS2_DOWNLOAD_MANY_SEQUENTIAL[] def download_many(cc_list: list[str], base_url: str, verbose: bool, - _unused_concur_req: int) -> Counter[int]: - counter: Counter[int] = Counter() # <1> + _unused_concur_req: int) -> Counter[DownloadStatus]: + counter: Counter[DownloadStatus] = Counter() # <1> cc_iter = sorted(cc_list) # <2> if not verbose: cc_iter = tqdm.tqdm(cc_iter) # <3> - for cc in cc_iter: # <4> + for cc in cc_iter: try: - res = download_one(cc, base_url, verbose) # <5> - except requests.exceptions.HTTPError as exc: # <6> - error_msg = 'HTTP error {res.status_code} - {res.reason}' - error_msg = error_msg.format(res=exc.response) - except requests.exceptions.ConnectionError: # <7> - error_msg = 'Connection error' + status = download_one(cc, base_url, verbose) # <4> + except httpx.HTTPStatusError as exc: # <5> + error_msg = 'HTTP error {resp.status_code} - {resp.reason_phrase}' + error_msg = error_msg.format(resp=exc.response) + except httpx.RequestError as exc: # <6> + error_msg = f'{exc} {type(exc)}'.strip() + except KeyboardInterrupt: # <7> + break else: # <8> error_msg = '' - status = res.status if error_msg: - status = HTTPStatus.error # <9> + status = DownloadStatus.ERROR # <9> counter[status] += 1 # <10> if verbose and error_msg: # <11> - print(f'*** Error for {cc}: {error_msg}') + print(f'{cc} error: {error_msg}') return counter # <12> # end::FLAGS2_DOWNLOAD_MANY_SEQUENTIAL[] diff --git a/20-futures/getflags/flags2_threadpool.py b/20-futures/getflags/flags2_threadpool.py index bbe71cb..8955c7c 100755 --- a/20-futures/getflags/flags2_threadpool.py +++ b/20-futures/getflags/flags2_threadpool.py @@ -22,48 +22,49 @@ from collections import Counter from concurrent import futures -import requests -import tqdm # type: ignore # <1> +import httpx +import tqdm # type: ignore -from flags2_common import main, HTTPStatus # <2> -from flags2_sequential import download_one # <3> +from flags2_common import main, DownloadStatus +from flags2_sequential import download_one # <1> -DEFAULT_CONCUR_REQ = 30 # <4> -MAX_CONCUR_REQ = 1000 # <5> +DEFAULT_CONCUR_REQ = 30 # <2> +MAX_CONCUR_REQ = 1000 # <3> def download_many(cc_list: list[str], base_url: str, verbose: bool, - concur_req: int) -> Counter[int]: - counter: Counter[int] = Counter() - with futures.ThreadPoolExecutor(max_workers=concur_req) as executor: # <6> - to_do_map = {} # <7> - for cc in sorted(cc_list): # <8> + concur_req: int) -> Counter[DownloadStatus]: + counter: Counter[DownloadStatus] = Counter() + with futures.ThreadPoolExecutor(max_workers=concur_req) as executor: # <4> + to_do_map = {} # <5> + for cc in sorted(cc_list): # <6> future = executor.submit(download_one, cc, - base_url, verbose) # <9> - to_do_map[future] = cc # <10> - done_iter = futures.as_completed(to_do_map) # <11> + base_url, verbose) # <7> + to_do_map[future] = cc # <8> + done_iter = futures.as_completed(to_do_map) # <9> if not verbose: - done_iter = tqdm.tqdm(done_iter, total=len(cc_list)) # <12> - for future in done_iter: # <13> + done_iter = tqdm.tqdm(done_iter, total=len(cc_list)) # <10> + for future in done_iter: # <11> try: - res = future.result() # <14> - except requests.exceptions.HTTPError as exc: # <15> - error_fmt = 'HTTP {res.status_code} - {res.reason}' - error_msg = error_fmt.format(res=exc.response) - except requests.exceptions.ConnectionError: - error_msg = 'Connection error' + status = future.result() # <12> + except httpx.HTTPStatusError as exc: # <13> + error_msg = 'HTTP error {resp.status_code} - {resp.reason_phrase}' + error_msg = error_msg.format(resp=exc.response) + except httpx.RequestError as exc: # <15> + error_msg = f'{exc} {type(exc)}'.strip() + except KeyboardInterrupt: + break else: error_msg = '' - status = res.status if error_msg: - status = HTTPStatus.error + status = DownloadStatus.ERROR counter[status] += 1 if verbose and error_msg: cc = to_do_map[future] # <16> - print(f'*** Error for {cc}: {error_msg}') + print(f'{cc} error: {error_msg}') return counter diff --git a/20-futures/getflags/flags3_asyncio.py b/20-futures/getflags/flags3_asyncio.py index 04a01e2..b698d4d 100755 --- a/20-futures/getflags/flags3_asyncio.py +++ b/20-futures/getflags/flags3_asyncio.py @@ -8,11 +8,12 @@ import asyncio from collections import Counter +from http import HTTPStatus import aiohttp import tqdm # type: ignore -from flags2_common import main, HTTPStatus, Result, save_flag +from flags2_common import main, DownloadStatus, save_flag # default set low to avoid errors from remote site, such as # 503 - Service Temporarily Unavailable @@ -54,15 +55,15 @@ async def download_one(session: aiohttp.ClientSession, cc: str, base_url: str, semaphore: asyncio.Semaphore, - verbose: bool) -> Result: + verbose: bool) -> DownloadStatus: try: async with semaphore: image = await get_flag(session, base_url, cc) # <1> async with semaphore: country = await get_country(session, base_url, cc) # <2> except aiohttp.ClientResponseError as exc: - if exc.status == 404: - status = HTTPStatus.not_found + if exc.status == HTTPStatus.NOT_FOUND: + status = DownloadStatus.NOT_FOUND msg = 'not found' else: raise FetchError(cc) from exc @@ -72,18 +73,18 @@ async def download_one(session: aiohttp.ClientSession, loop = asyncio.get_running_loop() loop.run_in_executor(None, save_flag, image, filename) - status = HTTPStatus.ok + status = DownloadStatus.OK msg = 'OK' if verbose and msg: print(cc, msg) - return Result(status, cc) + return status # end::FLAGS3_ASYNCIO_DOWNLOAD_ONE[] async def supervisor(cc_list: list[str], base_url: str, verbose: bool, - concur_req: int) -> Counter[HTTPStatus]: - counter: Counter[HTTPStatus] = Counter() + concur_req: int) -> Counter[DownloadStatus]: + counter: Counter[DownloadStatus] = Counter() semaphore = asyncio.Semaphore(concur_req) async with aiohttp.ClientSession() as session: to_do = [download_one(session, cc, base_url, @@ -95,7 +96,7 @@ async def supervisor(cc_list: list[str], to_do_iter = tqdm.tqdm(to_do_iter, total=len(cc_list)) for coro in to_do_iter: try: - res = await coro + status = await coro except FetchError as exc: country_code = exc.country_code try: @@ -104,9 +105,7 @@ async def supervisor(cc_list: list[str], error_msg = 'Unknown cause' if verbose and error_msg: print(f'*** Error for {country_code}: {error_msg}') - status = HTTPStatus.error - else: - status = res.status + status = DownloadStatus.ERROR counter[status] += 1 @@ -116,7 +115,7 @@ async def supervisor(cc_list: list[str], def download_many(cc_list: list[str], base_url: str, verbose: bool, - concur_req: int) -> Counter[HTTPStatus]: + concur_req: int) -> Counter[DownloadStatus]: coro = supervisor(cc_list, base_url, verbose, concur_req) counts = asyncio.run(coro) # <14> diff --git a/20-futures/getflags/flags_asyncio.py b/20-futures/getflags/flags_asyncio.py index ee431d0..ba28065 100755 --- a/20-futures/getflags/flags_asyncio.py +++ b/20-futures/getflags/flags_asyncio.py @@ -9,38 +9,38 @@ $ python3 flags_asyncio.py EG VN IN TR RU ID US DE CN MX JP BD NG ET FR BR PH PK CD IR 20 flags downloaded in 1.07s - """ # tag::FLAGS_ASYNCIO_TOP[] import asyncio -from aiohttp import ClientSession # <1> +from httpx import AsyncClient # <1> from flags import BASE_URL, save_flag, main # <2> -async def download_one(session: ClientSession, cc: str): # <3> +async def download_one(session: AsyncClient, cc: str): # <3> image = await get_flag(session, cc) save_flag(image, f'{cc}.gif') print(cc, end=' ', flush=True) return cc -async def get_flag(session: ClientSession, cc: str) -> bytes: # <4> +async def get_flag(session: AsyncClient, cc: str) -> bytes: # <4> url = f'{BASE_URL}/{cc}/{cc}.gif'.lower() - async with session.get(url) as resp: # <5> - return await resp.read() # <6> + resp = await session.get(url, timeout=6.1, + follow_redirects=True) # <5> + return resp.read() # <6> # end::FLAGS_ASYNCIO_TOP[] # tag::FLAGS_ASYNCIO_START[] -def download_many(cc_list: list[str]) -> int: # <1> - return asyncio.run(supervisor(cc_list)) # <2> +def download_many(cc_list: list[str]) -> int: # <1> + return asyncio.run(supervisor(cc_list)) # <2> async def supervisor(cc_list: list[str]) -> int: - async with ClientSession() as session: # <3> - to_do = [download_one(session, cc) # <4> - for cc in sorted(cc_list)] - res = await asyncio.gather(*to_do) # <5> + async with AsyncClient() as session: # <3> + to_do = [download_one(session, cc) + for cc in sorted(cc_list)] # <4> + res = await asyncio.gather(*to_do) # <5> - return len(res) # <6> + return len(res) # <6> if __name__ == '__main__': main(download_many) diff --git a/20-futures/getflags/requirements.txt b/20-futures/getflags/requirements.txt index 37baa8d..b8bb630 100644 --- a/20-futures/getflags/requirements.txt +++ b/20-futures/getflags/requirements.txt @@ -1,13 +1,10 @@ -aiohttp==3.7.4.post0 -async-timeout==3.0.1 -attrs==21.2.0 +anyio==3.3.2 certifi==2021.5.30 -chardet==4.0.0 -charset-normalizer==2.0.4 +charset-normalizer==2.0.6 +h11==0.12.0 +httpcore==0.13.7 +httpx==1.0.0b0 idna==3.2 -multidict==5.1.0 -requests==2.26.0 -tqdm==4.62.2 -typing-extensions==3.10.0.2 -urllib3==1.26.6 -yarl==1.6.3 +rfc3986==1.5.0 +sniffio==1.2.0 +tqdm==4.62.3 diff --git a/20-futures/getflags/slow_server.py b/20-futures/getflags/slow_server.py index bede010..90e6672 100755 --- a/20-futures/getflags/slow_server.py +++ b/20-futures/getflags/slow_server.py @@ -15,8 +15,10 @@ from functools import partial from http import server, HTTPStatus from http.server import ThreadingHTTPServer, SimpleHTTPRequestHandler -from random import random +from random import random, uniform +MIN_DELAY = 0.5 # minimum delay for do_GET (seconds) +MAX_DELAY = 5.0 # maximum delay for do_GET (seconds) class SlowHTTPRequestHandler(SimpleHTTPRequestHandler): """SlowHTTPRequestHandler adds delays and errors to test HTTP clients. @@ -36,15 +38,23 @@ def __init__(self, *args, error_rate=0.0, **kwargs): def do_GET(self): """Serve a GET request.""" - time.sleep(.5) + delay = uniform(MIN_DELAY, MAX_DELAY) + cc = self.path[-6:-4].upper() + print(f'{cc} delay: {delay:0.2}s') + time.sleep(delay) if random() < self.error_rate: # HTTPStatus.IM_A_TEAPOT requires Python >= 3.9 - self.send_error(HTTPStatus.IM_A_TEAPOT, "I'm a Teapot") + try: + self.send_error(HTTPStatus.IM_A_TEAPOT, "I'm a Teapot") + except BrokenPipeError as exc: + print(f'{cc} *** BrokenPipeError: client closed') else: f = self.send_head() if f: try: self.copyfile(f, self.wfile) + except BrokenPipeError as exc: + print(f'{cc} *** BrokenPipeError: client closed') finally: f.close() @@ -67,9 +77,9 @@ def do_GET(self): help='Error rate; e.g. use .25 for 25%% probability ' '[default:0.0]') parser.add_argument('port', action='store', - default=8000, type=int, + default=8001, type=int, nargs='?', - help='Specify alternate port [default: 8000]') + help='Specify alternate port [default: 8001]') args = parser.parse_args() handler_class = partial(SlowHTTPRequestHandler, directory=args.directory, diff --git a/20-futures/getflags/tree.py b/20-futures/getflags/tree.py new file mode 100644 index 0000000..4f65697 --- /dev/null +++ b/20-futures/getflags/tree.py @@ -0,0 +1,38 @@ +import httpx + +def tree(cls, level=0): + yield cls.__name__, level + for sub_cls in cls.__subclasses__(): + yield from tree(sub_cls, level+1) + + +def display(cls): + for cls_name, level in tree(cls): + indent = ' ' * 4 * level + print(f'{indent}{cls_name}') + + +def find_roots(module): + exceptions = [] + for name in dir(module): + obj = getattr(module, name) + if isinstance(obj, type) and issubclass(obj, BaseException): + exceptions.append(obj) + roots = [] + for exc in exceptions: + root = True + for other in exceptions: + if exc is not other and issubclass(exc, other): + root = False + break + if root: + roots.append(exc) + return roots + + +def main(): + for exc in find_roots(httpx): + display(exc) + +if __name__ == '__main__': + main() From 0f91193c9f0cc6cf200c22e3828f2599fa8a67ed Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Sat, 2 Oct 2021 17:13:14 -0300 Subject: [PATCH 20/66] sequential, threaded & async HTTP clients using HTTPX --- 20-futures/getflags/flags3_asyncio.py | 126 -------------------------- 1 file changed, 126 deletions(-) delete mode 100755 20-futures/getflags/flags3_asyncio.py diff --git a/20-futures/getflags/flags3_asyncio.py b/20-futures/getflags/flags3_asyncio.py deleted file mode 100755 index b698d4d..0000000 --- a/20-futures/getflags/flags3_asyncio.py +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env python3 - -"""Download flags of countries (with error handling). - -asyncio async/await version using run_in_executor for save_flag. - -""" - -import asyncio -from collections import Counter -from http import HTTPStatus - -import aiohttp -import tqdm # type: ignore - -from flags2_common import main, DownloadStatus, save_flag - -# default set low to avoid errors from remote site, such as -# 503 - Service Temporarily Unavailable -DEFAULT_CONCUR_REQ = 5 -MAX_CONCUR_REQ = 1000 - - -class FetchError(Exception): - def __init__(self, country_code: str): - self.country_code = country_code - -async def get_flag(session: aiohttp.ClientSession, - base_url: str, - cc: str) -> bytes: - url = f'{base_url}/{cc}/{cc}.gif' - async with session.get(url) as resp: - if resp.status == 200: - return await resp.read() - else: - resp.raise_for_status() - return bytes() - -# tag::FLAGS3_ASYNCIO_GET_COUNTRY[] -async def get_country(session: aiohttp.ClientSession, - base_url: str, - cc: str) -> str: # <1> - url = f'{base_url}/{cc}/metadata.json' - async with session.get(url) as resp: - if resp.status == 200: - metadata = await resp.json() # <2> - return metadata.get('country', 'no name') # <3> - else: - resp.raise_for_status() - return '' -# end::FLAGS3_ASYNCIO_GET_COUNTRY[] - -# tag::FLAGS3_ASYNCIO_DOWNLOAD_ONE[] -async def download_one(session: aiohttp.ClientSession, - cc: str, - base_url: str, - semaphore: asyncio.Semaphore, - verbose: bool) -> DownloadStatus: - try: - async with semaphore: - image = await get_flag(session, base_url, cc) # <1> - async with semaphore: - country = await get_country(session, base_url, cc) # <2> - except aiohttp.ClientResponseError as exc: - if exc.status == HTTPStatus.NOT_FOUND: - status = DownloadStatus.NOT_FOUND - msg = 'not found' - else: - raise FetchError(cc) from exc - else: - filename = country.replace(' ', '_') # <3> - filename = f'{filename}.gif' - loop = asyncio.get_running_loop() - loop.run_in_executor(None, - save_flag, image, filename) - status = DownloadStatus.OK - msg = 'OK' - if verbose and msg: - print(cc, msg) - return status -# end::FLAGS3_ASYNCIO_DOWNLOAD_ONE[] - -async def supervisor(cc_list: list[str], - base_url: str, - verbose: bool, - concur_req: int) -> Counter[DownloadStatus]: - counter: Counter[DownloadStatus] = Counter() - semaphore = asyncio.Semaphore(concur_req) - async with aiohttp.ClientSession() as session: - to_do = [download_one(session, cc, base_url, - semaphore, verbose) - for cc in sorted(cc_list)] - - to_do_iter = asyncio.as_completed(to_do) - if not verbose: - to_do_iter = tqdm.tqdm(to_do_iter, total=len(cc_list)) - for coro in to_do_iter: - try: - status = await coro - except FetchError as exc: - country_code = exc.country_code - try: - error_msg = exc.__cause__.message # type: ignore - except AttributeError: - error_msg = 'Unknown cause' - if verbose and error_msg: - print(f'*** Error for {country_code}: {error_msg}') - status = DownloadStatus.ERROR - - counter[status] += 1 - - return counter - - -def download_many(cc_list: list[str], - base_url: str, - verbose: bool, - concur_req: int) -> Counter[DownloadStatus]: - coro = supervisor(cc_list, base_url, verbose, concur_req) - counts = asyncio.run(coro) # <14> - - return counts - - -if __name__ == '__main__': - main(download_many, DEFAULT_CONCUR_REQ, MAX_CONCUR_REQ) From 6359a4de0c7f3b155b5445512fe99972ed7c5f43 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Sat, 2 Oct 2021 17:27:22 -0300 Subject: [PATCH 21/66] sequential, threaded & async HTTP clients using HTTPX --- 20-futures/getflags/downloaded/.gitignore | 1 - 1 file changed, 1 deletion(-) delete mode 100644 20-futures/getflags/downloaded/.gitignore diff --git a/20-futures/getflags/downloaded/.gitignore b/20-futures/getflags/downloaded/.gitignore deleted file mode 100644 index d8c78e1..0000000 --- a/20-futures/getflags/downloaded/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.gif \ No newline at end of file From 980f75032685921e08d5200513a261e83ef5f858 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Sat, 2 Oct 2021 17:48:34 -0300 Subject: [PATCH 22/66] sequential, threaded & async HTTP clients using HTTPX --- 20-futures/getflags/flags2_asyncio.py | 1 + 20-futures/getflags/flags2_asyncio_executor.py | 1 + 2 files changed, 2 insertions(+) diff --git a/20-futures/getflags/flags2_asyncio.py b/20-futures/getflags/flags2_asyncio.py index a2bb6ff..4825db4 100755 --- a/20-futures/getflags/flags2_asyncio.py +++ b/20-futures/getflags/flags2_asyncio.py @@ -67,6 +67,7 @@ async def supervisor(cc_list: list[str], to_do_iter = asyncio.as_completed(to_do) # <4> if not verbose: to_do_iter = tqdm.tqdm(to_do_iter, total=len(cc_list)) # <5> + error: httpx.HTTPError | None = None for coro in to_do_iter: # <6> try: status = await coro # <7> diff --git a/20-futures/getflags/flags2_asyncio_executor.py b/20-futures/getflags/flags2_asyncio_executor.py index 7143b46..752b60f 100755 --- a/20-futures/getflags/flags2_asyncio_executor.py +++ b/20-futures/getflags/flags2_asyncio_executor.py @@ -70,6 +70,7 @@ async def supervisor(cc_list: list[str], to_do_iter = asyncio.as_completed(to_do) # <4> if not verbose: to_do_iter = tqdm.tqdm(to_do_iter, total=len(cc_list)) # <5> + error: httpx.HTTPError | None = None for coro in to_do_iter: # <6> try: status = await coro # <7> From 5d6b15604782c715c85236d6de30b90add3f8d32 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Tue, 5 Oct 2021 09:44:12 -0300 Subject: [PATCH 23/66] ch20: renamed directory --- {20-futures => 20-executors}/demo_executor_map.py | 0 {20-futures => 20-executors}/getflags/.gitignore | 0 {20-futures => 20-executors}/getflags/README.adoc | 0 .../getflags/country_codes.txt | 0 {20-futures => 20-executors}/getflags/flags.py | 0 {20-futures => 20-executors}/getflags/flags.zip | Bin .../getflags/flags2_asyncio.py | 0 .../getflags/flags2_asyncio_executor.py | 0 .../getflags/flags2_common.py | 0 .../getflags/flags2_sequential.py | 0 .../getflags/flags2_threadpool.py | 0 .../getflags/flags_asyncio.py | 0 .../getflags/flags_threadpool.py | 0 .../getflags/flags_threadpool_futures.py | 0 .../getflags/requirements.txt | 0 .../getflags/slow_server.py | 0 {20-futures => 20-executors}/getflags/tree.py | 0 {20-futures => 20-executors}/primes/primes.py | 0 {20-futures => 20-executors}/primes/proc_pool.py | 0 19 files changed, 0 insertions(+), 0 deletions(-) rename {20-futures => 20-executors}/demo_executor_map.py (100%) rename {20-futures => 20-executors}/getflags/.gitignore (100%) rename {20-futures => 20-executors}/getflags/README.adoc (100%) rename {20-futures => 20-executors}/getflags/country_codes.txt (100%) rename {20-futures => 20-executors}/getflags/flags.py (100%) rename {20-futures => 20-executors}/getflags/flags.zip (100%) rename {20-futures => 20-executors}/getflags/flags2_asyncio.py (100%) rename {20-futures => 20-executors}/getflags/flags2_asyncio_executor.py (100%) rename {20-futures => 20-executors}/getflags/flags2_common.py (100%) rename {20-futures => 20-executors}/getflags/flags2_sequential.py (100%) rename {20-futures => 20-executors}/getflags/flags2_threadpool.py (100%) rename {20-futures => 20-executors}/getflags/flags_asyncio.py (100%) rename {20-futures => 20-executors}/getflags/flags_threadpool.py (100%) rename {20-futures => 20-executors}/getflags/flags_threadpool_futures.py (100%) rename {20-futures => 20-executors}/getflags/requirements.txt (100%) rename {20-futures => 20-executors}/getflags/slow_server.py (100%) rename {20-futures => 20-executors}/getflags/tree.py (100%) rename {20-futures => 20-executors}/primes/primes.py (100%) rename {20-futures => 20-executors}/primes/proc_pool.py (100%) diff --git a/20-futures/demo_executor_map.py b/20-executors/demo_executor_map.py similarity index 100% rename from 20-futures/demo_executor_map.py rename to 20-executors/demo_executor_map.py diff --git a/20-futures/getflags/.gitignore b/20-executors/getflags/.gitignore similarity index 100% rename from 20-futures/getflags/.gitignore rename to 20-executors/getflags/.gitignore diff --git a/20-futures/getflags/README.adoc b/20-executors/getflags/README.adoc similarity index 100% rename from 20-futures/getflags/README.adoc rename to 20-executors/getflags/README.adoc diff --git a/20-futures/getflags/country_codes.txt b/20-executors/getflags/country_codes.txt similarity index 100% rename from 20-futures/getflags/country_codes.txt rename to 20-executors/getflags/country_codes.txt diff --git a/20-futures/getflags/flags.py b/20-executors/getflags/flags.py similarity index 100% rename from 20-futures/getflags/flags.py rename to 20-executors/getflags/flags.py diff --git a/20-futures/getflags/flags.zip b/20-executors/getflags/flags.zip similarity index 100% rename from 20-futures/getflags/flags.zip rename to 20-executors/getflags/flags.zip diff --git a/20-futures/getflags/flags2_asyncio.py b/20-executors/getflags/flags2_asyncio.py similarity index 100% rename from 20-futures/getflags/flags2_asyncio.py rename to 20-executors/getflags/flags2_asyncio.py diff --git a/20-futures/getflags/flags2_asyncio_executor.py b/20-executors/getflags/flags2_asyncio_executor.py similarity index 100% rename from 20-futures/getflags/flags2_asyncio_executor.py rename to 20-executors/getflags/flags2_asyncio_executor.py diff --git a/20-futures/getflags/flags2_common.py b/20-executors/getflags/flags2_common.py similarity index 100% rename from 20-futures/getflags/flags2_common.py rename to 20-executors/getflags/flags2_common.py diff --git a/20-futures/getflags/flags2_sequential.py b/20-executors/getflags/flags2_sequential.py similarity index 100% rename from 20-futures/getflags/flags2_sequential.py rename to 20-executors/getflags/flags2_sequential.py diff --git a/20-futures/getflags/flags2_threadpool.py b/20-executors/getflags/flags2_threadpool.py similarity index 100% rename from 20-futures/getflags/flags2_threadpool.py rename to 20-executors/getflags/flags2_threadpool.py diff --git a/20-futures/getflags/flags_asyncio.py b/20-executors/getflags/flags_asyncio.py similarity index 100% rename from 20-futures/getflags/flags_asyncio.py rename to 20-executors/getflags/flags_asyncio.py diff --git a/20-futures/getflags/flags_threadpool.py b/20-executors/getflags/flags_threadpool.py similarity index 100% rename from 20-futures/getflags/flags_threadpool.py rename to 20-executors/getflags/flags_threadpool.py diff --git a/20-futures/getflags/flags_threadpool_futures.py b/20-executors/getflags/flags_threadpool_futures.py similarity index 100% rename from 20-futures/getflags/flags_threadpool_futures.py rename to 20-executors/getflags/flags_threadpool_futures.py diff --git a/20-futures/getflags/requirements.txt b/20-executors/getflags/requirements.txt similarity index 100% rename from 20-futures/getflags/requirements.txt rename to 20-executors/getflags/requirements.txt diff --git a/20-futures/getflags/slow_server.py b/20-executors/getflags/slow_server.py similarity index 100% rename from 20-futures/getflags/slow_server.py rename to 20-executors/getflags/slow_server.py diff --git a/20-futures/getflags/tree.py b/20-executors/getflags/tree.py similarity index 100% rename from 20-futures/getflags/tree.py rename to 20-executors/getflags/tree.py diff --git a/20-futures/primes/primes.py b/20-executors/primes/primes.py similarity index 100% rename from 20-futures/primes/primes.py rename to 20-executors/primes/primes.py diff --git a/20-futures/primes/proc_pool.py b/20-executors/primes/proc_pool.py similarity index 100% rename from 20-futures/primes/proc_pool.py rename to 20-executors/primes/proc_pool.py From 43f1bf23b3ba020597b455e740fe553f1923fca9 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Tue, 5 Oct 2021 09:52:43 -0300 Subject: [PATCH 24/66] sync from Atlas --- 19-concurrency/primes/procs.py | 60 +++++++------- 19-concurrency/primes/procs_race_condition.py | 80 +++++++++++++++++++ 20-executors/getflags/.gitignore | 3 +- 20-executors/getflags/flags2_threadpool.py | 10 +-- README.md | 2 +- 5 files changed, 118 insertions(+), 37 deletions(-) create mode 100755 19-concurrency/primes/procs_race_condition.py diff --git a/19-concurrency/primes/procs.py b/19-concurrency/primes/procs.py index 09f75e3..50e3d9f 100644 --- a/19-concurrency/primes/procs.py +++ b/19-concurrency/primes/procs.py @@ -31,46 +31,46 @@ def worker(jobs: JobQueue, results: ResultQueue) -> None: # <7> while n := jobs.get(): # <8> results.put(check(n)) # <9> results.put(PrimeResult(0, False, 0.0)) # <10> -# end::PRIMES_PROC_TOP[] -# tag::PRIMES_PROC_MIDDLE[] -def start_jobs(workers: int, jobs: JobQueue, results: ResultQueue) -> None: +def start_jobs( + procs: int, jobs: JobQueue, results: ResultQueue # <11> +) -> None: for n in NUMBERS: - jobs.put(n) # <1> - for _ in range(workers): - proc = Process(target=worker, args=(jobs, results)) # <2> - proc.start() # <3> - jobs.put(0) # <4> - -def report(workers: int, results: ResultQueue) -> int: - checked = 0 - workers_done = 0 - while workers_done < workers: - n, prime, elapsed = results.get() - if n == 0: - workers_done += 1 - else: - checked += 1 - label = 'P' if prime else ' ' - print(f'{n:16} {label} {elapsed:9.6f}s') - return checked -# end::PRIMES_PROC_MIDDLE[] + jobs.put(n) # <12> + for _ in range(procs): + proc = Process(target=worker, args=(jobs, results)) # <13> + proc.start() # <14> + jobs.put(0) # <15> +# end::PRIMES_PROC_TOP[] # tag::PRIMES_PROC_MAIN[] def main() -> None: - if len(sys.argv) < 2: - workers = cpu_count() + if len(sys.argv) < 2: # <1> + procs = cpu_count() else: - workers = int(sys.argv[1]) + procs = int(sys.argv[1]) - print(f'Checking {len(NUMBERS)} numbers with {workers} processes:') + print(f'Checking {len(NUMBERS)} numbers with {procs} processes:') t0 = perf_counter() - jobs: JobQueue = SimpleQueue() + jobs: JobQueue = SimpleQueue() # <2> results: ResultQueue = SimpleQueue() - start_jobs(workers, jobs, results) - checked = report(workers, results) + start_jobs(procs, jobs, results) # <3> + checked = report(procs, results) # <4> elapsed = perf_counter() - t0 - print(f'{checked} checks in {elapsed:.2f}s') + print(f'{checked} checks in {elapsed:.2f}s') # <5> + +def report(procs: int, results: ResultQueue) -> int: # <6> + checked = 0 + procs_done = 0 + while procs_done < procs: # <7> + n, prime, elapsed = results.get() # <8> + if n == 0: # <9> + procs_done += 1 + else: + checked += 1 # <10> + label = 'P' if prime else ' ' + print(f'{n:16} {label} {elapsed:9.6f}s') + return checked if __name__ == '__main__': main() diff --git a/19-concurrency/primes/procs_race_condition.py b/19-concurrency/primes/procs_race_condition.py new file mode 100755 index 0000000..aa5e172 --- /dev/null +++ b/19-concurrency/primes/procs_race_condition.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 + +""" +procs.py: shows that multiprocessing on a multicore machine +can be faster than sequential code for CPU-intensive work. +""" + +# tag::PRIMES_PROC_TOP[] +import sys +from time import perf_counter +from typing import NamedTuple +from multiprocessing import Process, SimpleQueue, cpu_count # <1> +from multiprocessing import queues # <2> + +from primes import is_prime, NUMBERS + +class PrimeResult(NamedTuple): # <3> + n: int + prime: bool + elapsed: float + +JobQueue = queues.SimpleQueue[int] # <4> +ResultQueue = queues.SimpleQueue[PrimeResult] # <5> + +def check(n: int) -> PrimeResult: # <6> + t0 = perf_counter() + res = is_prime(n) + return PrimeResult(n, res, perf_counter() - t0) + +def worker(jobs: JobQueue, results: ResultQueue) -> None: # <7> + while n := jobs.get(): # <8> + results.put(check(n)) # <9> + results.put(PrimeResult(0, False, 0.0)) +# end::PRIMES_PROC_TOP[] + +def start_jobs(workers: int) -> ResultQueue: + jobs: JobQueue = SimpleQueue() # <2> + results: ResultQueue = SimpleQueue() + + for n in NUMBERS: # <3> + jobs.put(n) + + for _ in range(workers): + proc = Process(target=worker, args=(jobs, results)) # <4> + proc.start() # <5> + jobs.put(0) # <6> + + return results + +def report(workers: int, results: ResultQueue) -> int: + workers_done = 0 + checked = 0 + while workers_done < workers: + n, prime, elapsed = results.get() # <7> + if n == 0: + workers_done += 1 + else: + checked += 1 + label = 'P' if prime else ' ' + print(f'{n:16} {label} {elapsed:9.6f}s') # <8> + return checked + + +# tag::PRIMES_PROC_MAIN[] +def main() -> None: + if len(sys.argv) < 2: # <1> + workers = cpu_count() + else: + workers = int(sys.argv[1]) + + print(f'Checking {len(NUMBERS)} numbers with {workers} processes:') + t0 = perf_counter() + results = start_jobs(workers) + checked = report(workers, results) + elapsed = perf_counter() - t0 + print(f'{checked} checks in {elapsed:.2f}s') + +if __name__ == '__main__': + main() +# end::PRIMES_PROC_MAIN[] diff --git a/20-executors/getflags/.gitignore b/20-executors/getflags/.gitignore index 8484300..aad8463 100644 --- a/20-executors/getflags/.gitignore +++ b/20-executors/getflags/.gitignore @@ -1 +1,2 @@ -flags/ \ No newline at end of file +flags/ +downloaded/ diff --git a/20-executors/getflags/flags2_threadpool.py b/20-executors/getflags/flags2_threadpool.py index 8955c7c..62f6c3b 100755 --- a/20-executors/getflags/flags2_threadpool.py +++ b/20-executors/getflags/flags2_threadpool.py @@ -20,7 +20,7 @@ # tag::FLAGS2_THREADPOOL[] from collections import Counter -from concurrent import futures +from concurrent.futures import ThreadPoolExecutor, as_completed import httpx import tqdm # type: ignore @@ -37,13 +37,13 @@ def download_many(cc_list: list[str], verbose: bool, concur_req: int) -> Counter[DownloadStatus]: counter: Counter[DownloadStatus] = Counter() - with futures.ThreadPoolExecutor(max_workers=concur_req) as executor: # <4> + with ThreadPoolExecutor(max_workers=concur_req) as executor: # <4> to_do_map = {} # <5> for cc in sorted(cc_list): # <6> future = executor.submit(download_one, cc, base_url, verbose) # <7> to_do_map[future] = cc # <8> - done_iter = futures.as_completed(to_do_map) # <9> + done_iter = as_completed(to_do_map) # <9> if not verbose: done_iter = tqdm.tqdm(done_iter, total=len(cc_list)) # <10> for future in done_iter: # <11> @@ -52,7 +52,7 @@ def download_many(cc_list: list[str], except httpx.HTTPStatusError as exc: # <13> error_msg = 'HTTP error {resp.status_code} - {resp.reason_phrase}' error_msg = error_msg.format(resp=exc.response) - except httpx.RequestError as exc: # <15> + except httpx.RequestError as exc: error_msg = f'{exc} {type(exc)}'.strip() except KeyboardInterrupt: break @@ -63,7 +63,7 @@ def download_many(cc_list: list[str], status = DownloadStatus.ERROR counter[status] += 1 if verbose and error_msg: - cc = to_do_map[future] # <16> + cc = to_do_map[future] # <14> print(f'{cc} error: {error_msg}') return counter diff --git a/README.md b/README.md index f0854e9..96273ac 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Part / Chapter #|Title|Directory|1st ed. Chapter # 17|Iterators, Generators, and Classic Coroutines|[17-it-generator](17-it-generator)|14 18|Context Managers and else Blocks|[18-with-match](18-with-match)|15 19|Concurrency Models in Python|[19-concurrency](19-concurrency)|🆕 -20|Concurrency with Futures|[20-futures](20-futures)|17 +20|Concurrent Executors|[20-executors](20-executors)|17 21|Asynchronous Programming|[21-async](21-async)|18 **VI – Metaprogramming**| 22|Dynamic Attributes and Properties|[22-dyn-attr-prop](22-dyn-attr-prop)|19 From 6fb0832c4041ec8f46f80d0a8bac5af5a69f32f4 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Tue, 12 Oct 2021 22:37:28 -0300 Subject: [PATCH 25/66] sync from Atlas --- 02-array-seq/lispy/py3.10/examples_test.py | 2 +- 02-array-seq/lispy/py3.9/lis.py | 2 +- 18-with-match/lispy/py3.10/examples_test.py | 2 +- 18-with-match/lispy/py3.10/lis.py | 2 +- 18-with-match/lispy/py3.9/examples_test.py | 4 +- 18-with-match/lispy/py3.9/lis.py | 2 +- 20-executors/getflags/flags2_asyncio.py | 51 ++++++++++----------- 7 files changed, 31 insertions(+), 34 deletions(-) diff --git a/02-array-seq/lispy/py3.10/examples_test.py b/02-array-seq/lispy/py3.10/examples_test.py index ba6bd10..603ccd3 100644 --- a/02-array-seq/lispy/py3.10/examples_test.py +++ b/02-array-seq/lispy/py3.10/examples_test.py @@ -147,7 +147,7 @@ def test_factorial(): gcd_src = """ (define (mod m n) - (- m (* n (// m n)))) + (- m (* n (quotient m n)))) (define (gcd m n) (if (= n 0) m diff --git a/02-array-seq/lispy/py3.9/lis.py b/02-array-seq/lispy/py3.9/lis.py index 201b41e..dd80096 100644 --- a/02-array-seq/lispy/py3.9/lis.py +++ b/02-array-seq/lispy/py3.9/lis.py @@ -80,7 +80,7 @@ def standard_env() -> Environment: '-': op.sub, '*': op.mul, '/': op.truediv, - '//': op.floordiv, + 'quotient': op.floordiv, '>': op.gt, '<': op.lt, '>=': op.ge, diff --git a/18-with-match/lispy/py3.10/examples_test.py b/18-with-match/lispy/py3.10/examples_test.py index 2807596..d207df0 100644 --- a/18-with-match/lispy/py3.10/examples_test.py +++ b/18-with-match/lispy/py3.10/examples_test.py @@ -146,7 +146,7 @@ def test_factorial(): gcd_src = """ (define (mod m n) - (- m (* n (// m n)))) + (- m (* n (quotient m n)))) (define (gcd m n) (if (= n 0) m diff --git a/18-with-match/lispy/py3.10/lis.py b/18-with-match/lispy/py3.10/lis.py index 0faf6d2..04cc28d 100755 --- a/18-with-match/lispy/py3.10/lis.py +++ b/18-with-match/lispy/py3.10/lis.py @@ -83,7 +83,7 @@ def standard_env() -> Environment: '-': op.sub, '*': op.mul, '/': op.truediv, - '//': op.floordiv, + 'quotient': op.floordiv, '>': op.gt, '<': op.lt, '>=': op.ge, diff --git a/18-with-match/lispy/py3.9/examples_test.py b/18-with-match/lispy/py3.9/examples_test.py index c632662..603ccd3 100644 --- a/18-with-match/lispy/py3.9/examples_test.py +++ b/18-with-match/lispy/py3.9/examples_test.py @@ -147,7 +147,7 @@ def test_factorial(): gcd_src = """ (define (mod m n) - (- m (* n (// m n)))) + (- m (* n (quotient m n)))) (define (gcd m n) (if (= n 0) m @@ -255,4 +255,4 @@ def test_closure_with_change(capsys): def test_closure_averager(): got = run(closure_averager_src) assert got == 12.0 -# end::RUN_AVERAGER[] \ No newline at end of file +# end::RUN_AVERAGER[] diff --git a/18-with-match/lispy/py3.9/lis.py b/18-with-match/lispy/py3.9/lis.py index 6ab8a19..e868a14 100644 --- a/18-with-match/lispy/py3.9/lis.py +++ b/18-with-match/lispy/py3.9/lis.py @@ -80,7 +80,7 @@ def standard_env() -> Environment: '-': op.sub, '*': op.mul, '/': op.truediv, - '//': op.floordiv, + 'quotient': op.floordiv, '>': op.gt, '<': op.lt, '>=': op.ge, diff --git a/20-executors/getflags/flags2_asyncio.py b/20-executors/getflags/flags2_asyncio.py index 4825db4..a922db5 100755 --- a/20-executors/getflags/flags2_asyncio.py +++ b/20-executors/getflags/flags2_asyncio.py @@ -16,37 +16,36 @@ from flags2_common import main, DownloadStatus, save_flag -# default set low to avoid errors from remote site, such as -# 503 - Service Temporarily Unavailable +# low concurrency default to avoid errors from remote site, +# such as 503 - Service Temporarily Unavailable DEFAULT_CONCUR_REQ = 5 MAX_CONCUR_REQ = 1000 -async def get_flag(session: httpx.AsyncClient, # <2> +async def get_flag(client: httpx.AsyncClient, # <1> base_url: str, cc: str) -> bytes: url = f'{base_url}/{cc}/{cc}.gif'.lower() - resp = await session.get(url, timeout=3.1, follow_redirects=True) # <3> + resp = await client.get(url, timeout=3.1, follow_redirects=True) # <2> resp.raise_for_status() return resp.content -async def download_one(session: httpx.AsyncClient, +async def download_one(client: httpx.AsyncClient, cc: str, base_url: str, - semaphore: asyncio.Semaphore, # <4> + semaphore: asyncio.Semaphore, verbose: bool) -> DownloadStatus: try: - async with semaphore: # <5> - image = await get_flag(session, base_url, cc) - except httpx.HTTPStatusError as exc: # <4> + async with semaphore: # <3> + image = await get_flag(client, base_url, cc) + except httpx.HTTPStatusError as exc: # <5> res = exc.response if res.status_code == HTTPStatus.NOT_FOUND: - status = DownloadStatus.NOT_FOUND # <5> + status = DownloadStatus.NOT_FOUND msg = f'not found: {res.url}' else: raise - else: - await asyncio.to_thread(save_flag, image, f'{cc}.gif') + await asyncio.to_thread(save_flag, image, f'{cc}.gif') # <6> status = DownloadStatus.OK msg = 'OK' if verbose and msg: @@ -61,33 +60,31 @@ async def supervisor(cc_list: list[str], concur_req: int) -> Counter[DownloadStatus]: # <1> counter: Counter[DownloadStatus] = Counter() semaphore = asyncio.Semaphore(concur_req) # <2> - async with httpx.AsyncClient() as session: - to_do = [download_one(session, cc, base_url, semaphore, verbose) + async with httpx.AsyncClient() as client: + to_do = [download_one(client, cc, base_url, semaphore, verbose) for cc in sorted(cc_list)] # <3> to_do_iter = asyncio.as_completed(to_do) # <4> if not verbose: to_do_iter = tqdm.tqdm(to_do_iter, total=len(cc_list)) # <5> - error: httpx.HTTPError | None = None - for coro in to_do_iter: # <6> + error: httpx.HTTPError | None = None # <6> + for coro in to_do_iter: # <7> try: - status = await coro # <7> - except httpx.HTTPStatusError as exc: # <8> + status = await coro # <8> + except httpx.HTTPStatusError as exc: error_msg = 'HTTP error {resp.status_code} - {resp.reason_phrase}' error_msg = error_msg.format(resp=exc.response) - error = exc - except httpx.RequestError as exc: # <9> + error = exc # <9> + except httpx.RequestError as exc: error_msg = f'{exc} {type(exc)}'.strip() - error = exc - except KeyboardInterrupt: # <10> + error = exc # <10> + except KeyboardInterrupt: break - else: # <11> - error = None if error: - status = DownloadStatus.ERROR # <12> + status = DownloadStatus.ERROR # <11> if verbose: - url = str(error.request.url) # <13> - cc = Path(url).stem.upper() # <14> + url = str(error.request.url) # <12> + cc = Path(url).stem.upper() # <13> print(f'{cc} error: {error_msg}') counter[status] += 1 From f1524171df7fd44204d33212b4af3e86b58a212a Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Mon, 18 Oct 2021 14:42:55 -0300 Subject: [PATCH 26/66] refactored drawtree.py --- 17-it-generator/tree/extra/drawtree.py | 28 +++++++++++++++ 17-it-generator/tree/extra/pretty_tree.py | 35 ------------------- .../{test_pretty_tree.py => test_drawtree.py} | 6 ++-- 3 files changed, 31 insertions(+), 38 deletions(-) create mode 100644 17-it-generator/tree/extra/drawtree.py delete mode 100644 17-it-generator/tree/extra/pretty_tree.py rename 17-it-generator/tree/extra/{test_pretty_tree.py => test_drawtree.py} (94%) diff --git a/17-it-generator/tree/extra/drawtree.py b/17-it-generator/tree/extra/drawtree.py new file mode 100644 index 0000000..043e53b --- /dev/null +++ b/17-it-generator/tree/extra/drawtree.py @@ -0,0 +1,28 @@ +from tree import tree + +SP = '\N{SPACE}' +HLIN = '\N{BOX DRAWINGS LIGHT HORIZONTAL}' # ─ +ELBOW = f'\N{BOX DRAWINGS LIGHT UP AND RIGHT}{HLIN*2}{SP}' # └── +TEE = f'\N{BOX DRAWINGS LIGHT VERTICAL AND RIGHT}{HLIN*2}{SP}' # ├── +PIPE = f'\N{BOX DRAWINGS LIGHT VERTICAL}{SP*3}' # │ + + +def render_lines(tree_iter): + name, _, _ = next(tree_iter) + yield name + prefix = '' + + for name, level, last in tree_iter: + prefix = prefix[:4 * (level-1)] + prefix = prefix.replace(TEE, PIPE).replace(ELBOW, SP*4) + prefix += ELBOW if last else TEE + yield prefix + name + + +def draw(cls): + for line in render_lines(tree(cls)): + print(line) + + +if __name__ == '__main__': + draw(BaseException) diff --git a/17-it-generator/tree/extra/pretty_tree.py b/17-it-generator/tree/extra/pretty_tree.py deleted file mode 100644 index 6d6d91a..0000000 --- a/17-it-generator/tree/extra/pretty_tree.py +++ /dev/null @@ -1,35 +0,0 @@ -from tree import tree - -SPACES = ' ' * 4 -HLINE = '\u2500' # ─ BOX DRAWINGS LIGHT HORIZONTAL -HLINE2 = HLINE * 2 -ELBOW = f'\u2514{HLINE2} ' # └ BOX DRAWINGS LIGHT UP AND RIGHT -TEE = f'\u251C{HLINE2} ' # ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT -PIPE = '\u2502 ' # │ BOX DRAWINGS LIGHT VERTICAL - - -def render_lines(tree_iter): - name, _, _ = next(tree_iter) - yield name - prefix = '' - - for name, level, last in tree_iter: - if last: - connector = ELBOW - else: - connector = TEE - - prefix = prefix[:4 * (level-1)] - prefix = prefix.replace(TEE, PIPE).replace(ELBOW, SPACES) - prefix += connector - - yield prefix + name - - -def display(cls): - for line in render_lines(tree(cls)): - print(line) - - -if __name__ == '__main__': - display(BaseException) diff --git a/17-it-generator/tree/extra/test_pretty_tree.py b/17-it-generator/tree/extra/test_drawtree.py similarity index 94% rename from 17-it-generator/tree/extra/test_pretty_tree.py rename to 17-it-generator/tree/extra/test_drawtree.py index 70019a3..f66dfa4 100644 --- a/17-it-generator/tree/extra/test_pretty_tree.py +++ b/17-it-generator/tree/extra/test_drawtree.py @@ -1,4 +1,4 @@ -from pretty_tree import tree, render_lines +from drawtree import tree, render_lines def test_1_level(): result = list(render_lines(tree(BrokenPipeError))) @@ -59,7 +59,7 @@ class Leaf2(Branch): pass assert expected == result -def test_3_levels_2_leaves(): +def test_3_levels_2_leaves_dedent(): class A: pass class B(A): pass class C(B): pass @@ -77,7 +77,7 @@ class E(D): pass assert expected == result -def test_4_levels_4_leaves(): +def test_4_levels_4_leaves_dedent(): class A: pass class B1(A): pass class C1(B1): pass From c41611668dbc9431370b1b61dfdab80497794432 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Mon, 18 Oct 2021 14:57:06 -0300 Subject: [PATCH 27/66] refactored drawtree.py --- 17-it-generator/tree/extra/drawtree.py | 8 ++++---- 17-it-generator/tree/extra/test_tree.py | 18 ++++++++++++------ 17-it-generator/tree/extra/tree.py | 8 ++++---- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/17-it-generator/tree/extra/drawtree.py b/17-it-generator/tree/extra/drawtree.py index 043e53b..522666a 100644 --- a/17-it-generator/tree/extra/drawtree.py +++ b/17-it-generator/tree/extra/drawtree.py @@ -8,15 +8,15 @@ def render_lines(tree_iter): - name, _, _ = next(tree_iter) - yield name + cls, _, _ = next(tree_iter) + yield cls.__name__ prefix = '' - for name, level, last in tree_iter: + for cls, level, last in tree_iter: prefix = prefix[:4 * (level-1)] prefix = prefix.replace(TEE, PIPE).replace(ELBOW, SP*4) prefix += ELBOW if last else TEE - yield prefix + name + yield prefix + cls.__name__ def draw(cls): diff --git a/17-it-generator/tree/extra/test_tree.py b/17-it-generator/tree/extra/test_tree.py index 4c6404c..b06cf3b 100644 --- a/17-it-generator/tree/extra/test_tree.py +++ b/17-it-generator/tree/extra/test_tree.py @@ -4,7 +4,8 @@ def test_1_level(): class One: pass expected = [('One', 0, True)] - result = list(tree(One)) + result = [(cls.__name__, level, last) + for cls, level, last in tree(One)] assert expected == result @@ -17,7 +18,8 @@ class Leaf2(Branch): pass ('Leaf1', 1, False), ('Leaf2', 1, True), ] - result = list(tree(Branch)) + result = [(cls.__name__, level, last) + for cls, level, last in tree(Branch)] assert expected == result @@ -30,7 +32,8 @@ class Z(Y): pass ('Y', 1, True), ('Z', 2, True), ] - result = list(tree(X)) + result = [(cls.__name__, level, last) + for cls, level, last in tree(X)] assert expected == result @@ -46,7 +49,8 @@ class Level3(Level2): pass ('Level3', 3, True), ] - result = list(tree(Level0)) + result = [(cls.__name__, level, last) + for cls, level, last in tree(Level0)] assert expected == result @@ -68,7 +72,8 @@ class D2(C1): pass ('C2', 2, True), ] - result = list(tree(A)) + result = [(cls.__name__, level, last) + for cls, level, last in tree(A)] assert expected == result @@ -83,7 +88,8 @@ class Root: pass expected.append((name, level, True)) parent = cls - result = list(tree(Root)) + result = [(cls.__name__, level, last) + for cls, level, last in tree(Root)] assert len(result) == level_count assert result[0] == ('Root', 0, True) assert result[-1] == ('Sub99', 99, True) diff --git a/17-it-generator/tree/extra/tree.py b/17-it-generator/tree/extra/tree.py index 7169a28..aeebd37 100644 --- a/17-it-generator/tree/extra/tree.py +++ b/17-it-generator/tree/extra/tree.py @@ -1,5 +1,5 @@ -def tree(cls, level=0, last_in_level=True): - yield cls.__name__, level, last_in_level +def tree(cls, level=0, last_sibling=True): + yield cls, level, last_sibling subclasses = cls.__subclasses__() if subclasses: last = subclasses[-1] @@ -8,9 +8,9 @@ def tree(cls, level=0, last_in_level=True): def display(cls): - for cls_name, level, _ in tree(cls): + for cls, level, _ in tree(cls): indent = ' ' * 4 * level - print(f'{indent}{cls_name}') + print(f'{indent}{cls.__name__}') if __name__ == '__main__': From 7c155cb33725666349867020ec022b78aa3e531e Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Mon, 18 Oct 2021 15:22:46 -0300 Subject: [PATCH 28/66] draw tree of HTTPX exceptions --- .../getflags/httpx-error-tree/drawtree.py | 35 +++++++++++++++++++ .../getflags/httpx-error-tree/tree.py | 24 +++++++++++++ 2 files changed, 59 insertions(+) create mode 100755 20-executors/getflags/httpx-error-tree/drawtree.py create mode 100755 20-executors/getflags/httpx-error-tree/tree.py diff --git a/20-executors/getflags/httpx-error-tree/drawtree.py b/20-executors/getflags/httpx-error-tree/drawtree.py new file mode 100755 index 0000000..f2d9fea --- /dev/null +++ b/20-executors/getflags/httpx-error-tree/drawtree.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 + +from tree import tree + + +SP = '\N{SPACE}' +HLIN = '\N{BOX DRAWINGS LIGHT HORIZONTAL}' # ─ +ELBOW = f'\N{BOX DRAWINGS LIGHT UP AND RIGHT}{HLIN*2}{SP}' # └── +TEE = f'\N{BOX DRAWINGS LIGHT VERTICAL AND RIGHT}{HLIN*2}{SP}' # ├── +PIPE = f'\N{BOX DRAWINGS LIGHT VERTICAL}{SP*3}' # │ + + +def cls_name(cls): + module = 'builtins.' if cls.__module__ == 'builtins' else '' + return module + cls.__name__ + +def render_lines(tree_iter): + cls, _, _ = next(tree_iter) + yield cls_name(cls) + prefix = '' + + for cls, level, last in tree_iter: + prefix = prefix[:4 * (level-1)] + prefix = prefix.replace(TEE, PIPE).replace(ELBOW, SP*4) + prefix += ELBOW if last else TEE + yield prefix + cls_name(cls) + + +def draw(cls): + for line in render_lines(tree(cls)): + print(line) + + +if __name__ == '__main__': + draw(Exception) diff --git a/20-executors/getflags/httpx-error-tree/tree.py b/20-executors/getflags/httpx-error-tree/tree.py new file mode 100755 index 0000000..9b905f2 --- /dev/null +++ b/20-executors/getflags/httpx-error-tree/tree.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 + +import httpx # make httpx classes available to .__subclasses__() + + +def tree(cls, level=0, last_sibling=True): + yield cls, level, last_sibling + subclasses = [c for c in cls.__subclasses__() + if c.__module__ == 'httpx' or c is RuntimeError] + if subclasses: + last = subclasses[-1] + for sub_cls in subclasses: + yield from tree(sub_cls, level+1, sub_cls is last) + + +def display(cls): + for cls, level, _ in tree(cls): + indent = ' ' * 4 * level + module = 'builtins.' if cls.__module__ == 'builtins' else '' + print(f'{indent}{module}{cls.__name__}') + + +if __name__ == '__main__': + display(Exception) From ce7d45154ff29048e2002e4f4491f199807e3281 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Mon, 18 Oct 2021 16:42:59 -0300 Subject: [PATCH 29/66] draw tree of HTTPX exceptions --- 20-executors/getflags/httpx-error-tree/tree.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/20-executors/getflags/httpx-error-tree/tree.py b/20-executors/getflags/httpx-error-tree/tree.py index 9b905f2..7b82975 100755 --- a/20-executors/getflags/httpx-error-tree/tree.py +++ b/20-executors/getflags/httpx-error-tree/tree.py @@ -5,12 +5,13 @@ def tree(cls, level=0, last_sibling=True): yield cls, level, last_sibling - subclasses = [c for c in cls.__subclasses__() - if c.__module__ == 'httpx' or c is RuntimeError] + # get RuntimeError and exceptions defined in httpx + subclasses = [sub for sub in cls.__subclasses__() + if sub is RuntimeError or sub.__module__ == 'httpx'] if subclasses: last = subclasses[-1] - for sub_cls in subclasses: - yield from tree(sub_cls, level+1, sub_cls is last) + for sub in subclasses: + yield from tree(sub, level+1, sub is last) def display(cls): From 07083b8240c9886bb0b4615c81f4d89ecaede1ba Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Mon, 18 Oct 2021 16:45:15 -0300 Subject: [PATCH 30/66] draw tree of HTTPX exceptions --- 20-executors/getflags/httpx-error-tree/tree.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/20-executors/getflags/httpx-error-tree/tree.py b/20-executors/getflags/httpx-error-tree/tree.py index 7b82975..eff7870 100755 --- a/20-executors/getflags/httpx-error-tree/tree.py +++ b/20-executors/getflags/httpx-error-tree/tree.py @@ -10,8 +10,8 @@ def tree(cls, level=0, last_sibling=True): if sub is RuntimeError or sub.__module__ == 'httpx'] if subclasses: last = subclasses[-1] - for sub in subclasses: - yield from tree(sub, level+1, sub is last) + for sub in subclasses: + yield from tree(sub, level+1, sub is last) def display(cls): From f5e3cb8ad32bdf183cee85a17c6105d51538b751 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Fri, 22 Oct 2021 14:59:04 -0300 Subject: [PATCH 31/66] minor refactorings --- 17-it-generator/tree/classtree/classtree.py | 75 ++++++++ .../tree/classtree/classtree_test.py | 181 ++++++++++++++++++ 17-it-generator/tree/extra/drawtree.py | 30 ++- 3 files changed, 279 insertions(+), 7 deletions(-) create mode 100755 17-it-generator/tree/classtree/classtree.py create mode 100644 17-it-generator/tree/classtree/classtree_test.py diff --git a/17-it-generator/tree/classtree/classtree.py b/17-it-generator/tree/classtree/classtree.py new file mode 100755 index 0000000..56bbec3 --- /dev/null +++ b/17-it-generator/tree/classtree/classtree.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 + +from importlib import import_module +import sys + + +SP = '\N{SPACE}' +HLIN = '\N{BOX DRAWINGS LIGHT HORIZONTAL}' * 2 + SP # ── +VLIN = '\N{BOX DRAWINGS LIGHT VERTICAL}' + SP * 3 # │ +TEE = '\N{BOX DRAWINGS LIGHT VERTICAL AND RIGHT}' + HLIN # ├── +ELBOW = '\N{BOX DRAWINGS LIGHT UP AND RIGHT}' + HLIN # └── + + +def subclasses(cls): + try: + return cls.__subclasses__() + except TypeError: # handle the `type` type + return cls.__subclasses__(cls) + + +def tree(cls, level=0, last_sibling=True): + yield cls, level, last_sibling + chidren = subclasses(cls) + if chidren: + last = chidren[-1] + for child in chidren: + yield from tree(child, level + 1, child is last) + + +def render_lines(tree_generator): + cls, _, _ = next(tree_generator) + yield cls.__name__ + prefix = '' + for cls, level, last in tree_generator: + prefix = prefix[: 4 * (level - 1)] + prefix = prefix.replace(TEE, VLIN).replace(ELBOW, SP * 4) + prefix += ELBOW if last else TEE + yield prefix + cls.__name__ + + +def draw(cls): + for line in render_lines(tree(cls)): + print(line) + + +def parse(name): + if '.' in name: + return name.rsplit('.', 1) + else: + return 'builtins', name + + +def main(name): + module_name, cls_name = parse(name) + try: + cls = getattr(import_module(module_name), cls_name) + except ModuleNotFoundError: + print(f'*** Could not import {module_name!r}.') + except AttributeError: + print(f'*** {cls_name!r} not found in {module_name!r}.') + else: + if isinstance(cls, type): + draw(cls) + else: + print(f'*** {cls_name!r} is not a class.') + + +if __name__ == '__main__': + if len(sys.argv) == 2: + main(sys.argv[1]) + else: + print('Usage:' + f'\t{sys.argv[0]} Class # for builtin classes\n' + f'\t{sys.argv[0]} package.Class # for other classes' + ) diff --git a/17-it-generator/tree/classtree/classtree_test.py b/17-it-generator/tree/classtree/classtree_test.py new file mode 100644 index 0000000..4535747 --- /dev/null +++ b/17-it-generator/tree/classtree/classtree_test.py @@ -0,0 +1,181 @@ +from textwrap import dedent +from typing import SupportsBytes +from classtree import tree, render_lines, main, subclasses + +from abc import ABCMeta + + +def test_subclasses(): + result = subclasses(UnicodeError) + assert set(result) >= {UnicodeEncodeError, UnicodeDecodeError} + + +def test_subclasses_of_type(): + """ + The `type` class is a special case because `type.__subclasses__()` + is an unbound method when called on it, so we must call it as + `type.__subclasses__(type)` just for `type`. + + This test does not verify the full list of results, but just + checks that `abc.ABCMeta` is included, because that's the only + subclass of `type` (i.e. metaclass) I we get when I run + `$ classtree.py type` at the command line. + + However, the Python console and `pytest` both load other modules, + so `subclasses` may find more subclasses of `type`—for example, + `enum.EnumMeta`. + """ + result = subclasses(type) + assert ABCMeta in result + + +def test_tree_1_level(): + result = list(tree(TabError)) + assert result == [(TabError, 0, True)] + + +def test_tree_2_levels(): + result = list(tree(IndentationError)) + assert result == [ + (IndentationError, 0, True), + (TabError, 1, True), + ] + + +def test_render_lines_1_level(): + result = list(render_lines(tree(TabError))) + assert result == ['TabError'] + + +def test_render_lines_2_levels_1_leaf(): + result = list(render_lines(tree(IndentationError))) + expected = [ + 'IndentationError', + '└── TabError', + ] + assert expected == result + + +def test_render_lines_3_levels_1_leaf(): + class X: pass + class Y(X): pass + class Z(Y): pass + result = list(render_lines(tree(X))) + expected = [ + 'X', + '└── Y', + ' └── Z', + ] + assert expected == result + + +def test_render_lines_4_levels_1_leaf(): + class Level0: pass + class Level1(Level0): pass + class Level2(Level1): pass + class Level3(Level2): pass + + result = list(render_lines(tree(Level0))) + expected = [ + 'Level0', + '└── Level1', + ' └── Level2', + ' └── Level3', + ] + assert expected == result + + +def test_render_lines_2_levels_2_leaves(): + class Branch: pass + class Leaf1(Branch): pass + class Leaf2(Branch): pass + result = list(render_lines(tree(Branch))) + expected = [ + 'Branch', + '├── Leaf1', + '└── Leaf2', + ] + assert expected == result + + +def test_render_lines_3_levels_2_leaves_dedent(): + class A: pass + class B(A): pass + class C(B): pass + class D(A): pass + class E(D): pass + + result = list(render_lines(tree(A))) + expected = [ + 'A', + '├── B', + '│ └── C', + '└── D', + ' └── E', + ] + assert expected == result + + +def test_render_lines_4_levels_4_leaves_dedent(): + class A: pass + class B1(A): pass + class C1(B1): pass + class D1(C1): pass + class D2(C1): pass + class C2(B1): pass + class B2(A): pass + expected = [ + 'A', + '├── B1', + '│ ├── C1', + '│ │ ├── D1', + '│ │ └── D2', + '│ └── C2', + '└── B2', + ] + + result = list(render_lines(tree(A))) + assert expected == result + + +def test_main_simple(capsys): + main('IndentationError') + expected = dedent(""" + IndentationError + └── TabError + """).lstrip() + captured = capsys.readouterr() + assert captured.out == expected + + +def test_main_dotted(capsys): + main('collections.abc.Sequence') + expected = dedent(""" + Sequence + ├── ByteString + ├── MutableSequence + │ └── UserList + """).lstrip() + captured = capsys.readouterr() + assert captured.out.startswith(expected) + + +def test_main_class_not_found(capsys): + main('NoSuchClass') + expected = "*** 'NoSuchClass' not found in 'builtins'.\n" + captured = capsys.readouterr() + assert captured.out == expected + + +def test_main_module_not_found(capsys): + main('nosuch.module') + expected = "*** Could not import 'nosuch'.\n" + captured = capsys.readouterr() + assert captured.out == expected + + +def test_main_not_a_class(capsys): + main('collections.abc') + expected = "*** 'abc' is not a class.\n" + captured = capsys.readouterr() + assert captured.out == expected diff --git a/17-it-generator/tree/extra/drawtree.py b/17-it-generator/tree/extra/drawtree.py index 522666a..b74cd33 100644 --- a/17-it-generator/tree/extra/drawtree.py +++ b/17-it-generator/tree/extra/drawtree.py @@ -1,10 +1,26 @@ from tree import tree -SP = '\N{SPACE}' -HLIN = '\N{BOX DRAWINGS LIGHT HORIZONTAL}' # ─ -ELBOW = f'\N{BOX DRAWINGS LIGHT UP AND RIGHT}{HLIN*2}{SP}' # └── -TEE = f'\N{BOX DRAWINGS LIGHT VERTICAL AND RIGHT}{HLIN*2}{SP}' # ├── -PIPE = f'\N{BOX DRAWINGS LIGHT VERTICAL}{SP*3}' # │ +SP = '\N{SPACE}' +HLIN = '\N{BOX DRAWINGS LIGHT HORIZONTAL}' * 2 + SP # ── +VLIN = '\N{BOX DRAWINGS LIGHT VERTICAL}' + SP * 3 # │ +TEE = '\N{BOX DRAWINGS LIGHT VERTICAL AND RIGHT}' + HLIN # ├── +ELBOW = '\N{BOX DRAWINGS LIGHT UP AND RIGHT}' + HLIN # └── + + +def subclasses(cls): + try: + return cls.__subclasses__() + except TypeError: # handle the `type` type + return cls.__subclasses__(cls) + + +def tree(cls, level=0, last_sibling=True): + yield cls, level, last_sibling + children = subclasses(cls) + if children: + last = children[-1] + for child in children: + yield from tree(child, level+1, child is last) def render_lines(tree_iter): @@ -13,8 +29,8 @@ def render_lines(tree_iter): prefix = '' for cls, level, last in tree_iter: - prefix = prefix[:4 * (level-1)] - prefix = prefix.replace(TEE, PIPE).replace(ELBOW, SP*4) + prefix = prefix[:4 * (level - 1)] + prefix = prefix.replace(TEE, VLIN).replace(ELBOW, SP * 4) prefix += ELBOW if last else TEE yield prefix + cls.__name__ From 80f7f84274a47579e59c29a4657691525152c9d5 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Fri, 12 Nov 2021 11:33:12 -0300 Subject: [PATCH 32/66] 2e reviewed manuscript --- 02-array-seq/lispy/py3.10/lis.py | 10 +- 11-pythonic-obj/vector2d_v3.py | 4 +- 11-pythonic-obj/vector2d_v3_prophash.py | 4 +- 11-pythonic-obj/vector2d_v3_slots.py | 4 +- 18-with-match/lispy/py3.10/examples_test.py | 6 +- 18-with-match/lispy/py3.10/lis.py | 2 +- 18-with-match/lispy/py3.9/lis.py | 2 +- 20-executors/getflags/flags2_asyncio.py | 4 +- .../getflags/flags2_asyncio_executor.py | 12 +- 20-executors/getflags/flags3_asyncio.py | 119 ++++++++++++++++++ 20-executors/getflags/flags_asyncio.py | 12 +- .../getflags/httpx-error-tree/tree.py | 1 + 20-executors/getflags/tree.py | 38 ------ 21-async/mojifinder/tcp_mojifinder.py | 24 ++-- 21-async/mojifinder/web_mojifinder.py | 13 +- 22-dyn-attr-prop/bulkfood/bulkfood_v2prop.py | 4 +- 22-dyn-attr-prop/oscon/explore0.py | 11 +- 22-dyn-attr-prop/oscon/explore1.py | 7 +- 22-dyn-attr-prop/oscon/explore2.py | 7 +- 22-dyn-attr-prop/oscon/schedule_v1.py | 3 +- 22-dyn-attr-prop/oscon/schedule_v2.py | 10 +- 22-dyn-attr-prop/oscon/schedule_v3.py | 12 +- 22-dyn-attr-prop/oscon/schedule_v4.py | 12 +- 22-dyn-attr-prop/oscon/schedule_v4_hasattr.py | 12 +- 22-dyn-attr-prop/oscon/schedule_v5.py | 10 +- 23-descriptor/bulkfood/model_v5.py | 4 +- 23-descriptor/descriptorkinds.py | 25 ++-- .../checked/metaclass/checkedlib.py | 4 +- 24-class-metaprog/factories.py | 5 +- 24-class-metaprog/metabunch/from3.6/bunch.py | 5 +- .../metabunch/from3.6/bunch_test.py | 2 +- 24-class-metaprog/timeslice.py | 91 ++++++++++++++ 32 files changed, 323 insertions(+), 156 deletions(-) create mode 100755 20-executors/getflags/flags3_asyncio.py delete mode 100644 20-executors/getflags/tree.py create mode 100644 24-class-metaprog/timeslice.py diff --git a/02-array-seq/lispy/py3.10/lis.py b/02-array-seq/lispy/py3.10/lis.py index 150fca7..88d9345 100755 --- a/02-array-seq/lispy/py3.10/lis.py +++ b/02-array-seq/lispy/py3.10/lis.py @@ -84,7 +84,7 @@ def standard_env() -> Environment: '-': op.sub, '*': op.mul, '/': op.truediv, - '//': op.floordiv, + 'quotient': op.floordiv, '>': op.gt, '<': op.lt, '>=': op.ge, @@ -149,7 +149,7 @@ def evaluate(exp: Expression, env: Environment) -> Any: # end::EVAL_MATCH_TOP[] case int(x) | float(x): return x - case Symbol(name): + case Symbol() as name: return env[name] # tag::EVAL_MATCH_MIDDLE[] case ['quote', x]: # <1> @@ -161,12 +161,12 @@ def evaluate(exp: Expression, env: Environment) -> Any: return evaluate(alternative, env) case ['lambda', [*parms], *body] if body: # <3> return Procedure(parms, body, env) - case ['define', Symbol(name), value_exp]: # <4> + case ['define', Symbol() as name, value_exp]: # <4> env[name] = evaluate(value_exp, env) # end::EVAL_MATCH_MIDDLE[] - case ['define', [Symbol(name), *parms], *body] if body: + case ['define', [Symbol() as name, *parms], *body] if body: env[name] = Procedure(parms, body, env) - case ['set!', Symbol(name), value_exp]: + case ['set!', Symbol() as name, value_exp]: env.change(name, evaluate(value_exp, env)) case [func_exp, *args] if func_exp not in KEYWORDS: proc = evaluate(func_exp, env) diff --git a/11-pythonic-obj/vector2d_v3.py b/11-pythonic-obj/vector2d_v3.py index 9ee716c..0edffb7 100644 --- a/11-pythonic-obj/vector2d_v3.py +++ b/11-pythonic-obj/vector2d_v3.py @@ -79,8 +79,6 @@ >>> v1 = Vector2d(3, 4) >>> v2 = Vector2d(3.1, 4.2) - >>> hash(v1), hash(v2) - (7, 384307168202284039) >>> len({v1, v2}) 2 @@ -124,7 +122,7 @@ def __eq__(self, other): return tuple(self) == tuple(other) def __hash__(self): - return hash(self.x) ^ hash(self.y) + return hash((self.x, self.y)) def __abs__(self): return math.hypot(self.x, self.y) diff --git a/11-pythonic-obj/vector2d_v3_prophash.py b/11-pythonic-obj/vector2d_v3_prophash.py index 6d7dceb..1652cd4 100644 --- a/11-pythonic-obj/vector2d_v3_prophash.py +++ b/11-pythonic-obj/vector2d_v3_prophash.py @@ -81,8 +81,6 @@ >>> v1 = Vector2d(3, 4) >>> v2 = Vector2d(3.1, 4.2) - >>> hash(v1), hash(v2) - (7, 384307168202284039) >>> len({v1, v2}) 2 @@ -131,7 +129,7 @@ def __eq__(self, other): # tag::VECTOR_V3_HASH[] def __hash__(self): - return hash(self.x) ^ hash(self.y) + return hash((self.x, self.y)) # end::VECTOR_V3_HASH[] def __abs__(self): diff --git a/11-pythonic-obj/vector2d_v3_slots.py b/11-pythonic-obj/vector2d_v3_slots.py index c48fb5b..89da973 100644 --- a/11-pythonic-obj/vector2d_v3_slots.py +++ b/11-pythonic-obj/vector2d_v3_slots.py @@ -78,8 +78,6 @@ >>> v1 = Vector2d(3, 4) >>> v2 = Vector2d(3.1, 4.2) - >>> hash(v1), hash(v2) - (7, 384307168202284039) >>> len({v1, v2}) 2 @@ -126,7 +124,7 @@ def __eq__(self, other): return tuple(self) == tuple(other) def __hash__(self): - return hash(self.x) ^ hash(self.y) + return hash((self.x, self.y)) def __abs__(self): return math.hypot(self.x, self.y) diff --git a/18-with-match/lispy/py3.10/examples_test.py b/18-with-match/lispy/py3.10/examples_test.py index d207df0..7025dad 100644 --- a/18-with-match/lispy/py3.10/examples_test.py +++ b/18-with-match/lispy/py3.10/examples_test.py @@ -27,11 +27,13 @@ >>> inner_env = {'a': 2} >>> outer_env = {'a': 0, 'b': 1} >>> env = Environment(inner_env, outer_env) ->>> env['a'] = 111 # <1> +>>> env['a'] # <1> +2 +>>> env['a'] = 111 # <2> >>> env['c'] = 222 >>> env Environment({'a': 111, 'c': 222}, {'a': 0, 'b': 1}) ->>> env.change('b', 333) # <2> +>>> env.change('b', 333) # <3> >>> env Environment({'a': 111, 'c': 222}, {'a': 0, 'b': 333}) diff --git a/18-with-match/lispy/py3.10/lis.py b/18-with-match/lispy/py3.10/lis.py index 04cc28d..f2d982c 100755 --- a/18-with-match/lispy/py3.10/lis.py +++ b/18-with-match/lispy/py3.10/lis.py @@ -65,7 +65,7 @@ def parse_atom(token: str) -> Atom: class Environment(ChainMap[Symbol, Any]): "A ChainMap that allows changing an item in-place." - def change(self, key: Symbol, value: object) -> None: + def change(self, key: Symbol, value: Any) -> None: "Find where key is defined and change the value there." for map in self.maps: if key in map: diff --git a/18-with-match/lispy/py3.9/lis.py b/18-with-match/lispy/py3.9/lis.py index e868a14..e467211 100644 --- a/18-with-match/lispy/py3.9/lis.py +++ b/18-with-match/lispy/py3.9/lis.py @@ -62,7 +62,7 @@ def parse_atom(token: str) -> Atom: class Environment(ChainMap[Symbol, Any]): "A ChainMap that allows changing an item in-place." - def change(self, key: Symbol, value: object) -> None: + def change(self, key: Symbol, value: Any) -> None: "Find where key is defined and change the value there." for map in self.maps: if key in map: diff --git a/20-executors/getflags/flags2_asyncio.py b/20-executors/getflags/flags2_asyncio.py index a922db5..4f1849a 100755 --- a/20-executors/getflags/flags2_asyncio.py +++ b/20-executors/getflags/flags2_asyncio.py @@ -37,7 +37,7 @@ async def download_one(client: httpx.AsyncClient, try: async with semaphore: # <3> image = await get_flag(client, base_url, cc) - except httpx.HTTPStatusError as exc: # <5> + except httpx.HTTPStatusError as exc: # <4> res = exc.response if res.status_code == HTTPStatus.NOT_FOUND: status = DownloadStatus.NOT_FOUND @@ -45,7 +45,7 @@ async def download_one(client: httpx.AsyncClient, else: raise else: - await asyncio.to_thread(save_flag, image, f'{cc}.gif') # <6> + await asyncio.to_thread(save_flag, image, f'{cc}.gif') # <5> status = DownloadStatus.OK msg = 'OK' if verbose and msg: diff --git a/20-executors/getflags/flags2_asyncio_executor.py b/20-executors/getflags/flags2_asyncio_executor.py index 752b60f..62516b3 100755 --- a/20-executors/getflags/flags2_asyncio_executor.py +++ b/20-executors/getflags/flags2_asyncio_executor.py @@ -22,23 +22,23 @@ MAX_CONCUR_REQ = 1000 -async def get_flag(session: httpx.AsyncClient, # <2> +async def get_flag(client: httpx.AsyncClient, # <2> base_url: str, cc: str) -> bytes: url = f'{base_url}/{cc}/{cc}.gif'.lower() - resp = await session.get(url, timeout=3.1, follow_redirects=True) # <3> + resp = await client.get(url, timeout=3.1, follow_redirects=True) # <3> resp.raise_for_status() return resp.content -async def download_one(session: httpx.AsyncClient, +async def download_one(client: httpx.AsyncClient, cc: str, base_url: str, semaphore: asyncio.Semaphore, verbose: bool) -> DownloadStatus: try: async with semaphore: - image = await get_flag(session, base_url, cc) + image = await get_flag(client, base_url, cc) except httpx.HTTPStatusError as exc: res = exc.response if res.status_code == HTTPStatus.NOT_FOUND: @@ -64,8 +64,8 @@ async def supervisor(cc_list: list[str], concur_req: int) -> Counter[DownloadStatus]: # <1> counter: Counter[DownloadStatus] = Counter() semaphore = asyncio.Semaphore(concur_req) # <2> - async with httpx.AsyncClient() as session: - to_do = [download_one(session, cc, base_url, semaphore, verbose) + async with httpx.AsyncClient() as client: + to_do = [download_one(client, cc, base_url, semaphore, verbose) for cc in sorted(cc_list)] # <3> to_do_iter = asyncio.as_completed(to_do) # <4> if not verbose: diff --git a/20-executors/getflags/flags3_asyncio.py b/20-executors/getflags/flags3_asyncio.py new file mode 100755 index 0000000..9554dd2 --- /dev/null +++ b/20-executors/getflags/flags3_asyncio.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python3 + +"""Download flags of countries (with error handling). + +asyncio async/await version + +""" +# tag::FLAGS2_ASYNCIO_TOP[] +import asyncio +from collections import Counter +from http import HTTPStatus +from pathlib import Path + +import httpx +import tqdm # type: ignore + +from flags2_common import main, DownloadStatus, save_flag + +# low concurrency default to avoid errors from remote site, +# such as 503 - Service Temporarily Unavailable +DEFAULT_CONCUR_REQ = 5 +MAX_CONCUR_REQ = 1000 + +async def get_flag(client: httpx.AsyncClient, # <1> + base_url: str, + cc: str) -> bytes: + url = f'{base_url}/{cc}/{cc}.gif'.lower() + resp = await client.get(url, timeout=3.1, follow_redirects=True) # <2> + resp.raise_for_status() + return resp.content + +# tag::FLAGS3_ASYNCIO_GET_COUNTRY[] +async def get_country(client: httpx.AsyncClient, + base_url: str, + cc: str) -> str: # <1> + url = f'{base_url}/{cc}/metadata.json'.lower() + resp = await client.get(url, timeout=3.1, follow_redirects=True) + resp.raise_for_status() + metadata = resp.json() # <2> + return metadata['country'] # <3> +# end::FLAGS3_ASYNCIO_GET_COUNTRY[] + +# tag::FLAGS3_ASYNCIO_DOWNLOAD_ONE[] +async def download_one(client: httpx.AsyncClient, + cc: str, + base_url: str, + semaphore: asyncio.Semaphore, + verbose: bool) -> DownloadStatus: + try: + async with semaphore: # <1> + image = await get_flag(client, base_url, cc) + async with semaphore: # <2> + country = await get_country(client, base_url, cc) + except httpx.HTTPStatusError as exc: + res = exc.response + if res.status_code == HTTPStatus.NOT_FOUND: + status = DownloadStatus.NOT_FOUND + msg = f'not found: {res.url}' + else: + raise + else: + filename = country.replace(' ', '_') # <3> + await asyncio.to_thread(save_flag, image, f'{filename}.gif') + status = DownloadStatus.OK + msg = 'OK' + if verbose and msg: + print(cc, msg) + return status +# end::FLAGS3_ASYNCIO_DOWNLOAD_ONE[] + +# tag::FLAGS2_ASYNCIO_START[] +async def supervisor(cc_list: list[str], + base_url: str, + verbose: bool, + concur_req: int) -> Counter[DownloadStatus]: # <1> + counter: Counter[DownloadStatus] = Counter() + semaphore = asyncio.Semaphore(concur_req) # <2> + async with httpx.AsyncClient() as client: + to_do = [download_one(client, cc, base_url, semaphore, verbose) + for cc in sorted(cc_list)] # <3> + to_do_iter = asyncio.as_completed(to_do) # <4> + if not verbose: + to_do_iter = tqdm.tqdm(to_do_iter, total=len(cc_list)) # <5> + error: httpx.HTTPError | None = None # <6> + for coro in to_do_iter: # <7> + try: + status = await coro # <8> + except httpx.HTTPStatusError as exc: + error_msg = 'HTTP error {resp.status_code} - {resp.reason_phrase}' + error_msg = error_msg.format(resp=exc.response) + error = exc # <9> + except httpx.RequestError as exc: + error_msg = f'{exc} {type(exc)}'.strip() + error = exc # <10> + except KeyboardInterrupt: + break + + if error: + status = DownloadStatus.ERROR # <11> + if verbose: + url = str(error.request.url) # <12> + cc = Path(url).stem.upper() # <13> + print(f'{cc} error: {error_msg}') + counter[status] += 1 + + return counter + +def download_many(cc_list: list[str], + base_url: str, + verbose: bool, + concur_req: int) -> Counter[DownloadStatus]: + coro = supervisor(cc_list, base_url, verbose, concur_req) + counts = asyncio.run(coro) # <14> + + return counts + +if __name__ == '__main__': + main(download_many, DEFAULT_CONCUR_REQ, MAX_CONCUR_REQ) +# end::FLAGS2_ASYNCIO_START[] diff --git a/20-executors/getflags/flags_asyncio.py b/20-executors/getflags/flags_asyncio.py index ba28065..588d166 100755 --- a/20-executors/getflags/flags_asyncio.py +++ b/20-executors/getflags/flags_asyncio.py @@ -17,15 +17,15 @@ from flags import BASE_URL, save_flag, main # <2> -async def download_one(session: AsyncClient, cc: str): # <3> - image = await get_flag(session, cc) +async def download_one(client: AsyncClient, cc: str): # <3> + image = await get_flag(client, cc) save_flag(image, f'{cc}.gif') print(cc, end=' ', flush=True) return cc -async def get_flag(session: AsyncClient, cc: str) -> bytes: # <4> +async def get_flag(client: AsyncClient, cc: str) -> bytes: # <4> url = f'{BASE_URL}/{cc}/{cc}.gif'.lower() - resp = await session.get(url, timeout=6.1, + resp = await client.get(url, timeout=6.1, follow_redirects=True) # <5> return resp.read() # <6> # end::FLAGS_ASYNCIO_TOP[] @@ -35,8 +35,8 @@ def download_many(cc_list: list[str]) -> int: # <1> return asyncio.run(supervisor(cc_list)) # <2> async def supervisor(cc_list: list[str]) -> int: - async with AsyncClient() as session: # <3> - to_do = [download_one(session, cc) + async with AsyncClient() as client: # <3> + to_do = [download_one(client, cc) for cc in sorted(cc_list)] # <4> res = await asyncio.gather(*to_do) # <5> diff --git a/20-executors/getflags/httpx-error-tree/tree.py b/20-executors/getflags/httpx-error-tree/tree.py index eff7870..950bbfe 100755 --- a/20-executors/getflags/httpx-error-tree/tree.py +++ b/20-executors/getflags/httpx-error-tree/tree.py @@ -5,6 +5,7 @@ def tree(cls, level=0, last_sibling=True): yield cls, level, last_sibling + # get RuntimeError and exceptions defined in httpx subclasses = [sub for sub in cls.__subclasses__() if sub is RuntimeError or sub.__module__ == 'httpx'] diff --git a/20-executors/getflags/tree.py b/20-executors/getflags/tree.py deleted file mode 100644 index 4f65697..0000000 --- a/20-executors/getflags/tree.py +++ /dev/null @@ -1,38 +0,0 @@ -import httpx - -def tree(cls, level=0): - yield cls.__name__, level - for sub_cls in cls.__subclasses__(): - yield from tree(sub_cls, level+1) - - -def display(cls): - for cls_name, level in tree(cls): - indent = ' ' * 4 * level - print(f'{indent}{cls_name}') - - -def find_roots(module): - exceptions = [] - for name in dir(module): - obj = getattr(module, name) - if isinstance(obj, type) and issubclass(obj, BaseException): - exceptions.append(obj) - roots = [] - for exc in exceptions: - root = True - for other in exceptions: - if exc is not other and issubclass(exc, other): - root = False - break - if root: - roots.append(exc) - return roots - - -def main(): - for exc in find_roots(httpx): - display(exc) - -if __name__ == '__main__': - main() diff --git a/21-async/mojifinder/tcp_mojifinder.py b/21-async/mojifinder/tcp_mojifinder.py index 8ff4e50..4da7188 100755 --- a/21-async/mojifinder/tcp_mojifinder.py +++ b/21-async/mojifinder/tcp_mojifinder.py @@ -14,26 +14,28 @@ async def finder(index: InvertedIndex, # <2> reader: asyncio.StreamReader, - writer: asyncio.StreamWriter): + writer: asyncio.StreamWriter) -> None: client = writer.get_extra_info('peername') # <3> while True: # <4> writer.write(PROMPT) # can't await! # <5> await writer.drain() # must await! # <6> data = await reader.readline() # <7> + if not data: # <8> + break try: - query = data.decode().strip() # <8> - except UnicodeDecodeError: # <9> + query = data.decode().strip() # <9> + except UnicodeDecodeError: # <10> query = '\x00' - print(f' From {client}: {query!r}') # <10> + print(f' From {client}: {query!r}') # <11> if query: - if ord(query[:1]) < 32: # <11> + if ord(query[:1]) < 32: # <12> break - results = await search(query, index, writer) # <12> - print(f' To {client}: {results} results.') # <13> + results = await search(query, index, writer) # <13> + print(f' To {client}: {results} results.') # <14> - writer.close() # <14> - await writer.wait_closed() # <15> - print(f'Close {client}.') # <16> + writer.close() # <15> + await writer.wait_closed() # <16> + print(f'Close {client}.') # <17> # end::TCP_MOJIFINDER_TOP[] # tag::TCP_MOJIFINDER_SEARCH[] @@ -52,7 +54,7 @@ async def search(query: str, # <1> # end::TCP_MOJIFINDER_SEARCH[] # tag::TCP_MOJIFINDER_MAIN[] -async def supervisor(index: InvertedIndex, host: str, port: int): +async def supervisor(index: InvertedIndex, host: str, port: int) -> None: server = await asyncio.start_server( # <1> functools.partial(finder, index), # <2> host, port) # <3> diff --git a/21-async/mojifinder/web_mojifinder.py b/21-async/mojifinder/web_mojifinder.py index 7e0ff96..5f0cf5c 100644 --- a/21-async/mojifinder/web_mojifinder.py +++ b/21-async/mojifinder/web_mojifinder.py @@ -7,25 +7,26 @@ from charindex import InvertedIndex -app = FastAPI( # <1> +STATIC_PATH = Path(__file__).parent.absolute() / 'static' # <1> + +app = FastAPI( # <2> title='Mojifinder Web', description='Search for Unicode characters by name.', ) -class CharName(BaseModel): # <2> +class CharName(BaseModel): # <3> char: str name: str -def init(app): # <3> +def init(app): # <4> app.state.index = InvertedIndex() - static = Path(__file__).parent.absolute() / 'static' # <4> - app.state.form = (static / 'form.html').read_text() + app.state.form = (STATIC_PATH / 'form.html').read_text() init(app) # <5> @app.get('/search', response_model=list[CharName]) # <6> async def search(q: str): # <7> - chars = app.state.index.search(q) + chars = sorted(app.state.index.search(q)) return ({'char': c, 'name': name(c)} for c in chars) # <8> @app.get('/', response_class=HTMLResponse, include_in_schema=False) diff --git a/22-dyn-attr-prop/bulkfood/bulkfood_v2prop.py b/22-dyn-attr-prop/bulkfood/bulkfood_v2prop.py index e34a7c3..b2cffab 100644 --- a/22-dyn-attr-prop/bulkfood/bulkfood_v2prop.py +++ b/22-dyn-attr-prop/bulkfood/bulkfood_v2prop.py @@ -30,8 +30,8 @@ >>> nutmeg = LineItem('Moluccan nutmeg', 8, 13.95) >>> nutmeg.weight, nutmeg.price # <1> (8, 13.95) - >>> sorted(vars(nutmeg).items()) # <2> - [('description', 'Moluccan nutmeg'), ('price', 13.95), ('weight', 8)] + >>> nutmeg.__dict__ # <2> + {'description': 'Moluccan nutmeg', 'weight': 8, 'price': 13.95} # end::LINEITEM_V2_PROP_DEMO[] diff --git a/22-dyn-attr-prop/oscon/explore0.py b/22-dyn-attr-prop/oscon/explore0.py index 1ea7843..c881d16 100644 --- a/22-dyn-attr-prop/oscon/explore0.py +++ b/22-dyn-attr-prop/oscon/explore0.py @@ -54,12 +54,15 @@ def __getattr__(self, name): # <2> except AttributeError: return FrozenJSON.build(self.__data[name]) # <4> + def __dir__(self): # <5> + return self.__data.keys() + @classmethod - def build(cls, obj): # <5> - if isinstance(obj, abc.Mapping): # <6> + def build(cls, obj): # <6> + if isinstance(obj, abc.Mapping): # <7> return cls(obj) - elif isinstance(obj, abc.MutableSequence): # <7> + elif isinstance(obj, abc.MutableSequence): # <8> return [cls.build(item) for item in obj] - else: # <8> + else: # <9> return obj # end::EXPLORE0[] diff --git a/22-dyn-attr-prop/oscon/explore1.py b/22-dyn-attr-prop/oscon/explore1.py index ecb53b0..6942079 100644 --- a/22-dyn-attr-prop/oscon/explore1.py +++ b/22-dyn-attr-prop/oscon/explore1.py @@ -62,11 +62,14 @@ def __init__(self, mapping): # end::EXPLORE1[] def __getattr__(self, name): - if hasattr(self.__data, name): + try: return getattr(self.__data, name) - else: + except AttributeError: return FrozenJSON.build(self.__data[name]) + def __dir__(self): # <5> + return self.__data.keys() + @classmethod def build(cls, obj): if isinstance(obj, abc.Mapping): diff --git a/22-dyn-attr-prop/oscon/explore2.py b/22-dyn-attr-prop/oscon/explore2.py index 8cb9348..b50d49f 100644 --- a/22-dyn-attr-prop/oscon/explore2.py +++ b/22-dyn-attr-prop/oscon/explore2.py @@ -47,8 +47,11 @@ def __init__(self, mapping): self.__data[key] = value def __getattr__(self, name): - if hasattr(self.__data, name): + try: return getattr(self.__data, name) - else: + except AttributeError: return FrozenJSON(self.__data[name]) # <4> + + def __dir__(self): + return self.__data.keys() # end::EXPLORE2[] diff --git a/22-dyn-attr-prop/oscon/schedule_v1.py b/22-dyn-attr-prop/oscon/schedule_v1.py index 1be6c41..12aab71 100644 --- a/22-dyn-attr-prop/oscon/schedule_v1.py +++ b/22-dyn-attr-prop/oscon/schedule_v1.py @@ -23,8 +23,7 @@ def __init__(self, **kwargs): self.__dict__.update(kwargs) # <1> def __repr__(self): - cls_name = self.__class__.__name__ - return f'<{cls_name} serial={self.serial!r}>' # <2> + return f'<{self.__class__.__name__} serial={self.serial!r}>' # <2> def load(path=JSON_PATH): records = {} # <3> diff --git a/22-dyn-attr-prop/oscon/schedule_v2.py b/22-dyn-attr-prop/oscon/schedule_v2.py index 35827eb..5f264f7 100644 --- a/22-dyn-attr-prop/oscon/schedule_v2.py +++ b/22-dyn-attr-prop/oscon/schedule_v2.py @@ -29,8 +29,7 @@ def __init__(self, **kwargs): self.__dict__.update(kwargs) def __repr__(self): - cls_name = self.__class__.__name__ - return f'<{cls_name} serial={self.serial!r}>' + return f'<{self.__class__.__name__} serial={self.serial!r}>' @staticmethod # <3> def fetch(key): @@ -44,10 +43,9 @@ def fetch(key): class Event(Record): # <1> def __repr__(self): - if hasattr(self, 'name'): # <2> - cls_name = self.__class__.__name__ - return f'<{cls_name} {self.name!r}>' - else: + try: + return f'<{self.__class__.__name__} {self.name!r}>' # <2> + except AttributeError: return super().__repr__() @property diff --git a/22-dyn-attr-prop/oscon/schedule_v3.py b/22-dyn-attr-prop/oscon/schedule_v3.py index 786a412..7683b2d 100644 --- a/22-dyn-attr-prop/oscon/schedule_v3.py +++ b/22-dyn-attr-prop/oscon/schedule_v3.py @@ -33,8 +33,7 @@ def __init__(self, **kwargs): self.__dict__.update(kwargs) def __repr__(self): - cls_name = self.__class__.__name__ - return f'<{cls_name} serial={self.serial!r}>' + return f'<{self.__class__.__name__} serial={self.serial!r}>' @staticmethod def fetch(key): @@ -46,11 +45,10 @@ def fetch(key): class Event(Record): def __repr__(self): - if hasattr(self, 'name'): # <3> - cls_name = self.__class__.__name__ - return f'<{cls_name} {self.name!r}>' - else: - return super().__repr__() # <4> + try: + return f'<{self.__class__.__name__} {self.name!r}>' + except AttributeError: + return super().__repr__() @property def venue(self): diff --git a/22-dyn-attr-prop/oscon/schedule_v4.py b/22-dyn-attr-prop/oscon/schedule_v4.py index a609917..5b968e1 100644 --- a/22-dyn-attr-prop/oscon/schedule_v4.py +++ b/22-dyn-attr-prop/oscon/schedule_v4.py @@ -32,8 +32,7 @@ def __init__(self, **kwargs): self.__dict__.update(kwargs) def __repr__(self): - cls_name = self.__class__.__name__ - return f'<{cls_name} serial={self.serial!r}>' + return f'<{self.__class__.__name__} serial={self.serial!r}>' @staticmethod def fetch(key): @@ -52,11 +51,10 @@ def __init__(self, **kwargs): # end::SCHEDULE4_INIT[] def __repr__(self): - if hasattr(self, 'name'): - cls_name = self.__class__.__name__ - return f'<{cls_name} {self.name!r}>' - else: - return super().__repr__() # <4> + try: + return f'<{self.__class__.__name__} {self.name!r}>' + except AttributeError: + return super().__repr__() @property def venue(self): diff --git a/22-dyn-attr-prop/oscon/schedule_v4_hasattr.py b/22-dyn-attr-prop/oscon/schedule_v4_hasattr.py index ac5d5de..abc72bf 100644 --- a/22-dyn-attr-prop/oscon/schedule_v4_hasattr.py +++ b/22-dyn-attr-prop/oscon/schedule_v4_hasattr.py @@ -31,8 +31,7 @@ def __init__(self, **kwargs): self.__dict__.update(kwargs) def __repr__(self): - cls_name = self.__class__.__name__ - return f'<{cls_name} serial={self.serial!r}>' + return f'<{self.__class__.__name__} serial={self.serial!r}>' @staticmethod def fetch(key): @@ -44,11 +43,10 @@ def fetch(key): class Event(Record): def __repr__(self): - if hasattr(self, 'name'): - cls_name = self.__class__.__name__ - return f'<{cls_name} {self.name!r}>' - else: - return super().__repr__() # <4> + try: + return f'<{self.__class__.__name__} {self.name!r}>' + except AttributeError: + return super().__repr__() @property def venue(self): diff --git a/22-dyn-attr-prop/oscon/schedule_v5.py b/22-dyn-attr-prop/oscon/schedule_v5.py index 2517e57..7a9543b 100644 --- a/22-dyn-attr-prop/oscon/schedule_v5.py +++ b/22-dyn-attr-prop/oscon/schedule_v5.py @@ -36,8 +36,7 @@ def __init__(self, **kwargs): self.__dict__.update(kwargs) def __repr__(self): - cls_name = self.__class__.__name__ - return f'<{cls_name} serial={self.serial!r}>' + return f'<{self.__class__.__name__} serial={self.serial!r}>' @staticmethod def fetch(key): @@ -49,10 +48,9 @@ def fetch(key): class Event(Record): def __repr__(self): - if hasattr(self, 'name'): - cls_name = self.__class__.__name__ - return f'<{cls_name} {self.name!r}>' - else: + try: + return f'<{self.__class__.__name__} {self.name!r}>' + except AttributeError: return super().__repr__() # tag::SCHEDULE5_CACHED_PROPERTY[] diff --git a/23-descriptor/bulkfood/model_v5.py b/23-descriptor/bulkfood/model_v5.py index 018afcd..4c35698 100644 --- a/23-descriptor/bulkfood/model_v5.py +++ b/23-descriptor/bulkfood/model_v5.py @@ -30,7 +30,7 @@ class NonBlank(Validated): def validate(self, name, value): value = value.strip() - if len(value) == 0: + if not value: # <2> raise ValueError(f'{name} cannot be blank') - return value # <2> + return value # <3> # end::MODEL_V5_VALIDATED_SUB[] diff --git a/23-descriptor/descriptorkinds.py b/23-descriptor/descriptorkinds.py index 44f4018..13df709 100644 --- a/23-descriptor/descriptorkinds.py +++ b/23-descriptor/descriptorkinds.py @@ -5,21 +5,18 @@ >>> obj = Managed() # <1> >>> obj.over # <2> - -> Overriding.__get__(, , - ) + -> Overriding.__get__(, , ) >>> Managed.over # <3> -> Overriding.__get__(, None, ) >>> obj.over = 7 # <4> -> Overriding.__set__(, , 7) >>> obj.over # <5> - -> Overriding.__get__(, , - ) + -> Overriding.__get__(, , ) >>> obj.__dict__['over'] = 8 # <6> >>> vars(obj) # <7> {'over': 8} >>> obj.over # <8> - -> Overriding.__get__(, , - ) + -> Overriding.__get__(, , ) # end::DESCR_KINDS_DEMO1[] @@ -50,8 +47,7 @@ >>> obj = Managed() >>> obj.non_over # <1> - -> NonOverriding.__get__(, , - ) + -> NonOverriding.__get__(, , ) >>> obj.non_over = 7 # <2> >>> obj.non_over # <3> 7 @@ -59,8 +55,7 @@ -> NonOverriding.__get__(, None, ) >>> del obj.non_over # <5> >>> obj.non_over # <6> - -> NonOverriding.__get__(, , - ) + -> NonOverriding.__get__(, , ) # end::DESCR_KINDS_DEMO3[] @@ -88,7 +83,7 @@ >>> Managed.spam() Traceback (most recent call last): ... - TypeError: spam() missing 1 required positional argument: 'self' + TypeError: Managed.spam() missing 1 required positional argument: 'self' >>> Managed.spam(obj) -> Managed.spam() >>> Managed.spam.__get__(obj) # doctest: +ELLIPSIS @@ -156,15 +151,15 @@ def cls_name(obj_or_cls): def display(obj): cls = type(obj) if cls is type: - return ''.format(obj.__name__) + return f'' elif cls in [type(None), int]: return repr(obj) else: - return '<{} object>'.format(cls_name(obj)) + return f'<{cls_name(obj)} object>' def print_args(name, *args): pseudo_args = ', '.join(display(x) for x in args) - print('-> {}.__{}__({})'.format(cls_name(args[0]), name, pseudo_args)) + print(f'-> {cls_name(args[0])}.__{name}__({pseudo_args})') ### essential classes for this example ### @@ -199,6 +194,6 @@ class Managed: # <5> non_over = NonOverriding() def spam(self): # <6> - print('-> Managed.spam({})'.format(display(self))) + print(f'-> Managed.spam({display(self)})') # end::DESCR_KINDS[] diff --git a/24-class-metaprog/checked/metaclass/checkedlib.py b/24-class-metaprog/checked/metaclass/checkedlib.py index 8207dbe..768a0f6 100644 --- a/24-class-metaprog/checked/metaclass/checkedlib.py +++ b/24-class-metaprog/checked/metaclass/checkedlib.py @@ -78,7 +78,9 @@ def __init__(self, name: str, constructor: Callable) -> None: self.storage_name = '_' + name # <1> self.constructor = constructor - def __get__(self, instance, owner=None): # <2> + def __get__(self, instance, owner=None): + if instance is None: # <2> + return self return getattr(instance, self.storage_name) # <3> def __set__(self, instance: Any, value: Any) -> None: diff --git a/24-class-metaprog/factories.py b/24-class-metaprog/factories.py index 38ec763..cf61d89 100644 --- a/24-class-metaprog/factories.py +++ b/24-class-metaprog/factories.py @@ -49,9 +49,8 @@ def __iter__(self) -> Iterator[Any]: # <5> yield getattr(self, name) def __repr__(self): # <6> - values = ', '.join( - '{}={!r}'.format(*i) for i in zip(self.__slots__, self) - ) + values = ', '.join(f'{name}={value!r}' + for name, value in zip(self.__slots__, self)) cls_name = self.__class__.__name__ return f'{cls_name}({values})' diff --git a/24-class-metaprog/metabunch/from3.6/bunch.py b/24-class-metaprog/metabunch/from3.6/bunch.py index a8b3d5a..aa0a65e 100644 --- a/24-class-metaprog/metabunch/from3.6/bunch.py +++ b/24-class-metaprog/metabunch/from3.6/bunch.py @@ -28,7 +28,7 @@ >>> Point(x=1, y=2, z=3) Traceback (most recent call last): ... - AttributeError: 'Point' object has no attribute 'z' + AttributeError: No slots left for: 'z' >>> p = Point(x=21) >>> p.y = 42 >>> p @@ -51,7 +51,8 @@ def __init__(self, **kwargs): # <4> for name, default in defaults.items(): # <5> setattr(self, name, kwargs.pop(name, default)) if kwargs: # <6> - setattr(self, *kwargs.popitem()) + extra = ', '.join(kwargs) + raise AttributeError(f'No slots left for: {extra!r}') def __repr__(self): # <7> rep = ', '.join(f'{name}={value!r}' diff --git a/24-class-metaprog/metabunch/from3.6/bunch_test.py b/24-class-metaprog/metabunch/from3.6/bunch_test.py index 322487a..166e600 100644 --- a/24-class-metaprog/metabunch/from3.6/bunch_test.py +++ b/24-class-metaprog/metabunch/from3.6/bunch_test.py @@ -26,7 +26,7 @@ def test_init(): def test_init_wrong_argument(): with pytest.raises(AttributeError) as exc: p = Point(x=1.2, y=3.4, flavor='coffee') - assert "no attribute 'flavor'" in str(exc.value) + assert 'flavor' in str(exc.value) def test_slots(): diff --git a/24-class-metaprog/timeslice.py b/24-class-metaprog/timeslice.py new file mode 100644 index 0000000..5a52457 --- /dev/null +++ b/24-class-metaprog/timeslice.py @@ -0,0 +1,91 @@ + +""" +Could this be valid Python? + + if now >= T[4:20:PM]: chill() + + +>>> t = T[4:20] +>>> t +T[4:20] +>>> h, m, s = t +>>> h, m, s +(4, 20, 0) +>>> t[11:59:AM] +T[11:59:AM] +>>> start = t[9:O1:PM] +>>> start +T[9:O1:PM] +>>> start.h, start.m, start.s, start.pm +(9, 1, 0, True) +>>> now = T[7:O1:PM] +>>> T[4:OO:PM] +T[4:OO:PM] +>>> now > T[4:20:PM] +True +""" + +import functools + +AM = -2 +PM = -1 + +for n in range(10): + globals()[f'O{n}'] = n +OO = 0 + +@functools.total_ordering +class T(): + + def __init__(self, arg): + if isinstance(arg, slice): + h = arg.start or 0 + m = arg.stop or 0 + s = arg.step or 0 + else: + h, m, s = 0, 0, arg + if m in (AM, PM): + self.pm = m == PM + m = 0 + elif s in (AM, PM): + self.pm = s == PM + s = 0 + else: + self.pm = None + self.h, self.m, self.s = h, m, s + + def __class_getitem__(cls, arg): + return cls(arg) + + def __getitem__(self, arg): + return(type(self)(arg)) + + def __repr__(self): + h, m, s = self.h, self.m, self.s or None + if m == 0: + m = f'OO' + elif m < 10: + m = f'O{m}' + s = '' if s is None else s + if self.pm is None: + pm = '' + else: + pm = ':' + ('AM', 'PM')[self.pm] + return f'T[{h}:{m}{s}{pm}]' + + def __iter__(self): + yield from (self.h, self.m, self.s) + + def __eq__(self, other): + return tuple(self) == tuple(other) + + def __lt__(self, other): + return tuple(self) < tuple(other) + + def __add__(self, other): + """ + >>> T[11:O5:AM] + 15 # TODO: preserve pm field + T[11:20] + """ + if isinstance(other, int): + return self[self.h:self.m + other:self.pm] From 6709e755ee4b7edc6fc3b183c72d76a8cb7a83d5 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Sat, 15 Jan 2022 13:24:21 -0300 Subject: [PATCH 33/66] added links and README.md --- links/FPY.LI.htaccess | 982 ++++++++++++++++++++++++++++++++++++++++++ links/README.md | 37 ++ links/custom.htaccess | 109 +++++ 3 files changed, 1128 insertions(+) create mode 100644 links/FPY.LI.htaccess create mode 100644 links/README.md create mode 100644 links/custom.htaccess diff --git a/links/FPY.LI.htaccess b/links/FPY.LI.htaccess new file mode 100644 index 0000000..579d7e4 --- /dev/null +++ b/links/FPY.LI.htaccess @@ -0,0 +1,982 @@ +ErrorDocument 404 /404.html + +# main resources +RedirectTemp /code https://github.com/fluentpython/example-code-2e +RedirectTemp /home https://www.fluentpython.com/ + +# URLs mentioned at least three times +RedirectTemp /bisect https://www.fluentpython.com/extra/ordered-sequences-with-bisect/ +RedirectTemp /cardxvi https://www.python.org/dev/peps/pep-0484/#the-numeric-tower +RedirectTemp /collec https://docs.python.org/3/library/collections.html +RedirectTemp /dask https://dask.org/ +RedirectTemp /dtmodel https://docs.python.org/3/reference/datamodel.html +RedirectTemp /descr101 https://www.python.org/download/releases/2.2.3/descrintro/ +RedirectTemp /descrhow https://docs.python.org/3/howto/descriptor.html +RedirectTemp /doctest https://docs.python.org/3/library/doctest.html +RedirectTemp /effectpy https://effectivepython.com/ +RedirectTemp /fmtspec https://docs.python.org/3/library/string.html#formatspec +RedirectTemp /gunicorn https://gunicorn.org/ +RedirectTemp /hashint https://www.fluentpython.com/extra/internals-of-sets-and-dicts/ +RedirectTemp /hattingh https://www.oreilly.com/library/view/using-asyncio-in/9781492075325/ +RedirectTemp /httpx https://www.python-httpx.org/ +RedirectTemp /initvar https://docs.python.org/3/library/dataclasses.html#init-only-variables +RedirectTemp /mypy https://mypy.readthedocs.io/en/stable/ +RedirectTemp /norvigdp http://norvig.com/design-patterns/ +RedirectTemp /nsphere https://en.wikipedia.org/wiki/N-sphere +RedirectTemp /oldcoro https://www.fluentpython.com/extra/classic-coroutines/ +RedirectTemp /pandas https://pandas.pydata.org/ +RedirectTemp /pep218 https://www.python.org/dev/peps/pep-0218/ +RedirectTemp /pep227 https://www.python.org/dev/peps/pep-0227/ +RedirectTemp /pep255 https://www.python.org/dev/peps/pep-0255/ +RedirectTemp /pep342 https://www.python.org/dev/peps/pep-0342/ +RedirectTemp /pep343 https://www.python.org/dev/peps/pep-0343/ +RedirectTemp /pep357 https://www.python.org/dev/peps/pep-0357/ +RedirectTemp /pep362 https://www.python.org/dev/peps/pep-0362/ +RedirectTemp /pep371 https://www.python.org/dev/peps/pep-0371/ +RedirectTemp /pep380 https://www.python.org/dev/peps/pep-0380/ +RedirectTemp /pep393 https://www.python.org/dev/peps/pep-0393/ +RedirectTemp /pep412 https://www.python.org/dev/peps/pep-0412/ +RedirectTemp /pep442 https://www.python.org/dev/peps/pep-0442/ +RedirectTemp /pep443 https://www.python.org/dev/peps/pep-0443/ +RedirectTemp /pep448 https://www.python.org/dev/peps/pep-0448/ +RedirectTemp /pep455 https://www.python.org/dev/peps/pep-0455/ +RedirectTemp /pep456 https://www.python.org/dev/peps/pep-0456/ +RedirectTemp /pep461 https://www.python.org/dev/peps/pep-0461/ +RedirectTemp /pep465 https://www.python.org/dev/peps/pep-0465/ +RedirectTemp /pep467 https://www.python.org/dev/peps/pep-0467/ +RedirectTemp /pep482 https://www.python.org/dev/peps/pep-0482/ +RedirectTemp /pep483 https://www.python.org/dev/peps/pep-0483/ +RedirectTemp /pep484 https://www.python.org/dev/peps/pep-0484/ +RedirectTemp /pep487 https://www.python.org/dev/peps/pep-0487/ +RedirectTemp /pep492 https://www.python.org/dev/peps/pep-0492/ +RedirectTemp /pep519 https://www.python.org/dev/peps/pep-0519/ +RedirectTemp /pep525 https://www.python.org/dev/peps/pep-0525/ +RedirectTemp /pep526 https://www.python.org/dev/peps/pep-0526/ +RedirectTemp /pep528 https://www.python.org/dev/peps/pep-0528/ +RedirectTemp /pep529 https://www.python.org/dev/peps/pep-0529/ +RedirectTemp /pep530 https://www.python.org/dev/peps/pep-0530/ +RedirectTemp /pep544 https://www.python.org/dev/peps/pep-0544/ +RedirectTemp /pep554 https://www.python.org/dev/peps/pep-0554/ +RedirectTemp /pep557 https://www.python.org/dev/peps/pep-0557/ +RedirectTemp /pep560 https://www.python.org/dev/peps/pep-0560/ +RedirectTemp /pep561 https://www.python.org/dev/peps/pep-0561/ +RedirectTemp /pep563 https://www.python.org/dev/peps/pep-0563/ +RedirectTemp /pep570 https://www.python.org/dev/peps/pep-0570/ +RedirectTemp /pep572 https://www.python.org/dev/peps/pep-0572/ +RedirectTemp /pep584 https://www.python.org/dev/peps/pep-0584/ +RedirectTemp /pep585 https://www.python.org/dev/peps/pep-0585/ +RedirectTemp /pep586 https://www.python.org/dev/peps/pep-0586/ +RedirectTemp /pep589 https://www.python.org/dev/peps/pep-0589/ +RedirectTemp /pep591 https://www.python.org/dev/peps/pep-0591/ +RedirectTemp /pep593 https://www.python.org/dev/peps/pep-0593/ +RedirectTemp /pep604 https://www.python.org/dev/peps/pep-0604/ +RedirectTemp /pep612 https://www.python.org/dev/peps/pep-0612/ +RedirectTemp /pep613 https://www.python.org/dev/peps/pep-0613/ +RedirectTemp /pep616 https://www.python.org/dev/peps/pep-0616/ +RedirectTemp /pep617 https://www.python.org/dev/peps/pep-0617/ +RedirectTemp /pep618 https://www.python.org/dev/peps/pep-0618/ +RedirectTemp /pep634 https://www.python.org/dev/peps/pep-0634/ +RedirectTemp /pep635 https://www.python.org/dev/peps/pep-0635/ +RedirectTemp /pep636 https://www.python.org/dev/peps/pep-0636/ +RedirectTemp /pep638 https://www.python.org/dev/peps/pep-0638/ +RedirectTemp /pep645 https://www.python.org/dev/peps/pep-0645/ +RedirectTemp /pep646 https://www.python.org/dev/peps/pep-0646/ +RedirectTemp /pep647 https://www.python.org/dev/peps/pep-0647/ +RedirectTemp /pep649 https://www.python.org/dev/peps/pep-0649/ +RedirectTemp /pep654 https://www.python.org/dev/peps/pep-0654/ +RedirectTemp /pep655 https://www.python.org/dev/peps/pep-0655/ +RedirectTemp /pep661 https://www.python.org/dev/peps/pep-0661/ +RedirectTemp /pep3099 https://www.python.org/dev/peps/pep-3099/ +RedirectTemp /pep3102 https://www.python.org/dev/peps/pep-3102/ +RedirectTemp /pep3104 https://www.python.org/dev/peps/pep-3104/ +RedirectTemp /pep3106 https://www.python.org/dev/peps/pep-3106/ +RedirectTemp /pep3107 https://www.python.org/dev/peps/pep-3107/ +RedirectTemp /pep3115 https://www.python.org/dev/peps/pep-3115/ +RedirectTemp /pep3118 https://www.python.org/dev/peps/pep-3118/ +RedirectTemp /pep3119 https://www.python.org/dev/peps/pep-3119/ +RedirectTemp /pep3129 https://www.python.org/dev/peps/pep-3129/ +RedirectTemp /pep3132 https://www.python.org/dev/peps/pep-3132/ +RedirectTemp /pep3141 https://www.python.org/dev/peps/pep-3141/ +RedirectTemp /pep3148 https://www.python.org/dev/peps/pep-3148/ +RedirectTemp /pep3155 https://www.python.org/dev/peps/pep-3155/ +RedirectTemp /pep3333 https://www.python.org/dev/peps/pep-3333/ +RedirectTemp /pypydif https://doc.pypy.org/en/latest/cpython_differences.html#subclasses-of-built-in-types +RedirectTemp /shed4051 https://github.com/python/typeshed/issues/4051 +RedirectTemp /slatkin https://effectivepython.com/ +RedirectTemp /specattr https://docs.python.org/3/library/stdtypes.html#special-attributes +RedirectTemp /typecoro https://docs.python.org/3.10/library/typing.html#typing.Coroutine +RedirectTemp /typing https://docs.python.org/3/library/typing.html +RedirectTemp /weakref https://www.fluentpython.com/extra/weak-references/ + +# Remaining URLs by chapter + +############################################################ p +RedirectTemp /p-1 https://mail.python.org/pipermail/python-list/2002-December/134521.html +RedirectTemp /p-2 https://docs.python.org/3.10/tutorial/ +RedirectTemp /p-3 https://docs.python.org/3/tutorial/ +RedirectTemp /p-9 https://www.oreilly.com/library/view/fluent-python-2nd/9781492056348/ +RedirectTemp /p-10 https://www.oreilly.com/online-learning/try-now.html +RedirectTemp /p-13 https://www.oreilly.com/library/view/fluent-python-2nd/9781492056348/ +RedirectTemp /p-14 https://www.oreilly.com/ +RedirectTemp /p-15 https://www.facebook.com/OReilly/ +RedirectTemp /p-16 https://twitter.com/oreillymedia +RedirectTemp /p-17 https://www.youtube.com/oreillymedia +RedirectTemp /p-18 https://stackoverflow.com/users/95810/alex-martelli +RedirectTemp /p-19 https://pythonpro.com.br +RedirectTemp /p-20 https://groups.google.com/g/python-brasil +RedirectTemp /p-21 https://www.coffeelab.com.br/ +RedirectTemp /p-22 https://garoa.net.br/wiki/P%C3%A1gina_principal +############################################################ a +RedirectTemp /a-1 https://groups.google.com/forum/#!topic/python-tulip/Y4bhLNbKs74 +RedirectTemp /a-2 https://docs.python.org/3/library/asyncio-eventloop.html#executor +RedirectTemp /a-3 https://www.youtube.com/watch?v=x-kB2o8sd5c +RedirectTemp /a-4 https://www.youtube.com/watch?v=OSGv2VnC0go +RedirectTemp /a-5 https://mail.python.org/pipermail/python-ideas/2015-March/032557.html +RedirectTemp /a-6 https://pypi.org/project/pep8/ +RedirectTemp /a-7 https://pypi.org/project/flake8/ +RedirectTemp /a-8 https://pypi.org/project/pyflakes/ +RedirectTemp /a-9 https://pypi.org/project/mccabe/ +RedirectTemp /a-10 https://google.github.io/styleguide/pyguide.html +RedirectTemp /a-11 https://flask.palletsprojects.com/en/1.1.x/styleguide/ +RedirectTemp /a-12 https://docs.python-guide.org/ +RedirectTemp /a-13 https://david.goodger.org/projects/pycon/2007/idiomatic/handout.html +RedirectTemp /a-14 https://docs.mongodb.com/manual/about/#about-the-documentation-process +RedirectTemp /a-15 https://blog.startifact.com/posts/older/what-is-pythonic.html +RedirectTemp /a-16 https://mail.python.org/pipermail/tutor/2003-October/thread.html#25930 +RedirectTemp /a-17 https://mail.python.org/pipermail/python-list/2003-April/192027.html +RedirectTemp /a-19 https://www.python.org/doc/essays/ +############################################################ 01 +RedirectTemp /1-1 http://hugunin.net/story_of_jython.html +RedirectTemp /1-3 https://docs.python.org/2/library/string.html#format-string-syntax +RedirectTemp /1-4 https://stackoverflow.com/questions/1436703/what-is-the-difference-between-str-and-repr +RedirectTemp /1-5 https://docs.python.org/3/library/stdtypes.html#truth +RedirectTemp /1-6 https://docs.python.org/3/tutorial/controlflow.html#unpacking-argument-lists +RedirectTemp /1-8 https://www.python.org/doc/humor/#the-zen-of-python +RedirectTemp /1-10 https://stackoverflow.com/users/95810/alex-martelli +RedirectTemp /1-11 https://en.wikipedia.org/wiki/Object_model +RedirectTemp /1-13 https://www.dourish.com/goodies/jargon.html +RedirectTemp /1-14 https://zopeinterface.readthedocs.io/en/latest/ +RedirectTemp /1-15 https://plone.org/ +############################################################ 02 +RedirectTemp /2-4 https://github.com/fluentpython/example-code-2e/blob/master/02-array-seq/listcomp_speed.py +RedirectTemp /2-6 https://www.python.org/dev/peps/pep-3132/ +RedirectTemp /2-8 https://docs.python.org/3/whatsnew/3.5.html#pep-448-additional-unpacking-generalizations +RedirectTemp /2-9 https://docs.python.org/3/whatsnew/3.5.html#pep-448-additional-unpacking-generalizations +RedirectTemp /2-11 https://docs.python.org/3.10/whatsnew/3.10.html#pep-634-structural-pattern-matching +RedirectTemp /2-12 https://docs.python.org/3.10/whatsnew/3.10.html +RedirectTemp /2-13 https://en.wikipedia.org/wiki/Switch_statement#Fallthrough +RedirectTemp /2-14 https://en.wikipedia.org/wiki/Dangling_else +RedirectTemp /2-15 https://github.com/gvanrossum/patma/blob/3ece6444ef70122876fd9f0099eb9490a2d630df/EXAMPLES.md#case-6-a-very-deep-iterable-and-type-match-with-extraction +RedirectTemp /2-16 https://github.com/fluentpython/lispy/blob/main/original/norvig/lis.py +RedirectTemp /2-17 https://norvig.com/lispy.html +RedirectTemp /2-18 https://numpy.org/doc/stable/user/quickstart.html#indexing-slicing-and-iterating +RedirectTemp /2-19 https://pythontutor.com/ +RedirectTemp /2-20 https://en.wikipedia.org/wiki/Fluent_interface +RedirectTemp /2-23 https://docs.python.org/3/library/bisect.html#bisect.insort +RedirectTemp /2-24 https://stackoverflow.com/questions/4845418/when-should-a-memoryview-be-used/ +RedirectTemp /2-26 https://www.fluentpython.com/extra/parsing-binary-struct/ +RedirectTemp /2-27 http://www.netlib.org +RedirectTemp /2-28 https://pandas.pydata.org/ +RedirectTemp /2-29 https://scikit-learn.org/stable/ +RedirectTemp /2-32 https://docs.python.org/3/howto/sorting.html +RedirectTemp /2-33 https://www.python.org/dev/peps/pep-3132/ +RedirectTemp /2-34 https://bugs.python.org/issue2292 +RedirectTemp /2-36 https://docs.python.org/3.10/whatsnew/3.10.html#pep-634-structural-pattern-matching +RedirectTemp /2-37 https://docs.python.org/3.10/whatsnew/3.10.html +RedirectTemp /2-39 https://www.python.org/dev/peps/pep-0636/#appendix-a-quick-intro +RedirectTemp /2-41 https://eli.thegreenplace.net/2011/11/28/less-copies-in-python-with-the-buffer-protocol-and-memoryviews/ +RedirectTemp /2-42 https://jakevdp.github.io/PythonDataScienceHandbook/ +RedirectTemp /2-43 https://www.labri.fr/perso/nrougier/from-python-to-numpy/ +RedirectTemp /2-44 https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html +RedirectTemp /2-45 http://www.fonts101.com/fonts/view/Uncategorized/34398/Dijkstra +RedirectTemp /2-46 https://docs.python.org/3/reference/datamodel.html#objects-values-and-types +RedirectTemp /2-47 https://en.wikipedia.org/wiki/Timsort +RedirectTemp /2-48 http://www.groklaw.net/pdf3/OraGoogle-1202.pdf +RedirectTemp /2-49 https://www.python.org/doc/humor/#id9 +############################################################ 03 +RedirectTemp /3-5 https://www.python.org/dev/peps/pep-0584/#motivation +RedirectTemp /3-7 https://docs.python.org/3.10/c-api/typeobj.html#Py_TPFLAGS_MAPPING +RedirectTemp /3-8 https://docs.python.org/3/glossary.html#term-hashable +RedirectTemp /3-9 https://docs.python.org/3/glossary.html#term-hashable +RedirectTemp /3-11 http://www.aleax.it/Python/accu04_Relearn_Python_alex.pdf +RedirectTemp /3-12 https://github.com/pingo-io/pingo-py +RedirectTemp /3-13 https://github.com/fluentpython/example-code-2e/blob/master/03-dict-set/missing.py +RedirectTemp /3-14 https://docs.python.org/3/library/collections.html#collections.ChainMap +RedirectTemp /3-15 https://docs.python.org/3/library/collections.html#collections.Counter +RedirectTemp /3-16 https://docs.python.org/3/library/shelve.html +RedirectTemp /3-17 https://docs.python.org/3/library/dbm.html +RedirectTemp /3-18 https://docs.python.org/3/library/pickle.html +RedirectTemp /3-19 https://nedbatchelder.com/blog/202006/pickles_nine_flaws.html +RedirectTemp /3-20 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Lib/_collections_abc.py#L813 +RedirectTemp /3-22 https://mail.python.org/pipermail/python-dev/2015-May/140003.html +RedirectTemp /3-23 https://bugs.python.org/issue18986 +RedirectTemp /3-24 https://github.com/fluentpython/example-code-2e/blob/master/03-dict-set/transformdict.py +RedirectTemp /3-33 http://gandenberger.org/2018/03/10/ordered-dicts-vs-ordereddict/ +RedirectTemp /3-35 https://www.pypy.org/ +RedirectTemp /3-36 https://morepypy.blogspot.com/2015/01/faster-more-memory-efficient-and-more.html +RedirectTemp /3-37 https://www.npopov.com/2014/12/22/PHPs-new-hashtable-implementation.html +RedirectTemp /3-38 https://www.youtube.com/watch?v=66P5FMkWoVU +RedirectTemp /3-39 https://pyvideo.org/video/276/the-mighty-dictionary-55/ +RedirectTemp /3-40 https://www.youtube.com/watch?v=p33CVV29OG8 +RedirectTemp /3-41 https://docs.python.org/3/whatsnew/3.6.html#new-dict-implementation +RedirectTemp /3-43 https://www.youtube.com/watch?v=tGAngdU_8D8 +RedirectTemp /3-44 https://speakerdeck.com/ramalho/python-set-practice-at-pycon +RedirectTemp /3-45 https://github.com/standupdev/uintset +RedirectTemp /3-46 http://www.json.org/fatfree.html +RedirectTemp /3-47 https://twitter.com/mitsuhiko/status/1229385843585974272 +############################################################ 04 +RedirectTemp /4-1 https://www.slideshare.net/fischertrav/character-encoding-unicode-how-to-with-dignity-33352863 +RedirectTemp /4-2 https://pyvideo.org/video/2625/character-encoding-and-unicode-in-python/ +RedirectTemp /4-3 https://www.fluentpython.com/extra/parsing-binary-struct/ +RedirectTemp /4-5 https://www.fluentpython.com/extra/multi-character-emojis/ +RedirectTemp /4-8 https://w3techs.com/technologies/overview/character_encoding +RedirectTemp /4-9 https://docs.python.org/3/library/codecs.html#codecs.register_error +RedirectTemp /4-10 https://docs.python.org/3/library/stdtypes.html#str.isascii +RedirectTemp /4-11 https://pypi.org/project/chardet/ +RedirectTemp /4-12 https://docs.python.org/3/library/codecs.html#encodings-and-unicode +RedirectTemp /4-13 https://nedbatchelder.com/text/unipain/unipain.html +RedirectTemp /4-16 https://docs.python.org/3/using/cmdline.html#envvar-PYTHONIOENCODING +RedirectTemp /4-17 https://docs.python.org/3/using/cmdline.html#envvar-PYTHONLEGACYWINDOWSSTDIO +RedirectTemp /4-18 https://docs.python.org/3/library/locale.html#locale.getpreferredencoding +RedirectTemp /4-19 http://www.w3.org/TR/charmod-norm/ +RedirectTemp /4-20 https://docs.python.org/3/library/locale.html?highlight=strxfrm#locale.strxfrm +RedirectTemp /4-21 https://github.com/jtauber/pyuca +RedirectTemp /4-22 http://www.unicode.org/Public/UCA/6.3.0/allkeys.txt +RedirectTemp /4-23 https://pypi.org/project/PyICU/ +RedirectTemp /4-24 https://docs.python.org/3.10/library/stdtypes.html#str.isalpha +RedirectTemp /4-25 https://en.wikipedia.org/wiki/Unicode_character_property#General_Category +RedirectTemp /4-26 https://en.wikipedia.org/wiki/Unicode_character_property +RedirectTemp /4-27 https://github.com/microsoft/terminal +RedirectTemp /4-28 https://docs.python.org/3/library/unicodedata.html +RedirectTemp /4-29 https://docs.python.org/3/reference/lexical_analysis.html#string-literal-concatenation +RedirectTemp /4-30 https://docs.python.org/3/library/re.html +RedirectTemp /4-31 https://nedbatchelder.com/text/unipain.html +RedirectTemp /4-32 https://www.slideshare.net/fischertrav/character-encoding-unicode-how-to-with-dignity-33352863 +RedirectTemp /4-33 https://pyvideo.org/video/2625/character-encoding-and-unicode-in-python/ +RedirectTemp /4-34 https://regebro.wordpress.com/2011/03/23/unconfusing-unicode-what-is-unicode/ +RedirectTemp /4-35 https://docs.python.org/3/howto/unicode.html +RedirectTemp /4-36 https://diveintopython3.net/strings.html +RedirectTemp /4-37 https://diveintopython3.net/ +RedirectTemp /4-38 https://finderiko.com/python-book +RedirectTemp /4-39 https://docs.python.org/3.0/whatsnew/3.0.html#text-vs-data-instead-of-unicode-vs-8-bit +RedirectTemp /4-40 https://lucumr.pocoo.org/2013/7/2/the-updated-guide-to-unicode/ +RedirectTemp /4-41 http://python-notes.curiousefficiency.org/en/latest/python3/binary_protocols.html +RedirectTemp /4-42 http://python-notes.curiousefficiency.org/en/latest/python3/text_file_processing.html +RedirectTemp /4-43 https://docs.python.org/3/library/codecs.html#standard-encodings +RedirectTemp /4-44 https://www.informit.com/store/unicode-demystified-a-practical-programmers-guide-to-9780201700527 +RedirectTemp /4-45 https://unicodebook.readthedocs.io/index.html +RedirectTemp /4-46 https://www.w3.org/International/wiki/Case_folding +RedirectTemp /4-47 http://www.w3.org/TR/charmod-norm/ +RedirectTemp /4-48 http://unicode.org/reports/tr15/ +RedirectTemp /4-49 http://www.unicode.org/faq/normalization.html +RedirectTemp /4-50 http://www.unicode.org/ +RedirectTemp /4-51 http://www.macchiato.com/unicode/nfc-faq +RedirectTemp /4-52 https://emojipedia.org/ +RedirectTemp /4-53 https://blog.emojipedia.org/correcting-the-record-on-the-first-emoji-set/ +RedirectTemp /4-54 http://emojitracker.com/ +RedirectTemp /4-55 http://www.unicode.org/glossary/#plain_text +RedirectTemp /4-56 http://www.methods.co.nz/asciidoc/ +RedirectTemp /4-57 https://atlas.oreilly.com/ +############################################################ 05 +RedirectTemp /5-1 https://docs.python.org/3/library/typing.html#typing.TypedDict +RedirectTemp /5-4 https://docs.python.org/3.10/library/inspect.html#inspect.get_annotations +RedirectTemp /5-5 https://docs.python.org/3/library/typing.html#typing.get_type_hints +RedirectTemp /5-6 https://docs.python.org/3.8/library/collections.html#collections.somenamedtuple._asdict +RedirectTemp /5-8 https://www.jetbrains.com/pycharm/ +RedirectTemp /5-10 https://www.python.org/dev/peps/pep-0484/#acceptable-type-hints +RedirectTemp /5-11 https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass +RedirectTemp /5-13 https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass +RedirectTemp /5-14 https://docs.python.org/3/library/dataclasses.html +RedirectTemp /5-15 https://docs.python.org/3/library/dataclasses.html#inheritance +RedirectTemp /5-16 https://www.python.org/dev/peps/pep-0526/#class-and-instance-variable-annotations +RedirectTemp /5-22 https://dublincore.org/specifications/dublin-core/ +RedirectTemp /5-23 https://en.wikipedia.org/wiki/Dublin_Core +RedirectTemp /5-24 https://martinfowler.com/bliki/CodeSmell.html +RedirectTemp /5-25 https://martinfowler.com/books/refactoring.html +RedirectTemp /5-26 https://www.python.org/dev/peps/pep-0634/#class-patterns +RedirectTemp /5-30 https://docs.python.org/3/library/dataclasses.html +RedirectTemp /5-32 https://www.python.org/dev/peps/pep-0557/#id47 +RedirectTemp /5-33 https://www.python.org/dev/peps/pep-0557/#id48 +RedirectTemp /5-34 https://www.python.org/dev/peps/pep-0557/#id33 +RedirectTemp /5-35 https://realpython.com +RedirectTemp /5-36 https://realpython.com/python-data-classes/ +RedirectTemp /5-37 https://www.youtube.com/watch?v=T-TwcmT6Rcw +RedirectTemp /5-38 https://www.attrs.org/en/stable/ +RedirectTemp /5-39 https://glyph.twistedmatrix.com/2016/08/attrs.html +RedirectTemp /5-40 https://www.attrs.org/en/stable/why.html +RedirectTemp /5-41 https://github.com/dabeaz/cluegen +RedirectTemp /5-42 https://refactoring.guru/ +RedirectTemp /5-43 https://refactoring.guru/smells/data-class +RedirectTemp /5-44 https://web.archive.org/web/20190204130328/http://catb.org/esr/jargon/html/G/Guido.html +RedirectTemp /5-45 https://web.archive.org/web/20190211161610/http://catb.org/esr/jargon/html/index.html +RedirectTemp /5-47 https://www.attrs.org/en/stable/ +############################################################ 06 +RedirectTemp /6-3 https://www.olin.edu/faculty/profile/lynn-andrea-stein/ +RedirectTemp /6-4 https://docs.python.org/3/reference/datamodel.html#objects-values-and-types +RedirectTemp /6-5 https://pythontutor.com/ +RedirectTemp /6-6 https://docs.python.org/3/library/copy.html +RedirectTemp /6-7 https://en.wikipedia.org/wiki/Principle_of_least_astonishment +RedirectTemp /6-8 https://docs.python.org/3/reference/datamodel.html#object.%5C_%5C_del__ +RedirectTemp /6-9 https://emptysqua.re/blog/pypy-garbage-collection-and-a-deadlock/ +RedirectTemp /6-15 https://www.youtube.com/watch?v=HHFCFJSPWrI&feature=youtu.be +RedirectTemp /6-16 http://pymotw.com/3/copy/ +RedirectTemp /6-17 http://pymotw.com/3/weakref/ +RedirectTemp /6-18 https://docs.python.org/3/library/gc.html +RedirectTemp /6-20 https://devguide.python.org/garbage_collector/ +RedirectTemp /6-21 https://devguide.python.org/ +RedirectTemp /6-22 https://www.python.org/dev/peps/pep-0442/ +RedirectTemp /6-23 https://en.wikipedia.org/wiki/String_interning +RedirectTemp /6-24 https://en.wikipedia.org/wiki/Haddocks%27_Eyes +RedirectTemp /6-25 https://thp.io/2012/python-gc/python_gc_final_2012-01-22.pdf +############################################################ 07 +RedirectTemp /7-1 http://python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html +RedirectTemp /7-3 https://www.fluentpython.com/extra/function-introspection/ +RedirectTemp /7-5 https://docs.python.org/3/library/functions.html#map +RedirectTemp /7-6 https://en.wikipedia.org/wiki/Functional_programming +RedirectTemp /7-7 https://docs.python.org/3/howto/functional.html +RedirectTemp /7-8 https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy +RedirectTemp /7-9 https://docs.python.org/3/whatsnew/3.8.html#positional-only-parameters +RedirectTemp /7-10 https://docs.python.org/3/whatsnew/3.8.html#positional-only-parameters +RedirectTemp /7-12 https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy +RedirectTemp /7-14 https://docs.python.org/3/howto/functional.html +RedirectTemp /7-15 https://stackoverflow.com/questions/3252228/python-why-is-functools-partial-necessary +RedirectTemp /7-16 https://speakerdeck.com/ramalho/beyond-paradigms-berlin-edition +RedirectTemp /7-17 https://www.youtube.com/watch?v=bF3a2VYXxa0 +RedirectTemp /7-18 http://cs.brown.edu/~sk/Publications/Papers/Published/sk-teach-pl-post-linnaean/ +RedirectTemp /7-19 http://python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html +RedirectTemp /7-20 https://raw.githubusercontent.com/python/cpython/main/Misc/HISTORY +RedirectTemp /7-21 http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html +############################################################ 08 +RedirectTemp /8-1 https://www.python.org/dev/peps/pep-0484/#non-goals +RedirectTemp /8-4 https://github.com/python/typing/issues/182 +RedirectTemp /8-5 https://github.com/python/mypy/issues/731 +RedirectTemp /8-6 https://github.com/google/pytype +RedirectTemp /8-7 https://github.com/Microsoft/pyright +RedirectTemp /8-8 https://pyre-check.org/ +RedirectTemp /8-10 https://mypy.readthedocs.io/en/stable/introduction.html +RedirectTemp /8-11 https://mypy.readthedocs.io/en/stable/config_file.html +RedirectTemp /8-12 https://pypi.org/project/flake8/ +RedirectTemp /8-13 https://pypi.org/project/blue/ +RedirectTemp /8-14 https://pypi.org/project/black/ +RedirectTemp /8-16 https://wefearchange.org/2020/11/steeringcouncil.rst.html +RedirectTemp /8-17 https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes +RedirectTemp /8-18 https://en.wikipedia.org/wiki/Barbara_Liskov +RedirectTemp /8-19 https://en.wikipedia.org/wiki/Behavioral_subtyping +RedirectTemp /8-22 https://www.python.org/dev/peps/pep-0585/#implementation +RedirectTemp /8-25 https://docs.python.org/3/library/typing.html#module-contents +RedirectTemp /8-26 https://en.wikipedia.org/wiki/Geohash +RedirectTemp /8-27 https://en.wikipedia.org/wiki/Inverted_index +RedirectTemp /8-29 https://docs.python.org/3/library/typing.html#typing.List +RedirectTemp /8-30 https://docs.python.org/3/library/typing.html#typing.Dict +RedirectTemp /8-31 https://docs.python.org/3/library/typing.html#typing.Set +RedirectTemp /8-32 https://www.python.org/dev/peps/pep-0585/#implementation +RedirectTemp /8-34 https://docs.python.org/3/library/numbers.html +RedirectTemp /8-37 https://docs.python.org/3/library/typing.html#typing.List +RedirectTemp /8-38 https://github.com/python/typeshed +RedirectTemp /8-39 https://github.com/python/typeshed/blob/66cd36268a6a667714efaa27198a41d0d7f89477/stdlib/2and3/math.pyi#L45 +RedirectTemp /8-41 https://docs.python.org/3/library/statistics.html#statistics.mode +RedirectTemp /8-42 https://docs.python.org/3/library/statistics.html#statistics.mode +RedirectTemp /8-46 https://docs.python.org/3/library/typing.html#typing.Callable +RedirectTemp /8-47 https://pypi.org/project/blue/ +RedirectTemp /8-48 https://www.python.org/dev/peps/pep-0484/#id38 +RedirectTemp /8-49 https://docs.google.com/document/d/1aXs1tpwzPjW9MdsG5dI7clNFyYayFBkcXwRDo-qvbIk/preview +RedirectTemp /8-50 https://www.oreilly.com/library/view/the-best-software/9781590595008/ +RedirectTemp /8-51 https://www.youtube.com/watch?v=YFexUDjHO6w +RedirectTemp /8-52 https://www.youtube.com/watch?v=YFexUDjHO6w&t=13m40s +RedirectTemp /8-53 https://bernat.tech/posts/the-state-of-type-hints-in-python/ +RedirectTemp /8-54 https://realpython.com/python-type-checking/ +RedirectTemp /8-55 https://cjolowicz.github.io/posts/hypermodern-python-04-typing/ +RedirectTemp /8-56 https://mypy.readthedocs.io/en/stable/index.html +RedirectTemp /8-57 https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html +RedirectTemp /8-58 https://mypy.readthedocs.io/en/stable/common_issues.html +RedirectTemp /8-60 https://github.com/typeddjango/awesome-python-typing +RedirectTemp /8-61 https://docs.python.org/3/library/functions.html#max +RedirectTemp /8-62 https://en.wikipedia.org/wiki/Linguistic_relativity +RedirectTemp /8-63 https://pypistats.org/top +RedirectTemp /8-64 https://github.com/psf/requests/issues/3855 +RedirectTemp /8-65 https://lwn.net/Articles/643399/ +RedirectTemp /8-66 https://docs.python-requests.org/en/master/api/#requests.request +RedirectTemp /8-67 https://queue.acm.org/detail.cfm?id=1039523 +############################################################ 09 +RedirectTemp /9-1 https://docs.python.org/3/library/dis.html +RedirectTemp /9-2 https://en.wikipedia.org/wiki/Memoization +RedirectTemp /9-3 https://numpy.org/doc/stable/user/basics.types.html +RedirectTemp /9-5 https://docs.python.org/3/library/functools.html#functools.singledispatch +RedirectTemp /9-7 https://github.com/GrahamDumpleton/wrapt/blob/develop/blog/README.md +RedirectTemp /9-8 https://github.com/GrahamDumpleton/wrapt/blob/develop/blog/01-how-you-implemented-your-python-decorator-is-wrong.md +RedirectTemp /9-9 https://wrapt.readthedocs.io/en/latest/ +RedirectTemp /9-10 https://www.oreilly.com/library/view/python-cookbook-3rd/9781449357337/ch09.html +RedirectTemp /9-11 https://pypi.org/project/decorator/ +RedirectTemp /9-12 https://wiki.python.org/moin/PythonDecoratorLibrary +RedirectTemp /9-13 http://web.archive.org/web/20201109032203/http://effbot.org/zone/closure.htm +RedirectTemp /9-14 https://www.python.org/dev/peps/pep-3104/ +RedirectTemp /9-15 https://www.python.org/dev/peps/pep-0227/ +RedirectTemp /9-16 https://www.python.org/dev/peps/pep-0443/ +RedirectTemp /9-17 https://www.artima.com/weblogs/viewpost.jsp?thread=101605 +RedirectTemp /9-18 https://reg.readthedocs.io/en/latest/ +RedirectTemp /9-19 https://morepath.readthedocs.io/en/latest/ +RedirectTemp /9-20 https://www.gnu.org/software/emacs/manual/html_node/elisp/Dynamic-Binding.html +RedirectTemp /9-21 http://www.paulgraham.com/rootsoflisp.html +RedirectTemp /9-22 http://www-formal.stanford.edu/jmc/recursive/recursive.html +RedirectTemp /9-23 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this +############################################################ 10 +RedirectTemp /10-1 https://en.wikipedia.org/wiki/Software_design_pattern +RedirectTemp /10-2 https://en.wikipedia.org/wiki/Iterator_pattern +RedirectTemp /10-4 https://github.com/python/mypy/issues/9397 +RedirectTemp /10-5 http://www.norvig.com/design-patterns/index.htm +RedirectTemp /10-6 https://pyvideo.org/video/1110/python-design-patterns/ +RedirectTemp /10-7 http://www.aleax.it/gdd_pydp.pdf +RedirectTemp /10-9 https://perl.plover.com/yak/design/ +RedirectTemp /10-11 https://en.wikipedia.org/wiki/Turtles_all_the_way_down +############################################################ 11 +RedirectTemp /11-1 https://blog.startifact.com/posts/older/what-is-pythonic.html +RedirectTemp /11-2 https://julien.danjou.info/guide-python-static-class-abstract-methods/ +RedirectTemp /11-3 https://docs.python.org/3/library/string.html#formatspec +RedirectTemp /11-5 https://docs.python.org/3/reference/lexical_analysis.html#f-strings +RedirectTemp /11-6 https://docs.python.org/3/library/string.html#format-string-syntax +RedirectTemp /11-7 https://docs.python.org/3/library/string.html#formatspec +RedirectTemp /11-8 https://docs.python.org/3/reference/datamodel.html#object.__hash__ +RedirectTemp /11-9 https://web.archive.org/web/20161025185040/http://pythonpaste.org/StyleGuide.html +RedirectTemp /11-10 https://docs.python.org/3/tutorial/modules.html#more-on-modules +RedirectTemp /11-11 https://docs.python.org/3/library/gettext.html#gettext.NullTranslations +RedirectTemp /11-12 https://github.com/fluentpython/example-code-2e/blob/master/11-pythonic-obj/mem_test.py +RedirectTemp /11-16 https://docs.python.org/3/reference/datamodel.html#basic-customization +RedirectTemp /11-18 http://esug.org/data/HistoricalDocuments/TheSmalltalkReport/ST07/04wo.pdf +RedirectTemp /11-19 https://docs.oracle.com/javase/tutorial/essential/environment/security.html +RedirectTemp /11-21 https://docs.oracle.com/javase/tutorial/essential/environment/security.html +############################################################ 12 +RedirectTemp /12-1 https://en.wikipedia.org/wiki/Vector_space_model +RedirectTemp /12-2 https://pypi.org/project/gensim/ +RedirectTemp /12-6 https://docs.python.org/3/library/functions.html#enumerate +RedirectTemp /12-7 https://mathworld.wolfram.com/Hypersphere.html +RedirectTemp /12-12 https://en.wikipedia.org/wiki/Fold_(higher-order_function) +RedirectTemp /12-13 https://docs.python.org/2.5/whatsnew/pep-357.html +RedirectTemp /12-15 https://docs.python.org/3/reference/datamodel.html#special-method-names +RedirectTemp /12-16 https://en.wikipedia.org/wiki/KISS_principle +RedirectTemp /12-17 https://mail.python.org/pipermail/python-list/2000-July/046184.html +RedirectTemp /12-18 https://en.wikipedia.org/wiki/Duck_typing +RedirectTemp /12-19 https://mail.python.org/mailman/listinfo/python-list +RedirectTemp /12-20 https://mail.python.org/pipermail/python-list/2003-April/218568.html +############################################################ 13 +RedirectTemp /13-2 https://docs.python.org/3/c-api/index.html +RedirectTemp /13-3 https://docs.python.org/3/c-api/sequence.html +RedirectTemp /13-7 https://github.com/python/cpython/blob/31ceccb2c77854893f3a754aca04bedd74bedb10/Lib/_collections_abc.py#L870 +RedirectTemp /13-8 https://en.wikipedia.org/wiki/Monkey_patch +RedirectTemp /13-9 https://www.gevent.org/api/gevent.monkey.html +RedirectTemp /13-10 https://docs.python.org/3/library/random.html#random.shuffle +RedirectTemp /13-11 https://docs.python.org/3/reference/datamodel.html#emulating-container-types +RedirectTemp /13-12 https://docs.python.org/3/library/collections.html#collections.namedtuple +RedirectTemp /13-13 https://github.com/python/typeshed/blob/24afb531ffd07083d6a74be917342195062f7277/stdlib/collections/__init__.pyi +RedirectTemp /13-14 https://docs.python.org/3/glossary.html#term-abstract-base-class +RedirectTemp /13-15 https://en.wikipedia.org/wiki/Duck_typing#History +RedirectTemp /13-16 http://ptgmedia.pearsoncmg.com/images/020163371x/items/item33.html +RedirectTemp /13-17 https://docs.python.org/3/library/bisect.html#bisect.bisect +RedirectTemp /13-20 https://github.com/python/cpython/blob/main/Lib/_collections_abc.py +RedirectTemp /13-21 https://github.com/python/cpython/blob/main/Lib/abc.py +RedirectTemp /13-22 https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes +RedirectTemp /13-23 https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable +RedirectTemp /13-24 https://docs.python.org/3/library/abc.html +RedirectTemp /13-25 https://docs.python.org/dev/library/abc.html#abc.abstractmethod +RedirectTemp /13-26 https://docs.python.org/dev/library/abc.html +RedirectTemp /13-27 https://docs.python.org/3/library/os.html#os.urandom +RedirectTemp /13-28 https://github.com/python/mypy/issues/2922 +RedirectTemp /13-29 https://docs.python.org/3/library/stdtypes.html#truth +RedirectTemp /13-30 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Lib/_collections_abc.py +RedirectTemp /13-31 https://github.com/python/cpython/blob/0fbddb14dc03f61738af01af88e7d8aa8df07336/Lib/_collections_abc.py#L369 +RedirectTemp /13-32 https://bugs.python.org/issue31333 +RedirectTemp /13-33 https://github.com/python/cpython/blob/3635388f52b42e5280229104747962117104c453/Modules/_abc.c#L605 +RedirectTemp /13-34 https://github.com/python/cpython/blob/0fbddb14dc03f61738af01af88e7d8aa8df07336/Lib/_collections_abc.py#L881 +RedirectTemp /13-37 https://docs.python.org/3/library/typing.html#protocols +RedirectTemp /13-40 https://martinfowler.com/bliki/RoleInterface.html +RedirectTemp /13-41 https://en.wikipedia.org/wiki/Interface_segregation_principle +RedirectTemp /13-42 https://github.com/python/typeshed/blob/master/CONTRIBUTING.md +RedirectTemp /13-43 https://gist.github.com/asukakenji/ac8a05644a2e98f1d5ea8c299541fce9 +RedirectTemp /13-44 https://www.python.org/dev/peps/pep-0544/#merging-and-extending-protocols +RedirectTemp /13-45 https://numpy.org/devdocs/user/basics.types.html +RedirectTemp /13-46 https://github.com/python/typeshed/blob/master/stdlib/statistics.pyi +RedirectTemp /13-47 https://bugs.python.org/issue41974 +RedirectTemp /13-49 https://glyph.twistedmatrix.com/2020/07/new-duck.html +RedirectTemp /13-50 https://glyph.twistedmatrix.com/2021/03/interfaces-and-protocols.html +RedirectTemp /13-51 https://plone.org/ +RedirectTemp /13-52 https://trypyramid.com/ +RedirectTemp /13-53 https://twistedmatrix.com/trac/ +RedirectTemp /13-54 https://www.artima.com/articles/contracts-in-python +RedirectTemp /13-55 https://martinfowler.com/bliki/DynamicTyping.html +RedirectTemp /13-56 https://martinfowler.com/bliki/RoleInterface.html +RedirectTemp /13-57 https://mypy.readthedocs.io/en/stable/protocols.html +RedirectTemp /13-58 https://pymotw.com/3/abc/index.html +RedirectTemp /13-59 https://www.python.org/dev/peps/pep-3119/ +RedirectTemp /13-60 https://www.python.org/dev/peps/pep-3141/ +RedirectTemp /13-61 https://docs.python.org/3/library/numbers.html +RedirectTemp /13-62 https://github.com/python/mypy/issues/3186 +RedirectTemp /13-63 https://github.com/python/mypy/issues/3186 +RedirectTemp /13-64 https://martinfowler.com/articles/lean-inception/ +RedirectTemp /13-65 https://martinfowler.com +RedirectTemp /13-68 https://www.jetbrains.com/pycharm/ +RedirectTemp /13-69 https://wingware.com/ +RedirectTemp /13-70 https://code.visualstudio.com/ +############################################################ 14 +RedirectTemp /14-1 http://worrydream.com/EarlyHistoryOfSmalltalk/ +RedirectTemp /14-2 https://docs.python.org/3/tutorial/classes.html +RedirectTemp /14-3 https://docs.python.org/3/library/collections.html#ordereddict-examples-and-recipes +RedirectTemp /14-4 https://discuss.python.org/t/is-it-time-to-deprecate-unbound-super-methods/1833 +RedirectTemp /14-6 https://doc.pypy.org/en/latest/cpython_differences.html#subclasses-of-built-in-types +RedirectTemp /14-7 https://docs.python.org/3/library/collections.html +RedirectTemp /14-9 https://doc.pypy.org/en/latest/cpython_differences.html#subclasses-of-built-in-types +RedirectTemp /14-10 https://en.wikipedia.org/wiki/Breadth-first_search +RedirectTemp /14-11 https://www.python.org/download/releases/2.3/mro/ +RedirectTemp /14-12 https://github.com/fluentpython/example-code-2e/blob/master/14-inheritance/uppermixin.py +RedirectTemp /14-13 https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html +RedirectTemp /14-14 https://docs.python.org/3/library/collections.abc.html +RedirectTemp /14-15 https://github.com/python/cpython/blob/8ece98a7e418c3c68a4c61bc47a2d0931b59a889/Lib/collections/__init__.py#L1084 +RedirectTemp /14-16 https://docs.python.org/3/library/http.server.html +RedirectTemp /14-17 https://docs.python.org/3/library/socketserver.html#socketserver.ForkingMixIn +RedirectTemp /14-18 https://docs.python.org/3/library/os.html#os.fork +RedirectTemp /14-19 https://en.wikipedia.org/wiki/POSIX +RedirectTemp /14-20 http://ccbv.co.uk/ +RedirectTemp /14-21 https://github.com/django/django/tree/main/django/views/generic +RedirectTemp /14-22 https://en.wikipedia.org/wiki/Template_method_pattern +RedirectTemp /14-23 https://docs.python.org/3/library/tkinter.html +RedirectTemp /14-24 https://docs.python.org/3/library/tkinter.ttk.html +RedirectTemp /14-25 https://docs.oracle.com/javase/10/docs/api/java/awt/package-tree.html +RedirectTemp /14-26 https://docs.oracle.com/javase/10/docs/api/javax/swing/package-tree.html +RedirectTemp /14-27 https://squeak.org/ +RedirectTemp /14-28 https://github.com/python/cpython/blob/8ed183391241f0c73e7ba7f42b1d49fc02985f7b/Lib/tkinter/__init__.py#L2618 +RedirectTemp /14-29 https://docs.python.org/3/library/socketserver.html +RedirectTemp /14-30 https://docs.python.org/3/library/socketserver.html#socketserver.BaseServer +RedirectTemp /14-32 https://docs.python.org/3/library/typing.html#typing.final +RedirectTemp /14-33 https://docs.python.org/3/library/typing.html#typing.Final +RedirectTemp /14-35 https://docs.python.org/3/library/collections.abc.html +RedirectTemp /14-36 https://hynek.me/articles/python-subclassing-redux/ +RedirectTemp /14-38 https://rhettinger.wordpress.com/2011/05/26/super-considered-super/ +RedirectTemp /14-39 https://fuhm.net/super-harmful/ +RedirectTemp /14-40 https://www.artima.com/weblogs/viewpost.jsp?thread=246488 +RedirectTemp /14-41 https://www.artima.com/weblogs/viewpost.jsp?thread=281127 +RedirectTemp /14-42 https://www.artima.com/weblogs/viewpost.jsp?thread=246341 +RedirectTemp /14-43 https://www.artima.com/weblogs/viewpost.jsp?thread=246483 +RedirectTemp /14-44 https://www.artima.com/weblogs/viewpost.jsp?thread=236275 +RedirectTemp /14-45 https://www.artima.com/weblogs/viewpost.jsp?thread=236278 +RedirectTemp /14-46 https://www.artima.com/weblogs/viewpost.jsp?thread=237121 +RedirectTemp /14-47 https://python-patterns.guide/gang-of-four/composition-over-inheritance/ +RedirectTemp /14-48 https://python-patterns.guide/ +RedirectTemp /14-49 https://www.youtube.com/watch?v=3MNVP9-hglc +RedirectTemp /14-50 http://worrydream.com/EarlyHistoryOfSmalltalk/ +RedirectTemp /14-51 https://en.wikipedia.org/wiki/Polymorphism_(computer_science) +############################################################ 15 +RedirectTemp /15-1 https://www.youtube.com/watch?v=csL8DLXGNlU&t=92m5s +RedirectTemp /15-4 https://twitter.com/gwidion/status/1265384692464967680 +RedirectTemp /15-5 https://pypi.org/project/pydantic/ +RedirectTemp /15-7 https://google.github.io/pytype/faq.html +RedirectTemp /15-8 https://google.github.io/pytype/faq.html +RedirectTemp /15-9 https://lxml.de/ +RedirectTemp /15-10 https://docs.python.org/3/library/xml.etree.elementtree.html +RedirectTemp /15-11 https://mypy.readthedocs.io/en/stable/common_issues.html +RedirectTemp /15-12 https://mypy.readthedocs.io/en/stable/common_issues.html#types-of-empty-collections +RedirectTemp /15-13 https://github.com/python/typing/issues/182 +RedirectTemp /15-14 https://pypi.org/project/pydantic/ +RedirectTemp /15-16 https://mypy.readthedocs.io/en/stable/type_narrowing.html#casts +RedirectTemp /15-17 https://www.python.org/dev/peps/pep-0484/#casts +RedirectTemp /15-18 https://github.com/python/typeshed/issues/5535 +RedirectTemp /15-19 https://docs.python.org/3/library/asyncio-stream.html#tcp-echo-server-using-streams +RedirectTemp /15-20 https://en.wikipedia.org/wiki/Code_smell +RedirectTemp /15-21 https://mypy.readthedocs.io/en/stable/error_codes.html#error-codes +RedirectTemp /15-22 https://github.com/fluentpython/example-code-2e/blob/master/15-more-types/clip_annot.py +RedirectTemp /15-24 https://docs.python.org/3/library/typing.html#introspection-helpers +RedirectTemp /15-25 https://docs.python.org/3.10/library/inspect.html#inspect.get_annotations +RedirectTemp /15-27 https://www.python.org/dev/peps/pep-0563/#abstract +RedirectTemp /15-29 https://docs.python.org/3.10/howto/annotations.html +RedirectTemp /15-32 https://docs.python.org/3/library/typing.html#user-defined-generic-types +RedirectTemp /15-33 https://docs.python.org/3.10/library/typing.html#typing.FrozenSet +RedirectTemp /15-34 https://docs.python.org/3.10/library/typing.html#typing.Generator +RedirectTemp /15-36 https://docs.python.org/3.10/library/typing.html#typing.AsyncGenerator +RedirectTemp /15-62 https://www.oreilly.com/library/view/robust-python/9781098100650/ +RedirectTemp /15-63 https://www.python.org/dev/peps/pep-0484/#covariance-and-contravariance +RedirectTemp /15-64 https://mypy.readthedocs.io/en/stable/generics.html#variance-of-generic-types +RedirectTemp /15-65 https://mypy.readthedocs.io/en/stable/common_issues.html#variance +RedirectTemp /15-67 https://www.artima.com/weblogs/viewpost.jsp?thread=85551 +RedirectTemp /15-68 https://dl.acm.org/action/cookieAbsent +RedirectTemp /15-69 http://bracha.org/pluggableTypesPosition.pdf +RedirectTemp /15-70 https://www.atomickotlin.com/atomickotlin/ +RedirectTemp /15-71 https://www.informit.com/store/effective-java-9780134685991 +RedirectTemp /15-72 https://www.manning.com/books/programming-with-types +RedirectTemp /15-73 https://www.oreilly.com/library/view/programming-typescript/9781492037644/ +RedirectTemp /15-74 https://www.informit.com/store/dart-programming-language-9780321927705 +RedirectTemp /15-75 https://www.yodaiken.com/2017/09/15/bad-ideas-in-type-theory/ +RedirectTemp /15-76 https://www.yodaiken.com/2017/11/30/types-considered-harmful-ii/ +RedirectTemp /15-77 https://web.archive.org/web/20071010002142/http://weblogs.java.net/blog/arnold/archive/2005/06/generics_consid_1.html +RedirectTemp /15-78 https://www.python.org/dev/peps/pep-0484/#covariance-and-contravariance +############################################################ 16 +RedirectTemp /16-1 http://www.gotw.ca/publications/c_family_interview.htm +RedirectTemp /16-2 https://docs.python.org/3/reference/expressions.html#unary-arithmetic-and-bitwise-operations +RedirectTemp /16-4 https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#boolean-indexing +RedirectTemp /16-5 https://docs.python.org/3/library/collections.html#collections.Counter +RedirectTemp /16-6 https://docs.python.org/3/reference/datamodel.html#emulating-container-types +RedirectTemp /16-8 https://docs.python.org/3/library/numbers.html#implementing-the-arithmetic-operations +RedirectTemp /16-10 https://www.fluentpython.com/lingo/#fail-fast +RedirectTemp /16-11 https://neopythonic.blogspot.com/2019/03/why-operators-are-useful.html +RedirectTemp /16-12 https://treyhunner.com/2019/03/python-deep-comparisons-and-code-readability/ +RedirectTemp /16-14 https://docs.python.org/3/library/numbers.html#implementing-the-arithmetic-operations +RedirectTemp /16-15 https://docs.python.org/3/library/pathlib.html +RedirectTemp /16-16 https://pypi.org/project/scapy/ +RedirectTemp /16-17 https://scapy.readthedocs.io/en/latest/usage.html#stacking-layers +RedirectTemp /16-18 https://docs.python.org/3/library/functools.html#functools.total_ordering +RedirectTemp /16-19 https://wiki.illinois.edu//wiki/download/attachments/273416327/ingalls.pdf +RedirectTemp /16-20 https://wiki.illinois.edu//wiki/download/attachments/273416327/double-dispatch.pdf +RedirectTemp /16-21 http://www.gotw.ca/publications/c_family_interview.htm +RedirectTemp /16-22 https://doc.rust-lang.org/std/ops/index.html +RedirectTemp /16-23 https://www.fluentpython.com/lingo/#lazy +############################################################ 17 +RedirectTemp /17-1 http://www.paulgraham.com/icad.html +RedirectTemp /17-5 https://en.wikipedia.org/wiki/Sentinel_value +RedirectTemp /17-6 https://docs.python.org/3.10/library/functions.html#iter +RedirectTemp /17-7 https://docs.python.org/3.10/library/functions.html#iter +RedirectTemp /17-8 https://github.com/python/cpython/blob/b1930bf75f276cd7ca08c4455298128d89adf7d1/Lib/_collections_abc.py#L271 +RedirectTemp /17-9 https://github.com/python/cpython/blob/main/Lib/types.py#L6 +RedirectTemp /17-10 https://en.wikipedia.org/wiki/CLU_(programming_language) +RedirectTemp /17-12 https://docs.python.org/3/glossary.html +RedirectTemp /17-13 https://docs.python.org/3/glossary.html#term-generator-iterator +RedirectTemp /17-14 https://docs.python.org/3/glossary.html#term-generator-expression +RedirectTemp /17-15 https://marc.info/?l=python-list&m=141826925106951&w=2 +RedirectTemp /17-17 https://docs.python.org/3/library/itertools.html +RedirectTemp /17-18 https://docs.python.org/3/library/exceptions.html#exception-hierarchy +RedirectTemp /17-19 https://en.wikipedia.org/wiki/Depth-first_search +RedirectTemp /17-20 https://docs.python.org/3.10/library/typing.html#typing.TypeAlias +RedirectTemp /17-22 https://docs.python.org/3/library/typing.html#typing.Generator +RedirectTemp /17-25 http://www.dabeaz.com/coroutines/Coroutines.pdf +RedirectTemp /17-26 http://www.dabeaz.com/coroutines/Coroutines.pdf +RedirectTemp /17-27 https://mail.python.org/pipermail/python-ideas/2009-April/003841.html +RedirectTemp /17-28 https://mail.python.org/pipermail/python-ideas/2009-April/003912.html +RedirectTemp /17-31 https://docs.python.org/3/library/exceptions.html#StopIteration +RedirectTemp /17-32 https://docs.python.org/3/reference/expressions.html#yield-expressions +RedirectTemp /17-33 https://docs.python.org/3/reference/index.html +RedirectTemp /17-36 http://catb.org/~esr/jargon/html/G/grok.html +RedirectTemp /17-37 https://docs.python.org/3/reference/expressions.html#yieldexpr +RedirectTemp /17-39 https://docs.python.org/3/library/itertools.html#itertools-recipes +RedirectTemp /17-40 https://more-itertools.readthedocs.io/en/stable/index.html +RedirectTemp /17-41 https://rittau.org/2006/11/java-iterators-are-not-iterable/ +RedirectTemp /17-42 https://docs.python.org/3/whatsnew/3.3.html#pep-380-syntax-for-delegating-to-a-subgenerator +RedirectTemp /17-45 http://www.dabeaz.com/generators/ +RedirectTemp /17-46 http://www.dabeaz.com/coroutines/ +RedirectTemp /17-47 https://archive.org/details/pyvideo_213___pycon-2009-a-curious-course-on-coroutines-and-concurrency-part-1-of-3 +RedirectTemp /17-48 https://archive.org/details/pyvideo_215___pycon-2009-a-curious-course-on-coroutines-and-concurrency-part-2-of-3 +RedirectTemp /17-49 https://archive.org/details/pyvideo_214___pycon-2009-a-curious-course-on-coroutines-and-concurrency-part-3-of-3 +RedirectTemp /17-50 http://www.dabeaz.com/finalgenerator/ +RedirectTemp /17-51 https://web.archive.org/web/20200218150637/http://seriously.dontusethiscode.com/2013/05/01/greedy-coroutine.html +RedirectTemp /17-52 https://effectivepython.com/ +RedirectTemp /17-53 https://effectivepython.com/2015/03/10/consider-coroutines-to-run-many-functions-concurrently +RedirectTemp /17-54 https://en.wikipedia.org/wiki/Conway's_Game_of_Life +RedirectTemp /17-55 https://gist.github.com/ramalho/da5590bc38c973408839 +RedirectTemp /17-56 https://gist.github.com/ramalho/da5590bc38c973408839 +RedirectTemp /17-57 https://journal.code4lib.org/articles/4893 +RedirectTemp /17-58 https://github.com/fluentpython/isis2json +RedirectTemp /17-59 https://github.com/fluentpython/isis2json/blob/master/README.rst +############################################################ 18 +RedirectTemp /18-1 https://pyvideo.org/video/1669/keynote-3/ +RedirectTemp /18-2 https://docs.python.org/3/library/sqlite3.html#using-the-connection-as-a-context-manager +RedirectTemp /18-3 https://docs.python.org/3/library/threading.html#using-locks-conditions-and-semaphores-in-the-with-statement +RedirectTemp /18-4 https://docs.python.org/3/library/decimal.html#decimal.localcontext +RedirectTemp /18-5 https://docs.python.org/3/library/unittest.mock.html#patch +RedirectTemp /18-6 https://docs.python.org/3/library/contextlib.html#contextlib.redirect_stdout +RedirectTemp /18-7 https://docs.python.org/3/library/sys.html#sys.exc_info +RedirectTemp /18-9 https://en.wikipedia.org/wiki/LL_parser +RedirectTemp /18-10 https://docs.python.org/3/library/contextlib.html +RedirectTemp /18-11 https://www.zopatista.com/python/2013/11/26/inplace-file-rewriting/ +RedirectTemp /18-12 https://docs.python.org/3/library/fileinput.html#fileinput.input +RedirectTemp /18-13 https://www.zopatista.com/python/2013/11/26/inplace-file-rewriting/ +RedirectTemp /18-14 https://en.wikipedia.org/wiki/Euclidean_algorithm +RedirectTemp /18-15 https://github.com/fluentpython/example-code-2e/tree/master/18-with-match/lispy/py3.10/ +RedirectTemp /18-17 https://github.com/python/typeshed/issues/6042 +RedirectTemp /18-18 https://github.com/fluentpython/lispy/tree/main/mylis +RedirectTemp /18-19 https://mitpress.mit.edu/sites/default/files/sicp/index.html +RedirectTemp /18-20 https://www.python.org/dev/peps/pep-0634/#or-patterns +RedirectTemp /18-21 https://en.wikipedia.org/wiki/Lambda#Character_encodings +RedirectTemp /18-22 https://docs.python.org/3/reference/compound_stmts.html +RedirectTemp /18-23 https://docs.python.org/3/glossary.html#term-eafp +RedirectTemp /18-24 https://speakerdeck.com/pyconslides/pycon-keynote-python-is-awesome-by-raymond-hettinger?slide=21 +RedirectTemp /18-25 https://docs.python.org/3/reference/compound_stmts.html +RedirectTemp /18-26 https://stackoverflow.com/questions/16138232/is-it-a-good-practice-to-use-try-except-else-in-python +RedirectTemp /18-27 https://docs.python.org/3/library/stdtypes.html#typecontextmanager +RedirectTemp /18-28 https://docs.python.org/3/reference/datamodel.html#with-statement-context-managers +RedirectTemp /18-30 https://speakerdeck.com/pyconslides/pycon-keynote-python-is-awesome-by-raymond-hettinger?slide=21 +RedirectTemp /18-31 https://speakerdeck.com/pyconslides/transforming-code-into-beautiful-idiomatic-python-by-raymond-hettinger-1?slide=34 +RedirectTemp /18-32 https://preshing.com/20110920/the-python-with-statement-by-example/ +RedirectTemp /18-33 https://www.rath.org/on-the-beauty-of-pythons-exitstack.html +RedirectTemp /18-34 https://github.com/norvig/pytudes +RedirectTemp /18-35 https://github.com/fluentpython/lispy +RedirectTemp /18-36 https://racket-lang.org/ +RedirectTemp /18-37 https://pyvideo.org/video/1669/keynote-3/ +RedirectTemp /18-38 https://en.wikipedia.org/wiki/Tail_call +RedirectTemp /18-39 https://2ality.com/2015/06/tail-call-optimization.html +RedirectTemp /18-40 http://neopythonic.blogspot.com/2009/04/final-words-on-tail-calls.html +RedirectTemp /18-41 https://webkit.org/blog/6240/ecmascript-6-proper-tail-calls-in-webkit/ +RedirectTemp /18-42 http://kangax.github.io/compat-table/es6/ +RedirectTemp /18-43 https://world.hey.com/mgmarlow/what-happened-to-proper-tail-calls-in-javascript-5494c256 +RedirectTemp /18-44 http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html +RedirectTemp /18-45 https://github.com/fluentpython/lispy/blob/main/mylis/mylis_2/lis.py +RedirectTemp /18-46 https://github.com/fluentpython/lispy/tree/main/mylis +############################################################ 19 +RedirectTemp /19-1 https://go.dev/blog/waza-talk +RedirectTemp /19-2 https://en.wikipedia.org/wiki/Graphics_processing_unit +RedirectTemp /19-3 https://docs.python.org/3/library/sys.html#sys.getswitchinterval +RedirectTemp /19-4 https://docs.python.org/3/library/sys.html#sys.setswitchinterval +RedirectTemp /19-5 https://en.wikipedia.org/wiki/System_call +RedirectTemp /19-6 https://mail.python.org/pipermail/python-dev/2009-October/093356.html +RedirectTemp /19-8 http://www.dabeaz.com/finalgenerator/ +RedirectTemp /19-9 https://docs.python.org/3/library/threading.html#thread-objects +RedirectTemp /19-10 https://www.pypy.org/ +RedirectTemp /19-11 https://mail.python.org/pipermail/python-list/2009-February/675659.html +RedirectTemp /19-12 https://en.wikipedia.org/wiki/Braille_Patterns +RedirectTemp /19-13 https://docs.python.org/3/library/multiprocessing.shared_memory.html +RedirectTemp /19-14 https://greenlet.readthedocs.io/en/latest/ +RedirectTemp /19-15 https://docs.sqlalchemy.org/en/14/orm/extensions/asyncio.html +RedirectTemp /19-16 http://www.gevent.org/ +RedirectTemp /19-17 https://github.com/gevent/gevent/wiki/Projects +RedirectTemp /19-19 https://docs.python.org/3/library/concurrent.futures.html#processpoolexecutor-example +RedirectTemp /19-20 https://github.com/python/asyncio/issues/284 +RedirectTemp /19-21 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor +RedirectTemp /19-23 https://docs.python.org/3/library/queue.html#queue.SimpleQueue.get +RedirectTemp /19-24 https://en.wikipedia.org/wiki/Race_condition +RedirectTemp /19-26 https://en.wikipedia.org/wiki/Context_switch +RedirectTemp /19-27 http://www.gotw.ca/publications/concurrency-ddj.htm +RedirectTemp /19-28 https://www.ansible.com/ +RedirectTemp /19-29 https://saltproject.io/ +RedirectTemp /19-30 https://www.fabfile.org/ +RedirectTemp /19-31 https://jupyter.org/ +RedirectTemp /19-32 https://docs.bokeh.org/en/latest/index.html +RedirectTemp /19-33 https://www.tensorflow.org/ +RedirectTemp /19-34 https://pytorch.org/ +RedirectTemp /19-35 https://www.oreilly.com/radar/where-programming-ops-ai-and-the-cloud-are-headed-in-2021/ +RedirectTemp /19-38 https://www.youtube.com/watch?v=ods97a5Pzw0 +RedirectTemp /19-39 https://www.thoughtworks.com/radar/techniques/high-performance-envy-web-scale-envy +RedirectTemp /19-41 https://modwsgi.readthedocs.io/en/master/ +RedirectTemp /19-42 https://uwsgi-docs.readthedocs.io/en/latest/ +RedirectTemp /19-44 https://unit.nginx.org/ +RedirectTemp /19-45 https://www.techatbloomberg.com/blog/configuring-uwsgi-production-deployment/ +RedirectTemp /19-46 https://www.youtube.com/watch?v=p6R1h2Nn468 +RedirectTemp /19-47 https://asgi.readthedocs.io/en/latest/index.html +RedirectTemp /19-48 https://docs.celeryproject.org/en/stable/getting-started/introduction.html +RedirectTemp /19-49 https://python-rq.org/ +RedirectTemp /19-50 https://redis.io/ +RedirectTemp /19-51 https://realpython.com/intro-to-python-threading/ +RedirectTemp /19-52 https://pymotw.com/3/concurrency.html +RedirectTemp /19-54 https://docs.python.org/3/library/multiprocessing.html#programming-guidelines +RedirectTemp /19-56 https://docs.python.org/3/library/multiprocessing.html +RedirectTemp /19-57 https://www.oreilly.com/library/view/high-performance-python/9781492055013/ +RedirectTemp /19-58 https://link.springer.com/book/10.1007/978-1-4842-5793-7?error=cookies_not_supported&code=2ed5d61d-ae9f-4f3d-94ac-0f68cf45ea4f +RedirectTemp /19-59 https://www.packtpub.com/product/parallel-programming-with-python/9781783288397 +RedirectTemp /19-61 https://greenteapress.com/wp/semaphores/ +RedirectTemp /19-62 https://docs.python.org/3/c-api/init.html#thread-state-and-the-global-interpreter-lock +RedirectTemp /19-63 https://www.artima.com/weblogs/viewpost.jsp?thread=214235 +RedirectTemp /19-64 http://jessenoller.com/blog/2009/02/01/python-threads-and-the-global-interpreter-lock +RedirectTemp /19-65 https://realpython.com/products/cpython-internals-book/ +RedirectTemp /19-66 http://www.dabeaz.com/GIL/ +RedirectTemp /19-67 http://www.dabeaz.com/python/UnderstandingGIL.pdf +RedirectTemp /19-68 https://bugs.python.org/issue7946#msg223110 +RedirectTemp /19-69 https://bugs.python.org/issue7946 +RedirectTemp /19-70 https://www.fullstackpython.com/ +RedirectTemp /19-71 https://www.oreilly.com/library/view/high-performance-python/9781492055013/ +RedirectTemp /19-72 https://www.packtpub.com/product/parallel-programming-with-python/9781783288397 +RedirectTemp /19-73 https://www.packtpub.com/product/distributed-computing-with-python/9781785889691 +RedirectTemp /19-74 https://towardsdatascience.com/python-performance-and-gpus-1be860ffd58d?gi=6a57a172ab5e +RedirectTemp /19-75 https://www.oreilly.com/library/view/architecture-patterns-with/9781492052197/ +RedirectTemp /19-76 https://www.cosmicpython.com/ +RedirectTemp /19-77 https://pypi.org/project/lelo/ +RedirectTemp /19-78 https://github.com/npryce/python-parallelize +RedirectTemp /19-79 https://github.com/ericsnowcurrently/multi-core-python/wiki +RedirectTemp /19-81 https://gist.github.com/markshannon/79cace3656b40e21b7021504daee950c +RedirectTemp /19-82 https://en.wikipedia.org/wiki/Communicating_sequential_processes +RedirectTemp /19-83 https://github.com/stackless-dev/stackless/wiki +RedirectTemp /19-84 https://www.eveonline.com +RedirectTemp /19-85 https://www.ccpgames.com/ +RedirectTemp /19-86 https://stackless.readthedocs.io/en/3.6-slp/stackless-python.html#history +RedirectTemp /19-87 https://doc.pypy.org/en/latest/stackless.html +RedirectTemp /19-88 https://greenlet.readthedocs.io/en/latest/ +RedirectTemp /19-89 http://www.gevent.org/ +RedirectTemp /19-91 http://thespianpy.com/doc/ +RedirectTemp /19-92 https://pykka.readthedocs.io/en/latest/ +RedirectTemp /19-93 https://www.manning.com/books/rabbitmq-in-action +RedirectTemp /19-94 https://pragprog.com/titles/pb7con/seven-concurrency-models-in-seven-weeks/ +RedirectTemp /19-95 https://en.wikipedia.org/wiki/OpenCL +RedirectTemp /19-96 https://media.pragprog.com/titles/pb7con/Bonus_Chapter.pdf +RedirectTemp /19-97 https://martinfowler.com/ +RedirectTemp /19-98 https://martinfowler.com/articles/patterns-of-distributed-systems/ +RedirectTemp /19-99 https://www.oreilly.com/library/view/oscon-2016-video/9781491965153/video247021.html +RedirectTemp /19-100 https://www.oreilly.com/library/view/designing-for-scalability/9781449361556/ +RedirectTemp /19-101 https://www.thoughtworks.com/radar/techniques/high-performance-envy-web-scale-envy +RedirectTemp /19-102 https://en.wikipedia.org/wiki/KISS_principle +RedirectTemp /19-103 https://www.usenix.org/conference/hotos15/workshop-program/presentation/mcsherry +############################################################ 20 +RedirectTemp /20-1 https://www.artima.com/weblogs/viewpost.jsp?thread=299551 +RedirectTemp /20-3 https://docs.python.org/3/library/http.server.html +RedirectTemp /20-4 https://www.youtube.com/watch?v=A9e9Cy1UkME +RedirectTemp /20-5 https://www.cia.gov/the-world-factbook/ +RedirectTemp /20-7 https://docs.python-requests.org/en/latest/ +RedirectTemp /20-8 https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.as_completed +RedirectTemp /20-9 https://docs.python.org/3/library/concurrent.futures.html +RedirectTemp /20-10 https://docs.python.org/3.10/library/concurrent.futures.html#concurrent.futures.Executor +RedirectTemp /20-12 https://github.com/noamraph/tqdm +RedirectTemp /20-13 https://www.youtube.com/watch?v=M8Z65tAl5l4 +RedirectTemp /20-14 https://github.com/noamraph/tqdm/blob/master/README.md +RedirectTemp /20-15 https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.as_completed +RedirectTemp /20-16 https://docs.python.org/3/library/asyncio-task.html#asyncio.as_completed +RedirectTemp /20-17 https://www.cloudflare.com/ +RedirectTemp /20-19 https://github.com/fluentpython/example-code-2e/tree/master/20-executors/getflags +RedirectTemp /20-21 https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/418 +RedirectTemp /20-22 https://en.wikipedia.org/wiki/Embarrassingly_parallel +RedirectTemp /20-23 https://pyvideo.org/video/480/pyconau-2010--the-future-is-soon/ +RedirectTemp /20-25 http://www.dabeaz.com/coroutines/ +RedirectTemp /20-26 https://en.wikipedia.org/wiki/POSIX_Threads +RedirectTemp /20-27 https://en.wikipedia.org/wiki/C_dynamic_memory_allocation +RedirectTemp /20-28 https://pragprog.com/titles/pb7con/seven-concurrency-models-in-seven-weeks/ +RedirectTemp /20-29 https://hexdocs.pm/ecto/getting-started.html +############################################################ 21 +RedirectTemp /21-1 https://docs.python.org/3/library/asyncio.html +RedirectTemp /21-6 https://bugs.python.org/issue43216 +RedirectTemp /21-7 https://bugs.python.org/issue36921 +RedirectTemp /21-8 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.getaddrinfo +RedirectTemp /21-9 https://docs.python.org/3/library/socket.html#socket.getaddrinfo +RedirectTemp /21-10 https://docs.python.org/3.10/library/asyncio-eventloop.html#asyncio.get_event_loop +RedirectTemp /21-11 https://www.python.org/dev/peps/pep-0492/#await-expression +RedirectTemp /21-14 https://www.fluentpython.com/extra/classic-coroutines/#yield_from_meaning_sec +RedirectTemp /21-17 https://github.com/fluentpython/example-code-2e/tree/master/20-executors/getflags +RedirectTemp /21-18 https://magicstack.github.io/asyncpg/current/ +RedirectTemp /21-19 https://magicstack.github.io/asyncpg/current/api/index.html#transactions +RedirectTemp /21-21 https://magicstack.github.io/asyncpg/current/api/index.html#transactions +RedirectTemp /21-22 https://magicstack.github.io/asyncpg/current/usage.html#connection-pools +RedirectTemp /21-23 https://gist.github.com/jboner/2841832 +RedirectTemp /21-24 https://en.wikipedia.org/wiki/Network-attached_storage +RedirectTemp /21-25 https://en.wikipedia.org/wiki/Semaphore_(programming) +RedirectTemp /21-26 https://en.wikipedia.org/wiki/Semaphore_(programming) +RedirectTemp /21-27 https://groups.google.com/forum/#!msg/python-tulip/PdAEtwpaJHs/7fqb-Qj2zJoJ +RedirectTemp /21-28 https://tritarget.org/#blog/2012/11/28/the-pyramid-of-doom-a-javascript-style-trap +RedirectTemp /21-29 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor +RedirectTemp /21-30 https://motor.readthedocs.io/en/stable/ +RedirectTemp /21-31 https://emptysqua.re/blog/response-to-asynchronous-python-and-databases/ +RedirectTemp /21-33 https://docs.python.org/3/library/asyncio-stream.html#tcp-echo-server-using-streams +RedirectTemp /21-35 https://en.wikipedia.org/wiki/Phaistos_Disc +RedirectTemp /21-36 https://en.wikipedia.org/wiki/Inverted_index +RedirectTemp /21-37 https://fastapi.tiangolo.com/ +RedirectTemp /21-38 https://swagger.io/specification/ +RedirectTemp /21-40 https://asgi.readthedocs.io/en/latest/implementations.html +RedirectTemp /21-41 https://pydantic-docs.helpmanual.io/ +RedirectTemp /21-42 https://doc.traefik.io/traefik/ +RedirectTemp /21-43 https://fastapi.tiangolo.com/project-generation/ +RedirectTemp /21-44 https://fastapi.tiangolo.com/tutorial/response-model/ +RedirectTemp /21-45 https://docs.python.org/3/library/asyncio-stream.html#asyncio.start_server +RedirectTemp /21-46 https://github.com/python/typeshed/issues/5535 +RedirectTemp /21-47 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.Server.serve_forever +RedirectTemp /21-48 https://docs.python.org/3/library/asyncio-stream.html#asyncio.StreamWriter.close +RedirectTemp /21-49 https://docs.python.org/3/library/asyncio-stream.html#streamwriter +RedirectTemp /21-50 https://docs.python.org/3/library/asyncio-stream.html +RedirectTemp /21-51 https://docs.python.org/3/library/asyncio-protocol.html +RedirectTemp /21-52 https://docs.python.org/3/library/asyncio-protocol.html#tcp-echo-server +RedirectTemp /21-53 https://github.com/aio-libs/aiopg +RedirectTemp /21-54 https://docs.python.org/3/whatsnew/3.8.html#asyncio +RedirectTemp /21-56 https://datatracker.ietf.org/doc/html/rfc6761 +RedirectTemp /21-57 https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager +RedirectTemp /21-59 https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager +RedirectTemp /21-61 https://docs.python.org/3/library/asyncio-task.html#asyncio.gather +RedirectTemp /21-62 https://curio.readthedocs.io/en/latest/index.html +RedirectTemp /21-63 https://curio.readthedocs.io/en/latest/reference.html#task-groups +RedirectTemp /21-64 https://en.wikipedia.org/wiki/Structured_concurrency +RedirectTemp /21-66 https://www.python.org/dev/peps/pep-0654/#motivation +RedirectTemp /21-67 https://curio.readthedocs.io/en/latest/reference.html#AWAIT +RedirectTemp /21-68 https://www.python-httpx.org/async/#curio +RedirectTemp /21-69 https://github.com/dabeaz/curio/tree/78bca8a6ad677ef51e1568ac7b3e51441ab49c42/examples +RedirectTemp /21-70 https://datatracker.ietf.org/doc/html/rfc8305 +RedirectTemp /21-71 https://trio.readthedocs.io/en/stable/ +RedirectTemp /21-72 https://www.youtube.com/watch?v=M-sc73Y-zQA +RedirectTemp /21-73 https://en.wikipedia.org/wiki/Technical_debt +RedirectTemp /21-74 https://www.youtube.com/watch?v=E-1Y4kSsAFc +RedirectTemp /21-76 https://github.com/dabeaz/curio +RedirectTemp /21-77 https://trio.readthedocs.io/en/stable/ +RedirectTemp /21-78 https://curio.readthedocs.io/en/latest/#curio-university +RedirectTemp /21-79 https://docs.python.org/3/library/asyncio.html +RedirectTemp /21-80 https://bugs.python.org/issue33649 +RedirectTemp /21-82 https://docs.python.org/3/library/asyncio-dev.html +RedirectTemp /21-83 https://www.youtube.com/watch?v=iG6fr81xHKA +RedirectTemp /21-84 https://www.youtube.com/watch?v=F19R_M4Nay4 +RedirectTemp /21-85 https://asherman.io/projects/unsync.html +RedirectTemp /21-86 https://pyladies.com/ +RedirectTemp /21-87 https://www.youtube.com/watch?v=sW76-pRkZk8 +RedirectTemp /21-88 https://www.youtube.com/watch?v=Xbl7XjFYsN4 +RedirectTemp /21-89 https://www.youtube.com/watch?v=02CLD-42VdI +RedirectTemp /21-90 https://micropython.org/ +RedirectTemp /21-91 https://docs.micropython.org/en/latest/library/uasyncio.html +RedirectTemp /21-92 https://www.encode.io/articles/python-async-frameworks-beyond-developer-tribalism +RedirectTemp /21-93 https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/ +RedirectTemp /21-94 https://github.com/MagicStack/uvloop +RedirectTemp /21-95 http://magic.io/blog/uvloop-blazing-fast-python-networking/ +RedirectTemp /21-96 https://github.com/MagicStack/httptools +RedirectTemp /21-97 https://docs.aiohttp.org/en/stable/ +RedirectTemp /21-98 https://github.com/wg/wrk +RedirectTemp /21-99 https://twistedmatrix.com/trac/ +############################################################ 22 +RedirectTemp /22-4 https://pypi.org/project/attrdict/ +RedirectTemp /22-5 https://pypi.org/project/addict/ +RedirectTemp /22-7 https://github.com/ActiveState/code/tree/master/recipes/Python/52308_simple_but_handy_collector_bunch_named_stuff +RedirectTemp /22-8 https://docs.python.org/3/library/types.html#types.SimpleNamespace +RedirectTemp /22-9 https://docs.python.org/3/library/argparse.html#argparse.Namespace +RedirectTemp /22-12 https://docs.python.org/3/library/functools.html#functools.cached_property +RedirectTemp /22-13 https://docs.python.org/3/library/functools.html#functools.cached_property +RedirectTemp /22-14 https://bugs.python.org/issue42781 +RedirectTemp /22-15 https://docs.python.org/3/howto/descriptor.html +RedirectTemp /22-16 https://docs.python.org/3/library/threading.html#rlock-objects +RedirectTemp /22-17 https://docs.python.org/3.10/library/functools.html#functools.cached_property +RedirectTemp /22-18 https://www.wsj.com/articles/SB10001424052970203914304576627102996831200 +RedirectTemp /22-19 https://www.youtube.com/watch?v=s35rVw1zskA&feature=youtu.be +RedirectTemp /22-20 https://docs.python.org/3/library/functions.html#dir +RedirectTemp /22-21 https://docs.python.org/3/library/functions.html#hasattr +RedirectTemp /22-22 https://docs.python.org/3.10/reference/datamodel.html#special-method-lookup +RedirectTemp /22-23 https://docs.python.org/3/library/functions.html +RedirectTemp /22-24 https://docs.python.org/3/reference/datamodel.html#customizing-attribute-access +RedirectTemp /22-25 https://docs.python.org/3/reference/datamodel.html#special-method-lookup +RedirectTemp /22-26 https://docs.python.org/3/library/stdtypes.html#special-attributes +RedirectTemp /22-27 http://wiki.c2.com/?WelcomeVisitors +RedirectTemp /22-28 http://wiki.c2.com/?UniformAccessPrinciple +RedirectTemp /22-29 https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html +RedirectTemp /22-30 http://www.pingo.io/docs/ +RedirectTemp /22-31 https://www.drdobbs.com/javas-new-considered-harmful/184405016 +RedirectTemp /22-32 https://www.python.org/dev/peps/pep-0008/#class-names +############################################################ 23 +RedirectTemp /23-2 http://www.aleax.it/goo_pydp.pdf +RedirectTemp /23-3 https://docs.python.org/3.10/reference/datamodel.html#implementing-descriptors +RedirectTemp /23-6 https://docs.python.org/3/howto/descriptor.html +RedirectTemp /23-7 https://docs.python.org/3/howto/ +RedirectTemp /23-8 http://www.aleax.it/Python/nylug05_om.pdf +RedirectTemp /23-9 https://www.youtube.com/watch?v=VOzvpHoYQoo +RedirectTemp /23-11 https://www.python.org/dev/peps/pep-0487/#trait-descriptors +RedirectTemp /23-12 https://dreamsongs.com/RiseOfWorseIsBetter.html +RedirectTemp /23-13 http://web.archive.org/web/20031002184114/www.amk.ca/python/writing/warts.html +RedirectTemp /23-14 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this +RedirectTemp /23-15 http://python-history.blogspot.com/2009/02/adding-support-for-user-defined-classes.html +############################################################ 24 +RedirectTemp /24-2 https://docs.python.org/3/library/stdtypes.html#special-attributes +RedirectTemp /24-3 https://docs.djangoproject.com/en/3.2/topics/db/models/#meta-options +RedirectTemp /24-4 https://www.python.org/dev/peps/pep-3155/ +RedirectTemp /24-7 https://en.wikipedia.org/wiki/Tony_Hoare#Apologies_and_retractions +RedirectTemp /24-8 https://go.dev/tour/basics/12 +RedirectTemp /24-9 https://bugs.python.org/issue42102 +RedirectTemp /24-11 https://www.python.org/dev/peps/pep-0557/#abstract +RedirectTemp /24-12 https://github.com/python/cpython/blob/3.9/Lib/dataclasses.py +RedirectTemp /24-13 https://docs.python.org/3/reference/datamodel.html#creating-the-class-object +RedirectTemp /24-15 https://mail.python.org/pipermail/python-list/2002-December/134521.html +RedirectTemp /24-16 https://www.oreilly.com/library/view/python-in-a/9781491913833/ +RedirectTemp /24-17 https://mail.python.org/pipermail/python-list/2002-July/162558.html +RedirectTemp /24-18 https://github.com/fluentpython/example-code/tree/master/21-class-metaprog/bulkfood +RedirectTemp /24-19 https://en.wikipedia.org/wiki/Principle_of_least_astonishment +RedirectTemp /24-21 https://en.wikipedia.org/wiki/Trait_(computer_programming) +RedirectTemp /24-22 https://en.wikipedia.org/wiki/Aspect-oriented_programming +RedirectTemp /24-23 https://dhh.dk/arc/000416.html +RedirectTemp /24-24 https://github.com/cjrh/autoslot +RedirectTemp /24-25 https://docs.python.org/3/reference/datamodel.html#customizing-class-creation +RedirectTemp /24-26 https://docs.python.org/3/library/functions.html#type +RedirectTemp /24-27 https://docs.python.org/3/library/stdtypes.html#special-attributes +RedirectTemp /24-28 https://docs.python.org/3/library/types.html +RedirectTemp /24-29 https://www.python.org/dev/peps/pep-3129/ +RedirectTemp /24-30 https://www.youtube.com/watch?v=cAGliEJV9_o +RedirectTemp /24-31 https://docs.python.org/3/library/functools.html#functools.total_ordering +RedirectTemp /24-33 https://www.oreilly.com/library/view/python-in-a/9781491913833/ +RedirectTemp /24-36 https://www.python.org/download/releases/2.2.3/descrintro/ +RedirectTemp /24-42 https://github.com/lihaoyi/macropy +RedirectTemp /24-43 https://people.eecs.berkeley.edu/~bh/ss-toc2.html diff --git a/links/README.md b/links/README.md new file mode 100644 index 0000000..6ec844c --- /dev/null +++ b/links/README.md @@ -0,0 +1,37 @@ +# Short links for URLs in the book + +## The problem: link rot + +_Fluent Python, Second Edition_ has more than 1000 links to external resources. +Inevitably, some of those links will rot as time passes. +But I can't change the URLs in the print book! + +## The solution: indirection + +I replaced almost all URLs in the book with shortened versions that go through the `fpy.li` site which I control. +The site has an `.htaccess` file with *temporary* redirects. + +When I find out a link is stale, I can thange the redirect in `.htaccess` to a new target, +so the link in the book is back in service via the updated redirect. + +## Help wanted + +Please report broken links as bugs in the [`FPY.LI.htaccess`](FPY.LI.htaccess) file. +Also, feel free to send pull requests with fixes to that file. +When I accept a PR, I will redeploy it to `fpy.li/.htaccess`. + +## Details + +Almost all URLs in the book are replaced with shortened versions like +[`http://fpy.li/1-3`](http://fpy.li/1-3)—for chapter 1, link #3. + +There are also custom short URLs like +[`https://fpy.li/code`](https://fpy.li/code) which redirects to the example code repository. +I used custom short URLs for URLs with 3 or more mentions, or links to PEPs. + +Exceptions: + +- URLs with `oreilly` in them are unchanged; +- `fluentpython.com` URL (with no path) is unchanged; + +The `FPY.LI.htaccess` is deployed at the root folder in `http://fpy.li`. diff --git a/links/custom.htaccess b/links/custom.htaccess new file mode 100644 index 0000000..52649db --- /dev/null +++ b/links/custom.htaccess @@ -0,0 +1,109 @@ +ErrorDocument 404 /404.html + +# main resources +RedirectTemp /code https://github.com/fluentpython/example-code-2e +RedirectTemp /home https://www.fluentpython.com/ + +# URLs mentioned at least three times +RedirectTemp /bisect https://www.fluentpython.com/extra/ordered-sequences-with-bisect/ +RedirectTemp /cardxvi https://www.python.org/dev/peps/pep-0484/#the-numeric-tower +RedirectTemp /collec https://docs.python.org/3/library/collections.html +RedirectTemp /dask https://dask.org/ +RedirectTemp /dtmodel https://docs.python.org/3/reference/datamodel.html +RedirectTemp /descr101 https://www.python.org/download/releases/2.2.3/descrintro/ +RedirectTemp /descrhow https://docs.python.org/3/howto/descriptor.html +RedirectTemp /doctest https://docs.python.org/3/library/doctest.html +RedirectTemp /effectpy https://effectivepython.com/ +RedirectTemp /fmtspec https://docs.python.org/3/library/string.html#formatspec +RedirectTemp /gunicorn https://gunicorn.org/ +RedirectTemp /hashint https://www.fluentpython.com/extra/internals-of-sets-and-dicts/ +RedirectTemp /hattingh https://www.oreilly.com/library/view/using-asyncio-in/9781492075325/ +RedirectTemp /httpx https://www.python-httpx.org/ +RedirectTemp /initvar https://docs.python.org/3/library/dataclasses.html#init-only-variables +RedirectTemp /mypy https://mypy.readthedocs.io/en/stable/ +RedirectTemp /norvigdp http://norvig.com/design-patterns/ +RedirectTemp /nsphere https://en.wikipedia.org/wiki/N-sphere +RedirectTemp /oldcoro https://www.fluentpython.com/extra/classic-coroutines/ +RedirectTemp /pandas https://pandas.pydata.org/ +RedirectTemp /pep218 https://www.python.org/dev/peps/pep-0218/ +RedirectTemp /pep227 https://www.python.org/dev/peps/pep-0227/ +RedirectTemp /pep255 https://www.python.org/dev/peps/pep-0255/ +RedirectTemp /pep342 https://www.python.org/dev/peps/pep-0342/ +RedirectTemp /pep343 https://www.python.org/dev/peps/pep-0343/ +RedirectTemp /pep357 https://www.python.org/dev/peps/pep-0357/ +RedirectTemp /pep362 https://www.python.org/dev/peps/pep-0362/ +RedirectTemp /pep371 https://www.python.org/dev/peps/pep-0371/ +RedirectTemp /pep380 https://www.python.org/dev/peps/pep-0380/ +RedirectTemp /pep393 https://www.python.org/dev/peps/pep-0393/ +RedirectTemp /pep412 https://www.python.org/dev/peps/pep-0412/ +RedirectTemp /pep442 https://www.python.org/dev/peps/pep-0442/ +RedirectTemp /pep443 https://www.python.org/dev/peps/pep-0443/ +RedirectTemp /pep448 https://www.python.org/dev/peps/pep-0448/ +RedirectTemp /pep455 https://www.python.org/dev/peps/pep-0455/ +RedirectTemp /pep456 https://www.python.org/dev/peps/pep-0456/ +RedirectTemp /pep461 https://www.python.org/dev/peps/pep-0461/ +RedirectTemp /pep465 https://www.python.org/dev/peps/pep-0465/ +RedirectTemp /pep467 https://www.python.org/dev/peps/pep-0467/ +RedirectTemp /pep482 https://www.python.org/dev/peps/pep-0482/ +RedirectTemp /pep483 https://www.python.org/dev/peps/pep-0483/ +RedirectTemp /pep484 https://www.python.org/dev/peps/pep-0484/ +RedirectTemp /pep487 https://www.python.org/dev/peps/pep-0487/ +RedirectTemp /pep492 https://www.python.org/dev/peps/pep-0492/ +RedirectTemp /pep519 https://www.python.org/dev/peps/pep-0519/ +RedirectTemp /pep525 https://www.python.org/dev/peps/pep-0525/ +RedirectTemp /pep526 https://www.python.org/dev/peps/pep-0526/ +RedirectTemp /pep528 https://www.python.org/dev/peps/pep-0528/ +RedirectTemp /pep529 https://www.python.org/dev/peps/pep-0529/ +RedirectTemp /pep530 https://www.python.org/dev/peps/pep-0530/ +RedirectTemp /pep544 https://www.python.org/dev/peps/pep-0544/ +RedirectTemp /pep554 https://www.python.org/dev/peps/pep-0554/ +RedirectTemp /pep557 https://www.python.org/dev/peps/pep-0557/ +RedirectTemp /pep560 https://www.python.org/dev/peps/pep-0560/ +RedirectTemp /pep561 https://www.python.org/dev/peps/pep-0561/ +RedirectTemp /pep563 https://www.python.org/dev/peps/pep-0563/ +RedirectTemp /pep570 https://www.python.org/dev/peps/pep-0570/ +RedirectTemp /pep572 https://www.python.org/dev/peps/pep-0572/ +RedirectTemp /pep584 https://www.python.org/dev/peps/pep-0584/ +RedirectTemp /pep585 https://www.python.org/dev/peps/pep-0585/ +RedirectTemp /pep586 https://www.python.org/dev/peps/pep-0586/ +RedirectTemp /pep589 https://www.python.org/dev/peps/pep-0589/ +RedirectTemp /pep591 https://www.python.org/dev/peps/pep-0591/ +RedirectTemp /pep593 https://www.python.org/dev/peps/pep-0593/ +RedirectTemp /pep604 https://www.python.org/dev/peps/pep-0604/ +RedirectTemp /pep612 https://www.python.org/dev/peps/pep-0612/ +RedirectTemp /pep613 https://www.python.org/dev/peps/pep-0613/ +RedirectTemp /pep616 https://www.python.org/dev/peps/pep-0616/ +RedirectTemp /pep617 https://www.python.org/dev/peps/pep-0617/ +RedirectTemp /pep618 https://www.python.org/dev/peps/pep-0618/ +RedirectTemp /pep634 https://www.python.org/dev/peps/pep-0634/ +RedirectTemp /pep635 https://www.python.org/dev/peps/pep-0635/ +RedirectTemp /pep636 https://www.python.org/dev/peps/pep-0636/ +RedirectTemp /pep638 https://www.python.org/dev/peps/pep-0638/ +RedirectTemp /pep645 https://www.python.org/dev/peps/pep-0645/ +RedirectTemp /pep646 https://www.python.org/dev/peps/pep-0646/ +RedirectTemp /pep647 https://www.python.org/dev/peps/pep-0647/ +RedirectTemp /pep649 https://www.python.org/dev/peps/pep-0649/ +RedirectTemp /pep654 https://www.python.org/dev/peps/pep-0654/ +RedirectTemp /pep655 https://www.python.org/dev/peps/pep-0655/ +RedirectTemp /pep661 https://www.python.org/dev/peps/pep-0661/ +RedirectTemp /pep3099 https://www.python.org/dev/peps/pep-3099/ +RedirectTemp /pep3102 https://www.python.org/dev/peps/pep-3102/ +RedirectTemp /pep3104 https://www.python.org/dev/peps/pep-3104/ +RedirectTemp /pep3106 https://www.python.org/dev/peps/pep-3106/ +RedirectTemp /pep3107 https://www.python.org/dev/peps/pep-3107/ +RedirectTemp /pep3115 https://www.python.org/dev/peps/pep-3115/ +RedirectTemp /pep3118 https://www.python.org/dev/peps/pep-3118/ +RedirectTemp /pep3119 https://www.python.org/dev/peps/pep-3119/ +RedirectTemp /pep3129 https://www.python.org/dev/peps/pep-3129/ +RedirectTemp /pep3132 https://www.python.org/dev/peps/pep-3132/ +RedirectTemp /pep3141 https://www.python.org/dev/peps/pep-3141/ +RedirectTemp /pep3148 https://www.python.org/dev/peps/pep-3148/ +RedirectTemp /pep3155 https://www.python.org/dev/peps/pep-3155/ +RedirectTemp /pep3333 https://www.python.org/dev/peps/pep-3333/ +RedirectTemp /pypydif https://doc.pypy.org/en/latest/cpython_differences.html#subclasses-of-built-in-types +RedirectTemp /shed4051 https://github.com/python/typeshed/issues/4051 +RedirectTemp /slatkin https://effectivepython.com/ +RedirectTemp /specattr https://docs.python.org/3/library/stdtypes.html#special-attributes +RedirectTemp /typecoro https://docs.python.org/3.10/library/typing.html#typing.Coroutine +RedirectTemp /typing https://docs.python.org/3/library/typing.html +RedirectTemp /weakref https://www.fluentpython.com/extra/weak-references/ From 82b4fe2163174bfee23527e68d418eed2ae4f46b Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Sat, 15 Jan 2022 14:04:45 -0300 Subject: [PATCH 34/66] added links and README.md --- links/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/links/README.md b/links/README.md index 6ec844c..09c808a 100644 --- a/links/README.md +++ b/links/README.md @@ -1,18 +1,18 @@ # Short links for URLs in the book -## The problem: link rot +## Problem: link rot _Fluent Python, Second Edition_ has more than 1000 links to external resources. Inevitably, some of those links will rot as time passes. -But I can't change the URLs in the print book! +But I can't change the URLs in the print book... -## The solution: indirection +## Solution: indirection I replaced almost all URLs in the book with shortened versions that go through the `fpy.li` site which I control. The site has an `.htaccess` file with *temporary* redirects. When I find out a link is stale, I can thange the redirect in `.htaccess` to a new target, -so the link in the book is back in service via the updated redirect. +so the link in the book is back in service through the updated redirect. ## Help wanted From 646427f393a8d3463d8dc95f8eb0bc1744d2d002 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Sun, 16 Jan 2022 19:05:00 -0300 Subject: [PATCH 35/66] updated .htaccess --- links/FPY.LI.htaccess | 1567 ++++++++++++++++++++++------------------- links/custom.htaccess | 18 +- 2 files changed, 838 insertions(+), 747 deletions(-) diff --git a/links/FPY.LI.htaccess b/links/FPY.LI.htaccess index 579d7e4..9f960f1 100644 --- a/links/FPY.LI.htaccess +++ b/links/FPY.LI.htaccess @@ -25,6 +25,17 @@ RedirectTemp /norvigdp http://norvig.com/design-patterns/ RedirectTemp /nsphere https://en.wikipedia.org/wiki/N-sphere RedirectTemp /oldcoro https://www.fluentpython.com/extra/classic-coroutines/ RedirectTemp /pandas https://pandas.pydata.org/ +RedirectTemp /pycook3 https://www.oreilly.com/library/view/python-cookbook-3rd/9781449357337/ +RedirectTemp /pynut3 https://www.oreilly.com/library/view/python-in-a/9781491913833/ +RedirectTemp /pypydif https://doc.pypy.org/en/latest/cpython_differences.html#subclasses-of-built-in-types +RedirectTemp /shed4051 https://github.com/python/typeshed/issues/4051 +RedirectTemp /slatkin https://effectivepython.com/ +RedirectTemp /specattr https://docs.python.org/3/library/stdtypes.html#special-attributes +RedirectTemp /typecoro https://docs.python.org/3.10/library/typing.html#typing.Coroutine +RedirectTemp /typing https://docs.python.org/3/library/typing.html +RedirectTemp /weakref https://www.fluentpython.com/extra/weak-references/ + +# Python Enhancement Proposals RedirectTemp /pep218 https://www.python.org/dev/peps/pep-0218/ RedirectTemp /pep227 https://www.python.org/dev/peps/pep-0227/ RedirectTemp /pep255 https://www.python.org/dev/peps/pep-0255/ @@ -100,13 +111,6 @@ RedirectTemp /pep3141 https://www.python.org/dev/peps/pep-3141/ RedirectTemp /pep3148 https://www.python.org/dev/peps/pep-3148/ RedirectTemp /pep3155 https://www.python.org/dev/peps/pep-3155/ RedirectTemp /pep3333 https://www.python.org/dev/peps/pep-3333/ -RedirectTemp /pypydif https://doc.pypy.org/en/latest/cpython_differences.html#subclasses-of-built-in-types -RedirectTemp /shed4051 https://github.com/python/typeshed/issues/4051 -RedirectTemp /slatkin https://effectivepython.com/ -RedirectTemp /specattr https://docs.python.org/3/library/stdtypes.html#special-attributes -RedirectTemp /typecoro https://docs.python.org/3.10/library/typing.html#typing.Coroutine -RedirectTemp /typing https://docs.python.org/3/library/typing.html -RedirectTemp /weakref https://www.fluentpython.com/extra/weak-references/ # Remaining URLs by chapter @@ -114,18 +118,14 @@ RedirectTemp /weakref https://www.fluentpython.com/extra/weak-references/ RedirectTemp /p-1 https://mail.python.org/pipermail/python-list/2002-December/134521.html RedirectTemp /p-2 https://docs.python.org/3.10/tutorial/ RedirectTemp /p-3 https://docs.python.org/3/tutorial/ -RedirectTemp /p-9 https://www.oreilly.com/library/view/fluent-python-2nd/9781492056348/ -RedirectTemp /p-10 https://www.oreilly.com/online-learning/try-now.html -RedirectTemp /p-13 https://www.oreilly.com/library/view/fluent-python-2nd/9781492056348/ -RedirectTemp /p-14 https://www.oreilly.com/ -RedirectTemp /p-15 https://www.facebook.com/OReilly/ -RedirectTemp /p-16 https://twitter.com/oreillymedia -RedirectTemp /p-17 https://www.youtube.com/oreillymedia -RedirectTemp /p-18 https://stackoverflow.com/users/95810/alex-martelli -RedirectTemp /p-19 https://pythonpro.com.br -RedirectTemp /p-20 https://groups.google.com/g/python-brasil -RedirectTemp /p-21 https://www.coffeelab.com.br/ -RedirectTemp /p-22 https://garoa.net.br/wiki/P%C3%A1gina_principal +RedirectTemp /p-4 https://www.oreilly.com/library/view/fluent-python-2nd/9781492056348/ +RedirectTemp /p-5 https://www.oreilly.com/online-learning/try-now.html +RedirectTemp /p-6 https://www.oreilly.com/library/view/fluent-python-2nd/9781492056348/ +RedirectTemp /p-7 https://stackoverflow.com/users/95810/alex-martelli +RedirectTemp /p-8 https://pythonpro.com.br +RedirectTemp /p-9 https://groups.google.com/g/python-brasil +RedirectTemp /p-10 https://www.coffeelab.com.br/ +RedirectTemp /p-11 https://garoa.net.br/wiki/P%C3%A1gina_principal ############################################################ a RedirectTemp /a-1 https://groups.google.com/forum/#!topic/python-tulip/Y4bhLNbKs74 RedirectTemp /a-2 https://docs.python.org/3/library/asyncio-eventloop.html#executor @@ -144,133 +144,145 @@ RedirectTemp /a-14 https://docs.mongodb.com/manual/about/#about-the-documentatio RedirectTemp /a-15 https://blog.startifact.com/posts/older/what-is-pythonic.html RedirectTemp /a-16 https://mail.python.org/pipermail/tutor/2003-October/thread.html#25930 RedirectTemp /a-17 https://mail.python.org/pipermail/python-list/2003-April/192027.html -RedirectTemp /a-19 https://www.python.org/doc/essays/ +RedirectTemp /a-18 https://www.python.org/doc/essays/ ############################################################ 01 RedirectTemp /1-1 http://hugunin.net/story_of_jython.html -RedirectTemp /1-3 https://docs.python.org/2/library/string.html#format-string-syntax -RedirectTemp /1-4 https://stackoverflow.com/questions/1436703/what-is-the-difference-between-str-and-repr -RedirectTemp /1-5 https://docs.python.org/3/library/stdtypes.html#truth -RedirectTemp /1-6 https://docs.python.org/3/tutorial/controlflow.html#unpacking-argument-lists +RedirectTemp /1-2 https://www.oreilly.com/library/view/jython-essentials/9781449397364/ +RedirectTemp /1-3 https://docs.python.org/3/reference/lexical_analysis.html#reserved-classes-of-identifiers +RedirectTemp /1-4 https://docs.python.org/2/library/string.html#format-string-syntax +RedirectTemp /1-5 https://stackoverflow.com/questions/1436703/what-is-the-difference-between-str-and-repr +RedirectTemp /1-6 https://docs.python.org/3/library/stdtypes.html#truth +RedirectTemp /1-7 https://docs.python.org/3/tutorial/controlflow.html#unpacking-argument-lists RedirectTemp /1-8 https://www.python.org/doc/humor/#the-zen-of-python -RedirectTemp /1-10 https://stackoverflow.com/users/95810/alex-martelli -RedirectTemp /1-11 https://en.wikipedia.org/wiki/Object_model -RedirectTemp /1-13 https://www.dourish.com/goodies/jargon.html -RedirectTemp /1-14 https://zopeinterface.readthedocs.io/en/latest/ -RedirectTemp /1-15 https://plone.org/ +RedirectTemp /1-9 https://stackoverflow.com/users/95810/alex-martelli +RedirectTemp /1-10 https://en.wikipedia.org/wiki/Object_model +RedirectTemp /1-11 https://www.dourish.com/goodies/jargon.html +RedirectTemp /1-12 https://zopeinterface.readthedocs.io/en/latest/ +RedirectTemp /1-13 https://plone.org/ ############################################################ 02 -RedirectTemp /2-4 https://github.com/fluentpython/example-code-2e/blob/master/02-array-seq/listcomp_speed.py -RedirectTemp /2-6 https://www.python.org/dev/peps/pep-3132/ -RedirectTemp /2-8 https://docs.python.org/3/whatsnew/3.5.html#pep-448-additional-unpacking-generalizations -RedirectTemp /2-9 https://docs.python.org/3/whatsnew/3.5.html#pep-448-additional-unpacking-generalizations -RedirectTemp /2-11 https://docs.python.org/3.10/whatsnew/3.10.html#pep-634-structural-pattern-matching -RedirectTemp /2-12 https://docs.python.org/3.10/whatsnew/3.10.html -RedirectTemp /2-13 https://en.wikipedia.org/wiki/Switch_statement#Fallthrough -RedirectTemp /2-14 https://en.wikipedia.org/wiki/Dangling_else -RedirectTemp /2-15 https://github.com/gvanrossum/patma/blob/3ece6444ef70122876fd9f0099eb9490a2d630df/EXAMPLES.md#case-6-a-very-deep-iterable-and-type-match-with-extraction -RedirectTemp /2-16 https://github.com/fluentpython/lispy/blob/main/original/norvig/lis.py -RedirectTemp /2-17 https://norvig.com/lispy.html -RedirectTemp /2-18 https://numpy.org/doc/stable/user/quickstart.html#indexing-slicing-and-iterating -RedirectTemp /2-19 https://pythontutor.com/ -RedirectTemp /2-20 https://en.wikipedia.org/wiki/Fluent_interface -RedirectTemp /2-23 https://docs.python.org/3/library/bisect.html#bisect.insort -RedirectTemp /2-24 https://stackoverflow.com/questions/4845418/when-should-a-memoryview-be-used/ -RedirectTemp /2-26 https://www.fluentpython.com/extra/parsing-binary-struct/ -RedirectTemp /2-27 http://www.netlib.org -RedirectTemp /2-28 https://pandas.pydata.org/ -RedirectTemp /2-29 https://scikit-learn.org/stable/ -RedirectTemp /2-32 https://docs.python.org/3/howto/sorting.html -RedirectTemp /2-33 https://www.python.org/dev/peps/pep-3132/ -RedirectTemp /2-34 https://bugs.python.org/issue2292 -RedirectTemp /2-36 https://docs.python.org/3.10/whatsnew/3.10.html#pep-634-structural-pattern-matching -RedirectTemp /2-37 https://docs.python.org/3.10/whatsnew/3.10.html -RedirectTemp /2-39 https://www.python.org/dev/peps/pep-0636/#appendix-a-quick-intro -RedirectTemp /2-41 https://eli.thegreenplace.net/2011/11/28/less-copies-in-python-with-the-buffer-protocol-and-memoryviews/ -RedirectTemp /2-42 https://jakevdp.github.io/PythonDataScienceHandbook/ -RedirectTemp /2-43 https://www.labri.fr/perso/nrougier/from-python-to-numpy/ -RedirectTemp /2-44 https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html -RedirectTemp /2-45 http://www.fonts101.com/fonts/view/Uncategorized/34398/Dijkstra -RedirectTemp /2-46 https://docs.python.org/3/reference/datamodel.html#objects-values-and-types -RedirectTemp /2-47 https://en.wikipedia.org/wiki/Timsort -RedirectTemp /2-48 http://www.groklaw.net/pdf3/OraGoogle-1202.pdf -RedirectTemp /2-49 https://www.python.org/doc/humor/#id9 +RedirectTemp /2-1 https://github.com/fluentpython/example-code-2e/blob/master/02-array-seq/listcomp_speed.py +RedirectTemp /2-2 https://www.python.org/dev/peps/pep-3132/ +RedirectTemp /2-3 https://stackoverflow.com/questions/68630/are-tuples-more-efficient-than-lists-in-python/22140115#22140115 +RedirectTemp /2-4 https://docs.python.org/3/whatsnew/3.5.html#pep-448-additional-unpacking-generalizations +RedirectTemp /2-5 https://docs.python.org/3/whatsnew/3.5.html#pep-448-additional-unpacking-generalizations +RedirectTemp /2-6 https://docs.python.org/3.10/whatsnew/3.10.html#pep-634-structural-pattern-matching +RedirectTemp /2-7 https://docs.python.org/3.10/whatsnew/3.10.html +RedirectTemp /2-8 https://en.wikipedia.org/wiki/Switch_statement#Fallthrough +RedirectTemp /2-9 https://en.wikipedia.org/wiki/Dangling_else +RedirectTemp /2-10 https://github.com/gvanrossum/patma/blob/3ece6444ef70122876fd9f0099eb9490a2d630df/EXAMPLES.md#case-6-a-very-deep-iterable-and-type-match-with-extraction +RedirectTemp /2-11 https://github.com/fluentpython/lispy/blob/main/original/norvig/lis.py +RedirectTemp /2-12 https://norvig.com/lispy.html +RedirectTemp /2-13 https://numpy.org/doc/stable/user/quickstart.html#indexing-slicing-and-iterating +RedirectTemp /2-14 https://pythontutor.com/ +RedirectTemp /2-15 https://en.wikipedia.org/wiki/Fluent_interface +RedirectTemp /2-16 https://docs.python.org/3/library/bisect.html#bisect.insort +RedirectTemp /2-17 https://stackoverflow.com/questions/4845418/when-should-a-memoryview-be-used/ +RedirectTemp /2-18 https://www.fluentpython.com/extra/parsing-binary-struct/ +RedirectTemp /2-19 http://www.netlib.org +RedirectTemp /2-20 https://pandas.pydata.org/ +RedirectTemp /2-21 https://scikit-learn.org/stable/ +RedirectTemp /2-22 https://docs.python.org/3/howto/sorting.html +RedirectTemp /2-23 https://www.python.org/dev/peps/pep-3132/ +RedirectTemp /2-24 https://bugs.python.org/issue2292 +RedirectTemp /2-25 https://docs.python.org/3.10/whatsnew/3.10.html#pep-634-structural-pattern-matching +RedirectTemp /2-26 https://docs.python.org/3.10/whatsnew/3.10.html +RedirectTemp /2-27 https://www.python.org/dev/peps/pep-0636/#appendix-a-quick-intro +RedirectTemp /2-28 https://eli.thegreenplace.net/2011/11/28/less-copies-in-python-with-the-buffer-protocol-and-memoryviews/ +RedirectTemp /2-29 https://jakevdp.github.io/PythonDataScienceHandbook/ +RedirectTemp /2-30 https://www.oreilly.com/library/view/python-for-data/9781491957653/ +RedirectTemp /2-31 https://www.labri.fr/perso/nrougier/from-python-to-numpy/ +RedirectTemp /2-32 https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html +RedirectTemp /2-33 http://www.fonts101.com/fonts/view/Uncategorized/34398/Dijkstra +RedirectTemp /2-34 https://docs.python.org/3/reference/datamodel.html#objects-values-and-types +RedirectTemp /2-35 https://en.wikipedia.org/wiki/Timsort +RedirectTemp /2-36 http://www.groklaw.net/pdf3/OraGoogle-1202.pdf +RedirectTemp /2-37 https://www.python.org/doc/humor/#id9 ############################################################ 03 -RedirectTemp /3-5 https://www.python.org/dev/peps/pep-0584/#motivation -RedirectTemp /3-7 https://docs.python.org/3.10/c-api/typeobj.html#Py_TPFLAGS_MAPPING -RedirectTemp /3-8 https://docs.python.org/3/glossary.html#term-hashable -RedirectTemp /3-9 https://docs.python.org/3/glossary.html#term-hashable -RedirectTemp /3-11 http://www.aleax.it/Python/accu04_Relearn_Python_alex.pdf -RedirectTemp /3-12 https://github.com/pingo-io/pingo-py -RedirectTemp /3-13 https://github.com/fluentpython/example-code-2e/blob/master/03-dict-set/missing.py -RedirectTemp /3-14 https://docs.python.org/3/library/collections.html#collections.ChainMap -RedirectTemp /3-15 https://docs.python.org/3/library/collections.html#collections.Counter -RedirectTemp /3-16 https://docs.python.org/3/library/shelve.html -RedirectTemp /3-17 https://docs.python.org/3/library/dbm.html -RedirectTemp /3-18 https://docs.python.org/3/library/pickle.html -RedirectTemp /3-19 https://nedbatchelder.com/blog/202006/pickles_nine_flaws.html -RedirectTemp /3-20 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Lib/_collections_abc.py#L813 -RedirectTemp /3-22 https://mail.python.org/pipermail/python-dev/2015-May/140003.html -RedirectTemp /3-23 https://bugs.python.org/issue18986 -RedirectTemp /3-24 https://github.com/fluentpython/example-code-2e/blob/master/03-dict-set/transformdict.py -RedirectTemp /3-33 http://gandenberger.org/2018/03/10/ordered-dicts-vs-ordereddict/ -RedirectTemp /3-35 https://www.pypy.org/ -RedirectTemp /3-36 https://morepypy.blogspot.com/2015/01/faster-more-memory-efficient-and-more.html -RedirectTemp /3-37 https://www.npopov.com/2014/12/22/PHPs-new-hashtable-implementation.html -RedirectTemp /3-38 https://www.youtube.com/watch?v=66P5FMkWoVU -RedirectTemp /3-39 https://pyvideo.org/video/276/the-mighty-dictionary-55/ -RedirectTemp /3-40 https://www.youtube.com/watch?v=p33CVV29OG8 -RedirectTemp /3-41 https://docs.python.org/3/whatsnew/3.6.html#new-dict-implementation -RedirectTemp /3-43 https://www.youtube.com/watch?v=tGAngdU_8D8 -RedirectTemp /3-44 https://speakerdeck.com/ramalho/python-set-practice-at-pycon -RedirectTemp /3-45 https://github.com/standupdev/uintset -RedirectTemp /3-46 http://www.json.org/fatfree.html -RedirectTemp /3-47 https://twitter.com/mitsuhiko/status/1229385843585974272 +RedirectTemp /3-1 https://www.python.org/dev/peps/pep-0584/#motivation +RedirectTemp /3-2 https://docs.python.org/3.10/c-api/typeobj.html#Py_TPFLAGS_MAPPING +RedirectTemp /3-3 https://docs.python.org/3/glossary.html#term-hashable +RedirectTemp /3-4 https://docs.python.org/3/glossary.html#term-hashable +RedirectTemp /3-5 http://www.aleax.it/Python/accu04_Relearn_Python_alex.pdf +RedirectTemp /3-6 https://github.com/pingo-io/pingo-py +RedirectTemp /3-7 https://github.com/fluentpython/example-code-2e/blob/master/03-dict-set/missing.py +RedirectTemp /3-8 https://docs.python.org/3/library/collections.html#collections.ChainMap +RedirectTemp /3-9 https://docs.python.org/3/library/collections.html#collections.Counter +RedirectTemp /3-10 https://docs.python.org/3/library/shelve.html +RedirectTemp /3-11 https://docs.python.org/3/library/dbm.html +RedirectTemp /3-12 https://docs.python.org/3/library/pickle.html +RedirectTemp /3-13 https://nedbatchelder.com/blog/202006/pickles_nine_flaws.html +RedirectTemp /3-14 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Lib/_collections_abc.py#L813 +RedirectTemp /3-15 https://mail.python.org/pipermail/python-dev/2015-May/140003.html +RedirectTemp /3-16 https://bugs.python.org/issue18986 +RedirectTemp /3-17 https://github.com/fluentpython/example-code-2e/blob/master/03-dict-set/transformdict.py +RedirectTemp /3-18 http://gandenberger.org/2018/03/10/ordered-dicts-vs-ordereddict/ +RedirectTemp /3-19 https://www.pypy.org/ +RedirectTemp /3-20 https://morepypy.blogspot.com/2015/01/faster-more-memory-efficient-and-more.html +RedirectTemp /3-21 https://www.npopov.com/2014/12/22/PHPs-new-hashtable-implementation.html +RedirectTemp /3-22 https://www.youtube.com/watch?v=66P5FMkWoVU +RedirectTemp /3-23 https://pyvideo.org/video/276/the-mighty-dictionary-55/ +RedirectTemp /3-24 https://www.youtube.com/watch?v=p33CVV29OG8 +RedirectTemp /3-25 https://docs.python.org/3/whatsnew/3.6.html#new-dict-implementation +RedirectTemp /3-26 https://github.com/python/cpython/blob/cf7eaa4617295747ee5646c4e2b7e7a16d7c64ab/Objects/dictobject.c +RedirectTemp /3-27 https://github.com/python/cpython/blob/cf7eaa4617295747ee5646c4e2b7e7a16d7c64ab/Objects/dictnotes.txt +RedirectTemp /3-28 https://www.youtube.com/watch?v=tGAngdU_8D8 +RedirectTemp /3-29 https://speakerdeck.com/ramalho/python-set-practice-at-pycon +RedirectTemp /3-30 https://github.com/standupdev/uintset +RedirectTemp /3-31 https://spectrum.ieee.org/hans-peter-luhn-and-the-birth-of-the-hashing-algorithm +RedirectTemp /3-32 http://www.json.org/fatfree.html +RedirectTemp /3-33 https://twitter.com/mitsuhiko/status/1229385843585974272 ############################################################ 04 RedirectTemp /4-1 https://www.slideshare.net/fischertrav/character-encoding-unicode-how-to-with-dignity-33352863 RedirectTemp /4-2 https://pyvideo.org/video/2625/character-encoding-and-unicode-in-python/ RedirectTemp /4-3 https://www.fluentpython.com/extra/parsing-binary-struct/ -RedirectTemp /4-5 https://www.fluentpython.com/extra/multi-character-emojis/ -RedirectTemp /4-8 https://w3techs.com/technologies/overview/character_encoding -RedirectTemp /4-9 https://docs.python.org/3/library/codecs.html#codecs.register_error -RedirectTemp /4-10 https://docs.python.org/3/library/stdtypes.html#str.isascii -RedirectTemp /4-11 https://pypi.org/project/chardet/ -RedirectTemp /4-12 https://docs.python.org/3/library/codecs.html#encodings-and-unicode -RedirectTemp /4-13 https://nedbatchelder.com/text/unipain/unipain.html -RedirectTemp /4-16 https://docs.python.org/3/using/cmdline.html#envvar-PYTHONIOENCODING -RedirectTemp /4-17 https://docs.python.org/3/using/cmdline.html#envvar-PYTHONLEGACYWINDOWSSTDIO -RedirectTemp /4-18 https://docs.python.org/3/library/locale.html#locale.getpreferredencoding -RedirectTemp /4-19 http://www.w3.org/TR/charmod-norm/ -RedirectTemp /4-20 https://docs.python.org/3/library/locale.html?highlight=strxfrm#locale.strxfrm -RedirectTemp /4-21 https://github.com/jtauber/pyuca -RedirectTemp /4-22 http://www.unicode.org/Public/UCA/6.3.0/allkeys.txt -RedirectTemp /4-23 https://pypi.org/project/PyICU/ -RedirectTemp /4-24 https://docs.python.org/3.10/library/stdtypes.html#str.isalpha -RedirectTemp /4-25 https://en.wikipedia.org/wiki/Unicode_character_property#General_Category -RedirectTemp /4-26 https://en.wikipedia.org/wiki/Unicode_character_property -RedirectTemp /4-27 https://github.com/microsoft/terminal -RedirectTemp /4-28 https://docs.python.org/3/library/unicodedata.html -RedirectTemp /4-29 https://docs.python.org/3/reference/lexical_analysis.html#string-literal-concatenation -RedirectTemp /4-30 https://docs.python.org/3/library/re.html -RedirectTemp /4-31 https://nedbatchelder.com/text/unipain.html -RedirectTemp /4-32 https://www.slideshare.net/fischertrav/character-encoding-unicode-how-to-with-dignity-33352863 -RedirectTemp /4-33 https://pyvideo.org/video/2625/character-encoding-and-unicode-in-python/ -RedirectTemp /4-34 https://regebro.wordpress.com/2011/03/23/unconfusing-unicode-what-is-unicode/ -RedirectTemp /4-35 https://docs.python.org/3/howto/unicode.html -RedirectTemp /4-36 https://diveintopython3.net/strings.html -RedirectTemp /4-37 https://diveintopython3.net/ -RedirectTemp /4-38 https://finderiko.com/python-book -RedirectTemp /4-39 https://docs.python.org/3.0/whatsnew/3.0.html#text-vs-data-instead-of-unicode-vs-8-bit -RedirectTemp /4-40 https://lucumr.pocoo.org/2013/7/2/the-updated-guide-to-unicode/ -RedirectTemp /4-41 http://python-notes.curiousefficiency.org/en/latest/python3/binary_protocols.html -RedirectTemp /4-42 http://python-notes.curiousefficiency.org/en/latest/python3/text_file_processing.html -RedirectTemp /4-43 https://docs.python.org/3/library/codecs.html#standard-encodings -RedirectTemp /4-44 https://www.informit.com/store/unicode-demystified-a-practical-programmers-guide-to-9780201700527 -RedirectTemp /4-45 https://unicodebook.readthedocs.io/index.html -RedirectTemp /4-46 https://www.w3.org/International/wiki/Case_folding -RedirectTemp /4-47 http://www.w3.org/TR/charmod-norm/ -RedirectTemp /4-48 http://unicode.org/reports/tr15/ -RedirectTemp /4-49 http://www.unicode.org/faq/normalization.html -RedirectTemp /4-50 http://www.unicode.org/ -RedirectTemp /4-51 http://www.macchiato.com/unicode/nfc-faq +RedirectTemp /4-4 https://www.fluentpython.com/extra/multi-character-emojis/ +RedirectTemp /4-5 https://w3techs.com/technologies/overview/character_encoding +RedirectTemp /4-6 https://docs.python.org/3/library/codecs.html#codecs.register_error +RedirectTemp /4-7 https://docs.python.org/3/library/stdtypes.html#str.isascii +RedirectTemp /4-8 https://pypi.org/project/chardet/ +RedirectTemp /4-9 https://docs.python.org/3/library/codecs.html#encodings-and-unicode +RedirectTemp /4-10 https://nedbatchelder.com/text/unipain/unipain.html +RedirectTemp /4-11 https://devblogs.microsoft.com/commandline/windows-command-line-unicode-and-utf-8-output-text-buffer/ +RedirectTemp /4-12 https://docs.python.org/3/using/cmdline.html#envvar-PYTHONIOENCODING +RedirectTemp /4-13 https://docs.python.org/3/using/cmdline.html#envvar-PYTHONLEGACYWINDOWSSTDIO +RedirectTemp /4-14 https://docs.python.org/3/library/locale.html#locale.getpreferredencoding +RedirectTemp /4-15 http://www.w3.org/TR/charmod-norm/ +RedirectTemp /4-16 https://docs.python.org/3/library/locale.html?highlight=strxfrm#locale.strxfrm +RedirectTemp /4-17 https://pypi.org/project/pyuca/ +RedirectTemp /4-18 https://github.com/jtauber/pyuca +RedirectTemp /4-19 http://www.unicode.org/Public/UCA/6.3.0/allkeys.txt +RedirectTemp /4-20 https://pypi.org/project/PyICU/ +RedirectTemp /4-21 https://docs.python.org/3.10/library/stdtypes.html#str.isalpha +RedirectTemp /4-22 https://en.wikipedia.org/wiki/Unicode_character_property#General_Category +RedirectTemp /4-23 https://en.wikipedia.org/wiki/Unicode_character_property +RedirectTemp /4-24 https://github.com/microsoft/terminal +RedirectTemp /4-25 https://docs.python.org/3/library/unicodedata.html +RedirectTemp /4-26 https://docs.python.org/3/reference/lexical_analysis.html#string-literal-concatenation +RedirectTemp /4-27 https://docs.python.org/3/library/re.html +RedirectTemp /4-28 https://nedbatchelder.com/text/unipain.html +RedirectTemp /4-29 https://www.slideshare.net/fischertrav/character-encoding-unicode-how-to-with-dignity-33352863 +RedirectTemp /4-30 https://pyvideo.org/video/2625/character-encoding-and-unicode-in-python/ +RedirectTemp /4-31 https://regebro.wordpress.com/2011/03/23/unconfusing-unicode-what-is-unicode/ +RedirectTemp /4-32 https://docs.python.org/3/howto/unicode.html +RedirectTemp /4-33 https://diveintopython3.net/strings.html +RedirectTemp /4-34 https://diveintopython3.net/ +RedirectTemp /4-35 https://finderiko.com/python-book +RedirectTemp /4-36 https://docs.python.org/3.0/whatsnew/3.0.html#text-vs-data-instead-of-unicode-vs-8-bit +RedirectTemp /4-37 https://lucumr.pocoo.org/2013/7/2/the-updated-guide-to-unicode/ +RedirectTemp /4-38 http://python-notes.curiousefficiency.org/en/latest/python3/binary_protocols.html +RedirectTemp /4-39 http://python-notes.curiousefficiency.org/en/latest/python3/text_file_processing.html +RedirectTemp /4-40 https://docs.python.org/3/library/codecs.html#standard-encodings +RedirectTemp /4-41 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Tools/unicode/listcodecs.py +RedirectTemp /4-42 https://www.oreilly.com/library/view/unicode-explained/059610121X/ +RedirectTemp /4-43 https://www.informit.com/store/unicode-demystified-a-practical-programmers-guide-to-9780201700527 +RedirectTemp /4-44 https://unicodebook.readthedocs.io/index.html +RedirectTemp /4-45 https://www.w3.org/International/wiki/Case_folding +RedirectTemp /4-46 http://www.w3.org/TR/charmod-norm/ +RedirectTemp /4-47 http://unicode.org/reports/tr15/ +RedirectTemp /4-48 http://www.unicode.org/faq/normalization.html +RedirectTemp /4-49 http://www.unicode.org/ +RedirectTemp /4-50 http://www.macchiato.com/unicode/nfc-faq +RedirectTemp /4-51 https://stories.moma.org/the-original-emoji-set-has-been-added-to-the-museum-of-modern-arts-collection-c6060e141f61?gi=c403f5a840a5 RedirectTemp /4-52 https://emojipedia.org/ RedirectTemp /4-53 https://blog.emojipedia.org/correcting-the-record-on-the-first-emoji-set/ RedirectTemp /4-54 http://emojitracker.com/ @@ -279,397 +291,433 @@ RedirectTemp /4-56 http://www.methods.co.nz/asciidoc/ RedirectTemp /4-57 https://atlas.oreilly.com/ ############################################################ 05 RedirectTemp /5-1 https://docs.python.org/3/library/typing.html#typing.TypedDict -RedirectTemp /5-4 https://docs.python.org/3.10/library/inspect.html#inspect.get_annotations -RedirectTemp /5-5 https://docs.python.org/3/library/typing.html#typing.get_type_hints -RedirectTemp /5-6 https://docs.python.org/3.8/library/collections.html#collections.somenamedtuple._asdict -RedirectTemp /5-8 https://www.jetbrains.com/pycharm/ -RedirectTemp /5-10 https://www.python.org/dev/peps/pep-0484/#acceptable-type-hints -RedirectTemp /5-11 https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass -RedirectTemp /5-13 https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass -RedirectTemp /5-14 https://docs.python.org/3/library/dataclasses.html -RedirectTemp /5-15 https://docs.python.org/3/library/dataclasses.html#inheritance -RedirectTemp /5-16 https://www.python.org/dev/peps/pep-0526/#class-and-instance-variable-annotations -RedirectTemp /5-22 https://dublincore.org/specifications/dublin-core/ -RedirectTemp /5-23 https://en.wikipedia.org/wiki/Dublin_Core -RedirectTemp /5-24 https://martinfowler.com/bliki/CodeSmell.html -RedirectTemp /5-25 https://martinfowler.com/books/refactoring.html -RedirectTemp /5-26 https://www.python.org/dev/peps/pep-0634/#class-patterns -RedirectTemp /5-30 https://docs.python.org/3/library/dataclasses.html -RedirectTemp /5-32 https://www.python.org/dev/peps/pep-0557/#id47 -RedirectTemp /5-33 https://www.python.org/dev/peps/pep-0557/#id48 -RedirectTemp /5-34 https://www.python.org/dev/peps/pep-0557/#id33 -RedirectTemp /5-35 https://realpython.com -RedirectTemp /5-36 https://realpython.com/python-data-classes/ -RedirectTemp /5-37 https://www.youtube.com/watch?v=T-TwcmT6Rcw -RedirectTemp /5-38 https://www.attrs.org/en/stable/ -RedirectTemp /5-39 https://glyph.twistedmatrix.com/2016/08/attrs.html -RedirectTemp /5-40 https://www.attrs.org/en/stable/why.html -RedirectTemp /5-41 https://github.com/dabeaz/cluegen -RedirectTemp /5-42 https://refactoring.guru/ -RedirectTemp /5-43 https://refactoring.guru/smells/data-class -RedirectTemp /5-44 https://web.archive.org/web/20190204130328/http://catb.org/esr/jargon/html/G/Guido.html -RedirectTemp /5-45 https://web.archive.org/web/20190211161610/http://catb.org/esr/jargon/html/index.html -RedirectTemp /5-47 https://www.attrs.org/en/stable/ +RedirectTemp /5-2 https://docs.python.org/3.10/library/inspect.html#inspect.get_annotations +RedirectTemp /5-3 https://docs.python.org/3/library/typing.html#typing.get_type_hints +RedirectTemp /5-4 https://docs.python.org/3.8/library/collections.html#collections.somenamedtuple._asdict +RedirectTemp /5-5 https://www.jetbrains.com/pycharm/ +RedirectTemp /5-6 https://www.python.org/dev/peps/pep-0484/#acceptable-type-hints +RedirectTemp /5-7 https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass +RedirectTemp /5-8 https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass +RedirectTemp /5-9 https://docs.python.org/3/library/dataclasses.html +RedirectTemp /5-10 https://docs.python.org/3/library/dataclasses.html#inheritance +RedirectTemp /5-11 https://www.python.org/dev/peps/pep-0526/#class-and-instance-variable-annotations +RedirectTemp /5-12 https://dublincore.org/specifications/dublin-core/ +RedirectTemp /5-13 https://en.wikipedia.org/wiki/Dublin_Core +RedirectTemp /5-14 https://martinfowler.com/bliki/CodeSmell.html +RedirectTemp /5-15 https://martinfowler.com/books/refactoring.html +RedirectTemp /5-16 https://www.python.org/dev/peps/pep-0634/#class-patterns +RedirectTemp /5-17 https://docs.python.org/3/library/dataclasses.html +RedirectTemp /5-18 https://www.python.org/dev/peps/pep-0557/#id47 +RedirectTemp /5-19 https://www.python.org/dev/peps/pep-0557/#id48 +RedirectTemp /5-20 https://www.python.org/dev/peps/pep-0557/#id33 +RedirectTemp /5-21 https://realpython.com +RedirectTemp /5-22 https://realpython.com/python-data-classes/ +RedirectTemp /5-23 https://www.youtube.com/watch?v=T-TwcmT6Rcw +RedirectTemp /5-24 https://www.attrs.org/en/stable/ +RedirectTemp /5-25 https://glyph.twistedmatrix.com/2016/08/attrs.html +RedirectTemp /5-26 https://www.attrs.org/en/stable/why.html +RedirectTemp /5-27 https://github.com/dabeaz/cluegen +RedirectTemp /5-28 https://refactoring.guru/ +RedirectTemp /5-29 https://refactoring.guru/smells/data-class +RedirectTemp /5-30 https://web.archive.org/web/20190204130328/http://catb.org/esr/jargon/html/G/Guido.html +RedirectTemp /5-31 https://web.archive.org/web/20190211161610/http://catb.org/esr/jargon/html/index.html +RedirectTemp /5-32 https://www.attrs.org/en/stable/ ############################################################ 06 -RedirectTemp /6-3 https://www.olin.edu/faculty/profile/lynn-andrea-stein/ -RedirectTemp /6-4 https://docs.python.org/3/reference/datamodel.html#objects-values-and-types -RedirectTemp /6-5 https://pythontutor.com/ -RedirectTemp /6-6 https://docs.python.org/3/library/copy.html -RedirectTemp /6-7 https://en.wikipedia.org/wiki/Principle_of_least_astonishment -RedirectTemp /6-8 https://docs.python.org/3/reference/datamodel.html#object.%5C_%5C_del__ -RedirectTemp /6-9 https://emptysqua.re/blog/pypy-garbage-collection-and-a-deadlock/ -RedirectTemp /6-15 https://www.youtube.com/watch?v=HHFCFJSPWrI&feature=youtu.be -RedirectTemp /6-16 http://pymotw.com/3/copy/ -RedirectTemp /6-17 http://pymotw.com/3/weakref/ -RedirectTemp /6-18 https://docs.python.org/3/library/gc.html -RedirectTemp /6-20 https://devguide.python.org/garbage_collector/ -RedirectTemp /6-21 https://devguide.python.org/ -RedirectTemp /6-22 https://www.python.org/dev/peps/pep-0442/ -RedirectTemp /6-23 https://en.wikipedia.org/wiki/String_interning -RedirectTemp /6-24 https://en.wikipedia.org/wiki/Haddocks%27_Eyes -RedirectTemp /6-25 https://thp.io/2012/python-gc/python_gc_final_2012-01-22.pdf +RedirectTemp /6-1 https://www.olin.edu/faculty/profile/lynn-andrea-stein/ +RedirectTemp /6-2 https://docs.python.org/3/reference/datamodel.html#objects-values-and-types +RedirectTemp /6-3 https://pythontutor.com/ +RedirectTemp /6-4 https://docs.python.org/3/library/copy.html +RedirectTemp /6-5 https://en.wikipedia.org/wiki/Principle_of_least_astonishment +RedirectTemp /6-6 https://docs.python.org/3/reference/datamodel.html#object.%5C_%5C_del__ +RedirectTemp /6-7 https://emptysqua.re/blog/pypy-garbage-collection-and-a-deadlock/ +RedirectTemp /6-8 https://www.youtube.com/watch?v=HHFCFJSPWrI&feature=youtu.be +RedirectTemp /6-9 http://pymotw.com/3/copy/ +RedirectTemp /6-10 http://pymotw.com/3/weakref/ +RedirectTemp /6-11 https://docs.python.org/3/library/gc.html +RedirectTemp /6-12 https://devguide.python.org/garbage_collector/ +RedirectTemp /6-13 https://devguide.python.org/ +RedirectTemp /6-14 https://www.python.org/dev/peps/pep-0442/ +RedirectTemp /6-15 https://en.wikipedia.org/wiki/String_interning +RedirectTemp /6-16 https://en.wikipedia.org/wiki/Haddocks%27_Eyes +RedirectTemp /6-17 https://thp.io/2012/python-gc/python_gc_final_2012-01-22.pdf ############################################################ 07 RedirectTemp /7-1 http://python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html -RedirectTemp /7-3 https://www.fluentpython.com/extra/function-introspection/ -RedirectTemp /7-5 https://docs.python.org/3/library/functions.html#map -RedirectTemp /7-6 https://en.wikipedia.org/wiki/Functional_programming -RedirectTemp /7-7 https://docs.python.org/3/howto/functional.html -RedirectTemp /7-8 https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy -RedirectTemp /7-9 https://docs.python.org/3/whatsnew/3.8.html#positional-only-parameters -RedirectTemp /7-10 https://docs.python.org/3/whatsnew/3.8.html#positional-only-parameters -RedirectTemp /7-12 https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy -RedirectTemp /7-14 https://docs.python.org/3/howto/functional.html -RedirectTemp /7-15 https://stackoverflow.com/questions/3252228/python-why-is-functools-partial-necessary -RedirectTemp /7-16 https://speakerdeck.com/ramalho/beyond-paradigms-berlin-edition -RedirectTemp /7-17 https://www.youtube.com/watch?v=bF3a2VYXxa0 -RedirectTemp /7-18 http://cs.brown.edu/~sk/Publications/Papers/Published/sk-teach-pl-post-linnaean/ -RedirectTemp /7-19 http://python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html -RedirectTemp /7-20 https://raw.githubusercontent.com/python/cpython/main/Misc/HISTORY -RedirectTemp /7-21 http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html +RedirectTemp /7-2 https://www.fluentpython.com/extra/function-introspection/ +RedirectTemp /7-3 https://docs.python.org/3/library/functions.html#map +RedirectTemp /7-4 https://en.wikipedia.org/wiki/Functional_programming +RedirectTemp /7-5 https://docs.python.org/3/howto/functional.html +RedirectTemp /7-6 https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy +RedirectTemp /7-7 https://docs.python.org/3/whatsnew/3.8.html#positional-only-parameters +RedirectTemp /7-8 https://docs.python.org/3/whatsnew/3.8.html#positional-only-parameters +RedirectTemp /7-9 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Lib/functools.py#L341 +RedirectTemp /7-10 https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy +RedirectTemp /7-11 https://docs.python.org/3/howto/functional.html +RedirectTemp /7-12 https://stackoverflow.com/questions/3252228/python-why-is-functools-partial-necessary +RedirectTemp /7-13 https://speakerdeck.com/ramalho/beyond-paradigms-berlin-edition +RedirectTemp /7-14 https://www.youtube.com/watch?v=bF3a2VYXxa0 +RedirectTemp /7-15 http://cs.brown.edu/~sk/Publications/Papers/Published/sk-teach-pl-post-linnaean/ +RedirectTemp /7-16 http://python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html +RedirectTemp /7-17 https://raw.githubusercontent.com/python/cpython/main/Misc/HISTORY +RedirectTemp /7-18 http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html ############################################################ 08 RedirectTemp /8-1 https://www.python.org/dev/peps/pep-0484/#non-goals -RedirectTemp /8-4 https://github.com/python/typing/issues/182 -RedirectTemp /8-5 https://github.com/python/mypy/issues/731 -RedirectTemp /8-6 https://github.com/google/pytype -RedirectTemp /8-7 https://github.com/Microsoft/pyright -RedirectTemp /8-8 https://pyre-check.org/ -RedirectTemp /8-10 https://mypy.readthedocs.io/en/stable/introduction.html -RedirectTemp /8-11 https://mypy.readthedocs.io/en/stable/config_file.html -RedirectTemp /8-12 https://pypi.org/project/flake8/ -RedirectTemp /8-13 https://pypi.org/project/blue/ -RedirectTemp /8-14 https://pypi.org/project/black/ -RedirectTemp /8-16 https://wefearchange.org/2020/11/steeringcouncil.rst.html -RedirectTemp /8-17 https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes -RedirectTemp /8-18 https://en.wikipedia.org/wiki/Barbara_Liskov -RedirectTemp /8-19 https://en.wikipedia.org/wiki/Behavioral_subtyping -RedirectTemp /8-22 https://www.python.org/dev/peps/pep-0585/#implementation -RedirectTemp /8-25 https://docs.python.org/3/library/typing.html#module-contents -RedirectTemp /8-26 https://en.wikipedia.org/wiki/Geohash -RedirectTemp /8-27 https://en.wikipedia.org/wiki/Inverted_index -RedirectTemp /8-29 https://docs.python.org/3/library/typing.html#typing.List -RedirectTemp /8-30 https://docs.python.org/3/library/typing.html#typing.Dict -RedirectTemp /8-31 https://docs.python.org/3/library/typing.html#typing.Set -RedirectTemp /8-32 https://www.python.org/dev/peps/pep-0585/#implementation -RedirectTemp /8-34 https://docs.python.org/3/library/numbers.html -RedirectTemp /8-37 https://docs.python.org/3/library/typing.html#typing.List -RedirectTemp /8-38 https://github.com/python/typeshed -RedirectTemp /8-39 https://github.com/python/typeshed/blob/66cd36268a6a667714efaa27198a41d0d7f89477/stdlib/2and3/math.pyi#L45 -RedirectTemp /8-41 https://docs.python.org/3/library/statistics.html#statistics.mode -RedirectTemp /8-42 https://docs.python.org/3/library/statistics.html#statistics.mode -RedirectTemp /8-46 https://docs.python.org/3/library/typing.html#typing.Callable -RedirectTemp /8-47 https://pypi.org/project/blue/ -RedirectTemp /8-48 https://www.python.org/dev/peps/pep-0484/#id38 -RedirectTemp /8-49 https://docs.google.com/document/d/1aXs1tpwzPjW9MdsG5dI7clNFyYayFBkcXwRDo-qvbIk/preview -RedirectTemp /8-50 https://www.oreilly.com/library/view/the-best-software/9781590595008/ -RedirectTemp /8-51 https://www.youtube.com/watch?v=YFexUDjHO6w -RedirectTemp /8-52 https://www.youtube.com/watch?v=YFexUDjHO6w&t=13m40s -RedirectTemp /8-53 https://bernat.tech/posts/the-state-of-type-hints-in-python/ -RedirectTemp /8-54 https://realpython.com/python-type-checking/ -RedirectTemp /8-55 https://cjolowicz.github.io/posts/hypermodern-python-04-typing/ -RedirectTemp /8-56 https://mypy.readthedocs.io/en/stable/index.html -RedirectTemp /8-57 https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html -RedirectTemp /8-58 https://mypy.readthedocs.io/en/stable/common_issues.html -RedirectTemp /8-60 https://github.com/typeddjango/awesome-python-typing -RedirectTemp /8-61 https://docs.python.org/3/library/functions.html#max -RedirectTemp /8-62 https://en.wikipedia.org/wiki/Linguistic_relativity -RedirectTemp /8-63 https://pypistats.org/top -RedirectTemp /8-64 https://github.com/psf/requests/issues/3855 -RedirectTemp /8-65 https://lwn.net/Articles/643399/ -RedirectTemp /8-66 https://docs.python-requests.org/en/master/api/#requests.request -RedirectTemp /8-67 https://queue.acm.org/detail.cfm?id=1039523 +RedirectTemp /8-2 https://github.com/python/typing/issues/182 +RedirectTemp /8-3 https://github.com/python/mypy/issues/731 +RedirectTemp /8-4 https://github.com/google/pytype +RedirectTemp /8-5 https://github.com/Microsoft/pyright +RedirectTemp /8-6 https://pyre-check.org/ +RedirectTemp /8-7 https://mypy.readthedocs.io/en/stable/introduction.html +RedirectTemp /8-8 https://mypy.readthedocs.io/en/stable/config_file.html +RedirectTemp /8-9 https://pypi.org/project/flake8/ +RedirectTemp /8-10 https://pypi.org/project/blue/ +RedirectTemp /8-11 https://pypi.org/project/black/ +RedirectTemp /8-12 https://wefearchange.org/2020/11/steeringcouncil.rst.html +RedirectTemp /8-13 https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes +RedirectTemp /8-14 https://en.wikipedia.org/wiki/Barbara_Liskov +RedirectTemp /8-15 https://en.wikipedia.org/wiki/Behavioral_subtyping +RedirectTemp /8-16 https://www.python.org/dev/peps/pep-0585/#implementation +RedirectTemp /8-17 https://docs.python.org/3/library/typing.html#module-contents +RedirectTemp /8-18 https://en.wikipedia.org/wiki/Geohash +RedirectTemp /8-19 https://en.wikipedia.org/wiki/Inverted_index +RedirectTemp /8-20 https://docs.python.org/3/library/typing.html#typing.List +RedirectTemp /8-21 https://docs.python.org/3/library/typing.html#typing.Dict +RedirectTemp /8-22 https://docs.python.org/3/library/typing.html#typing.Set +RedirectTemp /8-23 https://www.python.org/dev/peps/pep-0585/#implementation +RedirectTemp /8-24 https://docs.python.org/3/library/numbers.html +RedirectTemp /8-25 https://docs.python.org/3/library/typing.html#typing.List +RedirectTemp /8-26 https://github.com/python/typeshed +RedirectTemp /8-27 https://github.com/python/typeshed/blob/66cd36268a6a667714efaa27198a41d0d7f89477/stdlib/2and3/math.pyi#L45 +RedirectTemp /8-28 https://docs.python.org/3/library/statistics.html#statistics.mode +RedirectTemp /8-29 https://github.com/python/cpython/blob/822efa5695b5ba6c2316c1400e4e9ec2546f7ea5/Lib/statistics.py#L534 +RedirectTemp /8-30 https://github.com/python/typeshed/blob/e1e99245bb46223928eba68d4fc74962240ba5b4/stdlib/3/statistics.pyi +RedirectTemp /8-31 https://docs.python.org/3/library/statistics.html#statistics.mode +RedirectTemp /8-32 https://github.com/python/typeshed/blob/a8834fcd46339e17fc8add82b5803a1ce53d3d60/stdlib/3/statistics.pyi#L32 +RedirectTemp /8-33 https://mail.python.org/archives/list/python-dev@python.org/thread/CLVXXPQ2T2LQ5MP2Y53VVQFCXYWQJHKZ/ +RedirectTemp /8-34 https://docs.python.org/3/library/typing.html#typing.Callable +RedirectTemp /8-35 https://pypi.org/project/blue/ +RedirectTemp /8-36 https://www.python.org/dev/peps/pep-0484/#id38 +RedirectTemp /8-37 https://docs.google.com/document/d/1aXs1tpwzPjW9MdsG5dI7clNFyYayFBkcXwRDo-qvbIk/preview +RedirectTemp /8-38 https://www.oreilly.com/library/view/the-best-software/9781590595008/ +RedirectTemp /8-39 https://www.youtube.com/watch?v=YFexUDjHO6w +RedirectTemp /8-40 https://www.youtube.com/watch?v=YFexUDjHO6w&t=13m40s +RedirectTemp /8-41 https://bernat.tech/posts/the-state-of-type-hints-in-python/ +RedirectTemp /8-42 https://realpython.com/python-type-checking/ +RedirectTemp /8-43 https://cjolowicz.github.io/posts/hypermodern-python-04-typing/ +RedirectTemp /8-44 https://mypy.readthedocs.io/en/stable/index.html +RedirectTemp /8-45 https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html +RedirectTemp /8-46 https://mypy.readthedocs.io/en/stable/common_issues.html +RedirectTemp /8-47 https://github.com/typeddjango/awesome-python-typing +RedirectTemp /8-48 https://docs.python.org/3/library/functions.html#max +RedirectTemp /8-49 https://en.wikipedia.org/wiki/Linguistic_relativity +RedirectTemp /8-50 https://pypistats.org/top +RedirectTemp /8-51 https://github.com/psf/requests/issues/3855 +RedirectTemp /8-52 https://lwn.net/Articles/643399/ +RedirectTemp /8-53 https://docs.python-requests.org/en/master/api/#requests.request +RedirectTemp /8-54 https://queue.acm.org/detail.cfm?id=1039523 ############################################################ 09 RedirectTemp /9-1 https://docs.python.org/3/library/dis.html RedirectTemp /9-2 https://en.wikipedia.org/wiki/Memoization RedirectTemp /9-3 https://numpy.org/doc/stable/user/basics.types.html -RedirectTemp /9-5 https://docs.python.org/3/library/functools.html#functools.singledispatch -RedirectTemp /9-7 https://github.com/GrahamDumpleton/wrapt/blob/develop/blog/README.md -RedirectTemp /9-8 https://github.com/GrahamDumpleton/wrapt/blob/develop/blog/01-how-you-implemented-your-python-decorator-is-wrong.md -RedirectTemp /9-9 https://wrapt.readthedocs.io/en/latest/ -RedirectTemp /9-10 https://www.oreilly.com/library/view/python-cookbook-3rd/9781449357337/ch09.html -RedirectTemp /9-11 https://pypi.org/project/decorator/ -RedirectTemp /9-12 https://wiki.python.org/moin/PythonDecoratorLibrary -RedirectTemp /9-13 http://web.archive.org/web/20201109032203/http://effbot.org/zone/closure.htm -RedirectTemp /9-14 https://www.python.org/dev/peps/pep-3104/ -RedirectTemp /9-15 https://www.python.org/dev/peps/pep-0227/ -RedirectTemp /9-16 https://www.python.org/dev/peps/pep-0443/ -RedirectTemp /9-17 https://www.artima.com/weblogs/viewpost.jsp?thread=101605 -RedirectTemp /9-18 https://reg.readthedocs.io/en/latest/ -RedirectTemp /9-19 https://morepath.readthedocs.io/en/latest/ -RedirectTemp /9-20 https://www.gnu.org/software/emacs/manual/html_node/elisp/Dynamic-Binding.html -RedirectTemp /9-21 http://www.paulgraham.com/rootsoflisp.html -RedirectTemp /9-22 http://www-formal.stanford.edu/jmc/recursive/recursive.html -RedirectTemp /9-23 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this +RedirectTemp /9-4 https://docs.python.org/3/library/functools.html#functools.singledispatch +RedirectTemp /9-5 https://github.com/GrahamDumpleton/wrapt/blob/develop/blog/README.md +RedirectTemp /9-6 https://github.com/GrahamDumpleton/wrapt/blob/develop/blog/01-how-you-implemented-your-python-decorator-is-wrong.md +RedirectTemp /9-7 https://wrapt.readthedocs.io/en/latest/ +RedirectTemp /9-8 https://www.oreilly.com/library/view/python-cookbook-3rd/9781449357337/ch09.html +RedirectTemp /9-9 https://pypi.org/project/decorator/ +RedirectTemp /9-10 https://wiki.python.org/moin/PythonDecoratorLibrary +RedirectTemp /9-11 http://web.archive.org/web/20201109032203/http://effbot.org/zone/closure.htm +RedirectTemp /9-12 https://www.python.org/dev/peps/pep-3104/ +RedirectTemp /9-13 https://www.python.org/dev/peps/pep-0227/ +RedirectTemp /9-14 https://www.python.org/dev/peps/pep-0443/ +RedirectTemp /9-15 https://www.artima.com/weblogs/viewpost.jsp?thread=101605 +RedirectTemp /9-16 https://reg.readthedocs.io/en/latest/ +RedirectTemp /9-17 https://morepath.readthedocs.io/en/latest/ +RedirectTemp /9-18 https://www.gnu.org/software/emacs/manual/html_node/elisp/Dynamic-Binding.html +RedirectTemp /9-19 http://www.paulgraham.com/rootsoflisp.html +RedirectTemp /9-20 http://www-formal.stanford.edu/jmc/recursive/recursive.html +RedirectTemp /9-21 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this ############################################################ 10 RedirectTemp /10-1 https://en.wikipedia.org/wiki/Software_design_pattern RedirectTemp /10-2 https://en.wikipedia.org/wiki/Iterator_pattern -RedirectTemp /10-4 https://github.com/python/mypy/issues/9397 -RedirectTemp /10-5 http://www.norvig.com/design-patterns/index.htm -RedirectTemp /10-6 https://pyvideo.org/video/1110/python-design-patterns/ -RedirectTemp /10-7 http://www.aleax.it/gdd_pydp.pdf -RedirectTemp /10-9 https://perl.plover.com/yak/design/ -RedirectTemp /10-11 https://en.wikipedia.org/wiki/Turtles_all_the_way_down +RedirectTemp /10-3 https://github.com/python/mypy/issues/9397 +RedirectTemp /10-4 http://www.norvig.com/design-patterns/index.htm +RedirectTemp /10-5 https://pyvideo.org/video/1110/python-design-patterns/ +RedirectTemp /10-6 http://www.aleax.it/gdd_pydp.pdf +RedirectTemp /10-7 https://perl.plover.com/yak/design/ +RedirectTemp /10-8 https://en.wikipedia.org/wiki/Turtles_all_the_way_down ############################################################ 11 RedirectTemp /11-1 https://blog.startifact.com/posts/older/what-is-pythonic.html RedirectTemp /11-2 https://julien.danjou.info/guide-python-static-class-abstract-methods/ RedirectTemp /11-3 https://docs.python.org/3/library/string.html#formatspec -RedirectTemp /11-5 https://docs.python.org/3/reference/lexical_analysis.html#f-strings -RedirectTemp /11-6 https://docs.python.org/3/library/string.html#format-string-syntax -RedirectTemp /11-7 https://docs.python.org/3/library/string.html#formatspec -RedirectTemp /11-8 https://docs.python.org/3/reference/datamodel.html#object.__hash__ -RedirectTemp /11-9 https://web.archive.org/web/20161025185040/http://pythonpaste.org/StyleGuide.html -RedirectTemp /11-10 https://docs.python.org/3/tutorial/modules.html#more-on-modules -RedirectTemp /11-11 https://docs.python.org/3/library/gettext.html#gettext.NullTranslations -RedirectTemp /11-12 https://github.com/fluentpython/example-code-2e/blob/master/11-pythonic-obj/mem_test.py -RedirectTemp /11-16 https://docs.python.org/3/reference/datamodel.html#basic-customization -RedirectTemp /11-18 http://esug.org/data/HistoricalDocuments/TheSmalltalkReport/ST07/04wo.pdf -RedirectTemp /11-19 https://docs.oracle.com/javase/tutorial/essential/environment/security.html -RedirectTemp /11-21 https://docs.oracle.com/javase/tutorial/essential/environment/security.html +RedirectTemp /11-4 https://docs.python.org/3/reference/lexical_analysis.html#f-strings +RedirectTemp /11-5 https://docs.python.org/3/library/string.html#format-string-syntax +RedirectTemp /11-6 https://docs.python.org/3/library/string.html#formatspec +RedirectTemp /11-7 https://docs.python.org/3/reference/datamodel.html#object.__hash__ +RedirectTemp /11-8 https://web.archive.org/web/20161025185040/http://pythonpaste.org/StyleGuide.html +RedirectTemp /11-9 https://docs.python.org/3/tutorial/modules.html#more-on-modules +RedirectTemp /11-10 https://docs.python.org/3/library/gettext.html#gettext.NullTranslations +RedirectTemp /11-11 https://github.com/fluentpython/example-code-2e/blob/master/11-pythonic-obj/mem_test.py +RedirectTemp /11-12 https://docs.python.org/3/reference/datamodel.html#basic-customization +RedirectTemp /11-13 http://esug.org/data/HistoricalDocuments/TheSmalltalkReport/ST07/04wo.pdf +RedirectTemp /11-14 https://www.artima.com/articles/the-simplest-thing-that-could-possibly-work#part3 +RedirectTemp /11-15 https://docs.oracle.com/javase/tutorial/essential/environment/security.html +RedirectTemp /11-16 https://github.com/fluentpython/example-code-2e/blob/master/11-pythonic-obj/private/Expose.java +RedirectTemp /11-17 https://docs.oracle.com/javase/tutorial/essential/environment/security.html ############################################################ 12 RedirectTemp /12-1 https://en.wikipedia.org/wiki/Vector_space_model RedirectTemp /12-2 https://pypi.org/project/gensim/ -RedirectTemp /12-6 https://docs.python.org/3/library/functions.html#enumerate -RedirectTemp /12-7 https://mathworld.wolfram.com/Hypersphere.html -RedirectTemp /12-12 https://en.wikipedia.org/wiki/Fold_(higher-order_function) -RedirectTemp /12-13 https://docs.python.org/2.5/whatsnew/pep-357.html -RedirectTemp /12-15 https://docs.python.org/3/reference/datamodel.html#special-method-names -RedirectTemp /12-16 https://en.wikipedia.org/wiki/KISS_principle -RedirectTemp /12-17 https://mail.python.org/pipermail/python-list/2000-July/046184.html -RedirectTemp /12-18 https://en.wikipedia.org/wiki/Duck_typing -RedirectTemp /12-19 https://mail.python.org/mailman/listinfo/python-list -RedirectTemp /12-20 https://mail.python.org/pipermail/python-list/2003-April/218568.html +RedirectTemp /12-3 https://docs.python.org/3/library/functions.html#enumerate +RedirectTemp /12-4 https://mathworld.wolfram.com/Hypersphere.html +RedirectTemp /12-5 https://en.wikipedia.org/wiki/Fold_(higher-order_function) +RedirectTemp /12-6 https://docs.python.org/2.5/whatsnew/pep-357.html +RedirectTemp /12-7 https://docs.python.org/3/reference/datamodel.html#special-method-names +RedirectTemp /12-8 https://en.wikipedia.org/wiki/KISS_principle +RedirectTemp /12-9 https://mail.python.org/pipermail/python-list/2000-July/046184.html +RedirectTemp /12-10 https://en.wikipedia.org/wiki/Duck_typing +RedirectTemp /12-11 https://mail.python.org/mailman/listinfo/python-list +RedirectTemp /12-12 https://mail.python.org/pipermail/python-list/2003-April/218568.html ############################################################ 13 -RedirectTemp /13-2 https://docs.python.org/3/c-api/index.html -RedirectTemp /13-3 https://docs.python.org/3/c-api/sequence.html -RedirectTemp /13-7 https://github.com/python/cpython/blob/31ceccb2c77854893f3a754aca04bedd74bedb10/Lib/_collections_abc.py#L870 -RedirectTemp /13-8 https://en.wikipedia.org/wiki/Monkey_patch -RedirectTemp /13-9 https://www.gevent.org/api/gevent.monkey.html -RedirectTemp /13-10 https://docs.python.org/3/library/random.html#random.shuffle -RedirectTemp /13-11 https://docs.python.org/3/reference/datamodel.html#emulating-container-types -RedirectTemp /13-12 https://docs.python.org/3/library/collections.html#collections.namedtuple -RedirectTemp /13-13 https://github.com/python/typeshed/blob/24afb531ffd07083d6a74be917342195062f7277/stdlib/collections/__init__.pyi -RedirectTemp /13-14 https://docs.python.org/3/glossary.html#term-abstract-base-class -RedirectTemp /13-15 https://en.wikipedia.org/wiki/Duck_typing#History -RedirectTemp /13-16 http://ptgmedia.pearsoncmg.com/images/020163371x/items/item33.html -RedirectTemp /13-17 https://docs.python.org/3/library/bisect.html#bisect.bisect -RedirectTemp /13-20 https://github.com/python/cpython/blob/main/Lib/_collections_abc.py -RedirectTemp /13-21 https://github.com/python/cpython/blob/main/Lib/abc.py -RedirectTemp /13-22 https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes -RedirectTemp /13-23 https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable -RedirectTemp /13-24 https://docs.python.org/3/library/abc.html -RedirectTemp /13-25 https://docs.python.org/dev/library/abc.html#abc.abstractmethod -RedirectTemp /13-26 https://docs.python.org/dev/library/abc.html -RedirectTemp /13-27 https://docs.python.org/3/library/os.html#os.urandom -RedirectTemp /13-28 https://github.com/python/mypy/issues/2922 -RedirectTemp /13-29 https://docs.python.org/3/library/stdtypes.html#truth -RedirectTemp /13-30 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Lib/_collections_abc.py -RedirectTemp /13-31 https://github.com/python/cpython/blob/0fbddb14dc03f61738af01af88e7d8aa8df07336/Lib/_collections_abc.py#L369 -RedirectTemp /13-32 https://bugs.python.org/issue31333 -RedirectTemp /13-33 https://github.com/python/cpython/blob/3635388f52b42e5280229104747962117104c453/Modules/_abc.c#L605 -RedirectTemp /13-34 https://github.com/python/cpython/blob/0fbddb14dc03f61738af01af88e7d8aa8df07336/Lib/_collections_abc.py#L881 -RedirectTemp /13-37 https://docs.python.org/3/library/typing.html#protocols -RedirectTemp /13-40 https://martinfowler.com/bliki/RoleInterface.html -RedirectTemp /13-41 https://en.wikipedia.org/wiki/Interface_segregation_principle -RedirectTemp /13-42 https://github.com/python/typeshed/blob/master/CONTRIBUTING.md -RedirectTemp /13-43 https://gist.github.com/asukakenji/ac8a05644a2e98f1d5ea8c299541fce9 -RedirectTemp /13-44 https://www.python.org/dev/peps/pep-0544/#merging-and-extending-protocols -RedirectTemp /13-45 https://numpy.org/devdocs/user/basics.types.html -RedirectTemp /13-46 https://github.com/python/typeshed/blob/master/stdlib/statistics.pyi -RedirectTemp /13-47 https://bugs.python.org/issue41974 -RedirectTemp /13-49 https://glyph.twistedmatrix.com/2020/07/new-duck.html -RedirectTemp /13-50 https://glyph.twistedmatrix.com/2021/03/interfaces-and-protocols.html -RedirectTemp /13-51 https://plone.org/ -RedirectTemp /13-52 https://trypyramid.com/ -RedirectTemp /13-53 https://twistedmatrix.com/trac/ -RedirectTemp /13-54 https://www.artima.com/articles/contracts-in-python -RedirectTemp /13-55 https://martinfowler.com/bliki/DynamicTyping.html -RedirectTemp /13-56 https://martinfowler.com/bliki/RoleInterface.html -RedirectTemp /13-57 https://mypy.readthedocs.io/en/stable/protocols.html -RedirectTemp /13-58 https://pymotw.com/3/abc/index.html -RedirectTemp /13-59 https://www.python.org/dev/peps/pep-3119/ -RedirectTemp /13-60 https://www.python.org/dev/peps/pep-3141/ -RedirectTemp /13-61 https://docs.python.org/3/library/numbers.html -RedirectTemp /13-62 https://github.com/python/mypy/issues/3186 -RedirectTemp /13-63 https://github.com/python/mypy/issues/3186 -RedirectTemp /13-64 https://martinfowler.com/articles/lean-inception/ -RedirectTemp /13-65 https://martinfowler.com -RedirectTemp /13-68 https://www.jetbrains.com/pycharm/ -RedirectTemp /13-69 https://wingware.com/ -RedirectTemp /13-70 https://code.visualstudio.com/ +RedirectTemp /13-1 https://docs.python.org/3/c-api/index.html +RedirectTemp /13-2 https://docs.python.org/3/c-api/sequence.html +RedirectTemp /13-3 https://github.com/python/cpython/blob/31ceccb2c77854893f3a754aca04bedd74bedb10/Lib/_collections_abc.py#L870 +RedirectTemp /13-4 https://en.wikipedia.org/wiki/Monkey_patch +RedirectTemp /13-5 https://www.gevent.org/api/gevent.monkey.html +RedirectTemp /13-6 https://docs.python.org/3/library/random.html#random.shuffle +RedirectTemp /13-7 https://docs.python.org/3/reference/datamodel.html#emulating-container-types +RedirectTemp /13-8 https://docs.python.org/3/library/collections.html#collections.namedtuple +RedirectTemp /13-9 https://github.com/python/typeshed/blob/24afb531ffd07083d6a74be917342195062f7277/stdlib/collections/__init__.pyi +RedirectTemp /13-10 https://docs.python.org/3/glossary.html#term-abstract-base-class +RedirectTemp /13-11 https://en.wikipedia.org/wiki/Duck_typing#History +RedirectTemp /13-12 http://ptgmedia.pearsoncmg.com/images/020163371x/items/item33.html +RedirectTemp /13-13 https://docs.python.org/3/library/bisect.html#bisect.bisect +RedirectTemp /13-14 https://github.com/python/cpython/blob/main/Lib/_collections_abc.py +RedirectTemp /13-15 https://github.com/python/cpython/blob/main/Lib/abc.py +RedirectTemp /13-16 https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes +RedirectTemp /13-17 https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable +RedirectTemp /13-18 https://docs.python.org/3/library/abc.html +RedirectTemp /13-19 https://docs.python.org/dev/library/abc.html#abc.abstractmethod +RedirectTemp /13-20 https://docs.python.org/dev/library/abc.html +RedirectTemp /13-21 https://docs.python.org/3/library/os.html#os.urandom +RedirectTemp /13-22 https://github.com/python/mypy/issues/2922 +RedirectTemp /13-23 https://docs.python.org/3/library/stdtypes.html#truth +RedirectTemp /13-24 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Lib/_collections_abc.py +RedirectTemp /13-25 https://github.com/python/cpython/blob/0fbddb14dc03f61738af01af88e7d8aa8df07336/Lib/_collections_abc.py#L369 +RedirectTemp /13-26 https://github.com/python/cpython/blob/c0a9afe2ac1820409e6173bd1893ebee2cf50270/Lib/abc.py#L196 +RedirectTemp /13-27 https://bugs.python.org/issue31333 +RedirectTemp /13-28 https://github.com/python/cpython/blob/3635388f52b42e5280229104747962117104c453/Modules/_abc.c#L605 +RedirectTemp /13-29 https://github.com/python/cpython/blob/0fbddb14dc03f61738af01af88e7d8aa8df07336/Lib/_collections_abc.py#L881 +RedirectTemp /13-30 https://docs.python.org/3/library/typing.html#protocols +RedirectTemp /13-31 https://github.com/python/cpython/blob/3635388f52b42e5280229104747962117104c453/Lib/typing.py#L1751 +RedirectTemp /13-32 https://mail.python.org/archives/list/python-dev@python.org/thread/CLVXXPQ2T2LQ5MP2Y53VVQFCXYWQJHKZ/ +RedirectTemp /13-33 https://martinfowler.com/bliki/RoleInterface.html +RedirectTemp /13-34 https://en.wikipedia.org/wiki/Interface_segregation_principle +RedirectTemp /13-35 https://github.com/python/typeshed/blob/master/CONTRIBUTING.md +RedirectTemp /13-36 https://gist.github.com/asukakenji/ac8a05644a2e98f1d5ea8c299541fce9 +RedirectTemp /13-37 https://www.python.org/dev/peps/pep-0544/#runtime-checkable-decorator-and-narrowing-types-by-isinstance +RedirectTemp /13-38 https://www.python.org/dev/peps/pep-0544/#merging-and-extending-protocols +RedirectTemp /13-39 https://numpy.org/devdocs/user/basics.types.html +RedirectTemp /13-40 https://github.com/python/typeshed/blob/master/stdlib/statistics.pyi +RedirectTemp /13-41 https://bugs.python.org/issue41974 +RedirectTemp /13-42 https://glyph.twistedmatrix.com/2020/07/new-duck.html +RedirectTemp /13-43 https://glyph.twistedmatrix.com/2021/03/interfaces-and-protocols.html +RedirectTemp /13-44 https://plone.org/ +RedirectTemp /13-45 https://trypyramid.com/ +RedirectTemp /13-46 https://twistedmatrix.com/trac/ +RedirectTemp /13-47 https://www.artima.com/articles/contracts-in-python +RedirectTemp /13-48 https://martinfowler.com/bliki/DynamicTyping.html +RedirectTemp /13-49 https://martinfowler.com/bliki/RoleInterface.html +RedirectTemp /13-50 https://mypy.readthedocs.io/en/stable/protocols.html +RedirectTemp /13-51 https://pymotw.com/3/abc/index.html +RedirectTemp /13-52 https://www.python.org/dev/peps/pep-3119/ +RedirectTemp /13-53 https://www.python.org/dev/peps/pep-3141/ +RedirectTemp /13-54 https://docs.python.org/3/library/numbers.html +RedirectTemp /13-55 https://github.com/python/mypy/issues/3186 +RedirectTemp /13-56 https://stackoverflow.com/questions/69334475/how-to-hint-at-number-types-i-e-subclasses-of-number-not-numbers-themselv/69383462#69383462 +RedirectTemp /13-57 https://github.com/python/mypy/issues/3186 +RedirectTemp /13-58 https://martinfowler.com/articles/lean-inception/ +RedirectTemp /13-59 https://martinfowler.com +RedirectTemp /13-60 https://www.jetbrains.com/pycharm/ +RedirectTemp /13-61 https://wingware.com/ +RedirectTemp /13-62 https://code.visualstudio.com/ ############################################################ 14 RedirectTemp /14-1 http://worrydream.com/EarlyHistoryOfSmalltalk/ RedirectTemp /14-2 https://docs.python.org/3/tutorial/classes.html RedirectTemp /14-3 https://docs.python.org/3/library/collections.html#ordereddict-examples-and-recipes RedirectTemp /14-4 https://discuss.python.org/t/is-it-time-to-deprecate-unbound-super-methods/1833 -RedirectTemp /14-6 https://doc.pypy.org/en/latest/cpython_differences.html#subclasses-of-built-in-types -RedirectTemp /14-7 https://docs.python.org/3/library/collections.html -RedirectTemp /14-9 https://doc.pypy.org/en/latest/cpython_differences.html#subclasses-of-built-in-types -RedirectTemp /14-10 https://en.wikipedia.org/wiki/Breadth-first_search -RedirectTemp /14-11 https://www.python.org/download/releases/2.3/mro/ -RedirectTemp /14-12 https://github.com/fluentpython/example-code-2e/blob/master/14-inheritance/uppermixin.py -RedirectTemp /14-13 https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html -RedirectTemp /14-14 https://docs.python.org/3/library/collections.abc.html -RedirectTemp /14-15 https://github.com/python/cpython/blob/8ece98a7e418c3c68a4c61bc47a2d0931b59a889/Lib/collections/__init__.py#L1084 -RedirectTemp /14-16 https://docs.python.org/3/library/http.server.html -RedirectTemp /14-17 https://docs.python.org/3/library/socketserver.html#socketserver.ForkingMixIn -RedirectTemp /14-18 https://docs.python.org/3/library/os.html#os.fork -RedirectTemp /14-19 https://en.wikipedia.org/wiki/POSIX -RedirectTemp /14-20 http://ccbv.co.uk/ -RedirectTemp /14-21 https://github.com/django/django/tree/main/django/views/generic -RedirectTemp /14-22 https://en.wikipedia.org/wiki/Template_method_pattern -RedirectTemp /14-23 https://docs.python.org/3/library/tkinter.html -RedirectTemp /14-24 https://docs.python.org/3/library/tkinter.ttk.html -RedirectTemp /14-25 https://docs.oracle.com/javase/10/docs/api/java/awt/package-tree.html -RedirectTemp /14-26 https://docs.oracle.com/javase/10/docs/api/javax/swing/package-tree.html -RedirectTemp /14-27 https://squeak.org/ -RedirectTemp /14-28 https://github.com/python/cpython/blob/8ed183391241f0c73e7ba7f42b1d49fc02985f7b/Lib/tkinter/__init__.py#L2618 -RedirectTemp /14-29 https://docs.python.org/3/library/socketserver.html -RedirectTemp /14-30 https://docs.python.org/3/library/socketserver.html#socketserver.BaseServer -RedirectTemp /14-32 https://docs.python.org/3/library/typing.html#typing.final -RedirectTemp /14-33 https://docs.python.org/3/library/typing.html#typing.Final -RedirectTemp /14-35 https://docs.python.org/3/library/collections.abc.html -RedirectTemp /14-36 https://hynek.me/articles/python-subclassing-redux/ -RedirectTemp /14-38 https://rhettinger.wordpress.com/2011/05/26/super-considered-super/ -RedirectTemp /14-39 https://fuhm.net/super-harmful/ -RedirectTemp /14-40 https://www.artima.com/weblogs/viewpost.jsp?thread=246488 -RedirectTemp /14-41 https://www.artima.com/weblogs/viewpost.jsp?thread=281127 -RedirectTemp /14-42 https://www.artima.com/weblogs/viewpost.jsp?thread=246341 -RedirectTemp /14-43 https://www.artima.com/weblogs/viewpost.jsp?thread=246483 -RedirectTemp /14-44 https://www.artima.com/weblogs/viewpost.jsp?thread=236275 -RedirectTemp /14-45 https://www.artima.com/weblogs/viewpost.jsp?thread=236278 -RedirectTemp /14-46 https://www.artima.com/weblogs/viewpost.jsp?thread=237121 -RedirectTemp /14-47 https://python-patterns.guide/gang-of-four/composition-over-inheritance/ -RedirectTemp /14-48 https://python-patterns.guide/ -RedirectTemp /14-49 https://www.youtube.com/watch?v=3MNVP9-hglc -RedirectTemp /14-50 http://worrydream.com/EarlyHistoryOfSmalltalk/ -RedirectTemp /14-51 https://en.wikipedia.org/wiki/Polymorphism_(computer_science) +RedirectTemp /14-5 https://doc.pypy.org/en/latest/cpython_differences.html#subclasses-of-built-in-types +RedirectTemp /14-6 https://docs.python.org/3/library/collections.html +RedirectTemp /14-7 https://github.com/fluentpython/example-code-2e/blob/master/14-inheritance/strkeydict_dictsub.py +RedirectTemp /14-8 https://doc.pypy.org/en/latest/cpython_differences.html#subclasses-of-built-in-types +RedirectTemp /14-9 https://en.wikipedia.org/wiki/Breadth-first_search +RedirectTemp /14-10 https://www.python.org/download/releases/2.3/mro/ +RedirectTemp /14-11 https://github.com/fluentpython/example-code-2e/blob/master/14-inheritance/uppermixin.py +RedirectTemp /14-12 https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html +RedirectTemp /14-13 https://docs.python.org/3/library/collections.abc.html +RedirectTemp /14-14 https://github.com/python/cpython/blob/8ece98a7e418c3c68a4c61bc47a2d0931b59a889/Lib/collections/__init__.py#L1084 +RedirectTemp /14-15 https://docs.python.org/3/library/http.server.html +RedirectTemp /14-16 https://github.com/python/cpython/blob/17c23167942498296f0bdfffe52e72d53d66d693/Lib/http/server.py#L144 +RedirectTemp /14-17 https://github.com/python/cpython/blob/699ee016af5736ffc80f68359617611a22b72943/Lib/socketserver.py#L664 +RedirectTemp /14-18 https://docs.python.org/3/library/socketserver.html#socketserver.ForkingMixIn +RedirectTemp /14-19 https://docs.python.org/3/library/os.html#os.fork +RedirectTemp /14-20 https://en.wikipedia.org/wiki/POSIX +RedirectTemp /14-21 http://ccbv.co.uk/ +RedirectTemp /14-22 https://github.com/django/django/tree/main/django/views/generic +RedirectTemp /14-23 https://en.wikipedia.org/wiki/Template_method_pattern +RedirectTemp /14-24 https://docs.python.org/3/library/tkinter.html +RedirectTemp /14-25 https://docs.python.org/3/library/tkinter.ttk.html +RedirectTemp /14-26 https://docs.oracle.com/javase/10/docs/api/java/awt/package-tree.html +RedirectTemp /14-27 https://docs.oracle.com/javase/10/docs/api/javax/swing/package-tree.html +RedirectTemp /14-28 https://squeak.org/ +RedirectTemp /14-29 https://github.com/django/django/blob/b64db05b9cedd96905d637a2d824cbbf428e40e7/django/views/generic/list.py#L194 +RedirectTemp /14-30 https://github.com/python/cpython/blob/8ed183391241f0c73e7ba7f42b1d49fc02985f7b/Lib/tkinter/__init__.py#L2618 +RedirectTemp /14-31 https://docs.python.org/3/library/socketserver.html +RedirectTemp /14-32 https://docs.python.org/3/library/socketserver.html#socketserver.BaseServer +RedirectTemp /14-33 https://github.com/python/cpython/blob/699ee016af5736ffc80f68359617611a22b72943/Lib/socketserver.py#L153 +RedirectTemp /14-34 https://docs.python.org/3/library/typing.html#typing.final +RedirectTemp /14-35 https://docs.python.org/3/library/typing.html#typing.Final +RedirectTemp /14-36 https://docs.python.org/3/library/collections.abc.html +RedirectTemp /14-37 https://hynek.me/articles/python-subclassing-redux/ +RedirectTemp /14-38 https://www.oreilly.com/library/view/python-cookbook-3rd/9781449357337/ch08.html#super +RedirectTemp /14-39 https://rhettinger.wordpress.com/2011/05/26/super-considered-super/ +RedirectTemp /14-40 https://fuhm.net/super-harmful/ +RedirectTemp /14-41 https://stackoverflow.com/questions/30190185/how-to-use-super-with-one-argument/30190341#30190341 +RedirectTemp /14-42 https://www.artima.com/weblogs/viewpost.jsp?thread=246488 +RedirectTemp /14-43 https://www.artima.com/weblogs/viewpost.jsp?thread=281127 +RedirectTemp /14-44 https://www.artima.com/weblogs/viewpost.jsp?thread=246341 +RedirectTemp /14-45 https://www.artima.com/weblogs/viewpost.jsp?thread=246483 +RedirectTemp /14-46 https://www.artima.com/weblogs/viewpost.jsp?thread=236275 +RedirectTemp /14-47 https://www.artima.com/weblogs/viewpost.jsp?thread=236278 +RedirectTemp /14-48 https://www.artima.com/weblogs/viewpost.jsp?thread=237121 +RedirectTemp /14-49 https://python-patterns.guide/gang-of-four/composition-over-inheritance/ +RedirectTemp /14-50 https://python-patterns.guide/ +RedirectTemp /14-51 https://www.youtube.com/watch?v=3MNVP9-hglc +RedirectTemp /14-52 http://worrydream.com/EarlyHistoryOfSmalltalk/ +RedirectTemp /14-53 https://en.wikipedia.org/wiki/Polymorphism_(computer_science) ############################################################ 15 RedirectTemp /15-1 https://www.youtube.com/watch?v=csL8DLXGNlU&t=92m5s +RedirectTemp /15-2 https://github.com/python/typeshed/blob/a8834fcd46339e17fc8add82b5803a1ce53d3d60/stdlib/2and3/builtins.pyi#L1434 +RedirectTemp /15-3 https://github.com/python/typeshed/blob/a8834fcd46339e17fc8add82b5803a1ce53d3d60/stdlib/2and3/builtins.pyi RedirectTemp /15-4 https://twitter.com/gwidion/status/1265384692464967680 RedirectTemp /15-5 https://pypi.org/project/pydantic/ +RedirectTemp /15-6 https://google.github.io/pytype/faq.html RedirectTemp /15-7 https://google.github.io/pytype/faq.html -RedirectTemp /15-8 https://google.github.io/pytype/faq.html -RedirectTemp /15-9 https://lxml.de/ -RedirectTemp /15-10 https://docs.python.org/3/library/xml.etree.elementtree.html -RedirectTemp /15-11 https://mypy.readthedocs.io/en/stable/common_issues.html -RedirectTemp /15-12 https://mypy.readthedocs.io/en/stable/common_issues.html#types-of-empty-collections -RedirectTemp /15-13 https://github.com/python/typing/issues/182 -RedirectTemp /15-14 https://pypi.org/project/pydantic/ -RedirectTemp /15-16 https://mypy.readthedocs.io/en/stable/type_narrowing.html#casts -RedirectTemp /15-17 https://www.python.org/dev/peps/pep-0484/#casts -RedirectTemp /15-18 https://github.com/python/typeshed/issues/5535 -RedirectTemp /15-19 https://docs.python.org/3/library/asyncio-stream.html#tcp-echo-server-using-streams +RedirectTemp /15-8 https://lxml.de/ +RedirectTemp /15-9 https://docs.python.org/3/library/xml.etree.elementtree.html +RedirectTemp /15-10 https://mypy.readthedocs.io/en/stable/common_issues.html +RedirectTemp /15-11 https://mypy.readthedocs.io/en/stable/common_issues.html#types-of-empty-collections +RedirectTemp /15-12 https://github.com/python/typing/issues/182 +RedirectTemp /15-13 https://pypi.org/project/pydantic/ +RedirectTemp /15-14 https://mypy.readthedocs.io/en/stable/type_narrowing.html#casts +RedirectTemp /15-15 https://github.com/python/cpython/blob/bee66d3cb98e740f9d8057eb7f503122052ca5d8/Lib/typing.py#L1340 +RedirectTemp /15-16 https://www.python.org/dev/peps/pep-0484/#casts +RedirectTemp /15-17 https://github.com/python/typeshed/issues/5535 +RedirectTemp /15-18 https://docs.python.org/3/library/asyncio-stream.html#tcp-echo-server-using-streams +RedirectTemp /15-19 https://github.com/python/cpython/blob/b798ab06937f8bb24b444a49dd42e11fff15e654/Lib/test/test_asyncio/test_server.py#L55 RedirectTemp /15-20 https://en.wikipedia.org/wiki/Code_smell -RedirectTemp /15-21 https://mypy.readthedocs.io/en/stable/error_codes.html#error-codes -RedirectTemp /15-22 https://github.com/fluentpython/example-code-2e/blob/master/15-more-types/clip_annot.py +RedirectTemp /15-21 https://mail.python.org/archives/list/typing-sig@python.org/message/5LCWMN2UY2UQNLC5Z47GHBZKSPZW4I63/ +RedirectTemp /15-22 https://mypy.readthedocs.io/en/stable/error_codes.html#error-codes +RedirectTemp /15-23 https://github.com/fluentpython/example-code-2e/blob/master/15-more-types/clip_annot.py RedirectTemp /15-24 https://docs.python.org/3/library/typing.html#introspection-helpers RedirectTemp /15-25 https://docs.python.org/3.10/library/inspect.html#inspect.get_annotations -RedirectTemp /15-27 https://www.python.org/dev/peps/pep-0563/#abstract -RedirectTemp /15-29 https://docs.python.org/3.10/howto/annotations.html -RedirectTemp /15-32 https://docs.python.org/3/library/typing.html#user-defined-generic-types -RedirectTemp /15-33 https://docs.python.org/3.10/library/typing.html#typing.FrozenSet -RedirectTemp /15-34 https://docs.python.org/3.10/library/typing.html#typing.Generator -RedirectTemp /15-36 https://docs.python.org/3.10/library/typing.html#typing.AsyncGenerator -RedirectTemp /15-62 https://www.oreilly.com/library/view/robust-python/9781098100650/ -RedirectTemp /15-63 https://www.python.org/dev/peps/pep-0484/#covariance-and-contravariance -RedirectTemp /15-64 https://mypy.readthedocs.io/en/stable/generics.html#variance-of-generic-types -RedirectTemp /15-65 https://mypy.readthedocs.io/en/stable/common_issues.html#variance -RedirectTemp /15-67 https://www.artima.com/weblogs/viewpost.jsp?thread=85551 -RedirectTemp /15-68 https://dl.acm.org/action/cookieAbsent -RedirectTemp /15-69 http://bracha.org/pluggableTypesPosition.pdf -RedirectTemp /15-70 https://www.atomickotlin.com/atomickotlin/ -RedirectTemp /15-71 https://www.informit.com/store/effective-java-9780134685991 -RedirectTemp /15-72 https://www.manning.com/books/programming-with-types -RedirectTemp /15-73 https://www.oreilly.com/library/view/programming-typescript/9781492037644/ -RedirectTemp /15-74 https://www.informit.com/store/dart-programming-language-9780321927705 -RedirectTemp /15-75 https://www.yodaiken.com/2017/09/15/bad-ideas-in-type-theory/ -RedirectTemp /15-76 https://www.yodaiken.com/2017/11/30/types-considered-harmful-ii/ -RedirectTemp /15-77 https://web.archive.org/web/20071010002142/http://weblogs.java.net/blog/arnold/archive/2005/06/generics_consid_1.html -RedirectTemp /15-78 https://www.python.org/dev/peps/pep-0484/#covariance-and-contravariance +RedirectTemp /15-26 https://www.python.org/dev/peps/pep-0563/#abstract +RedirectTemp /15-27 https://mail.python.org/archives/list/python-dev@python.org/message/ZBJ7MD6CSGM6LZAOTET7GXAVBZB7O77O/ +RedirectTemp /15-28 https://docs.python.org/3.10/howto/annotations.html +RedirectTemp /15-29 https://docs.python.org/3/library/typing.html#user-defined-generic-types +RedirectTemp /15-30 https://github.com/python/typeshed/blob/bfc83c365a0b26ab16586beac77ff16729d0e473/stdlib/builtins.pyi#L743 +RedirectTemp /15-31 https://docs.python.org/3.10/library/typing.html#typing.FrozenSet +RedirectTemp /15-32 https://docs.python.org/3.10/library/typing.html#typing.Generator +RedirectTemp /15-33 https://docs.python.org/3.10/library/typing.html#typing.AsyncGenerator +RedirectTemp /15-34 https://github.com/python/cpython/blob/46b16d0bdbb1722daed10389e27226a2370f1635/Lib/typing.py#L1786 +RedirectTemp /15-35 https://github.com/python/typeshed/blob/2a9f081abbf01134e4e04ced6a750107db904d70/stdlib/builtins.pyi#L239 +RedirectTemp /15-36 https://www.oreilly.com/library/view/robust-python/9781098100650/ +RedirectTemp /15-37 https://www.python.org/dev/peps/pep-0484/#covariance-and-contravariance +RedirectTemp /15-38 https://mypy.readthedocs.io/en/stable/generics.html#variance-of-generic-types +RedirectTemp /15-39 https://mypy.readthedocs.io/en/stable/common_issues.html#variance +RedirectTemp /15-40 https://www.artima.com/weblogs/viewpost.jsp?thread=85551 +RedirectTemp /15-41 https://dl.acm.org/action/cookieAbsent +RedirectTemp /15-42 http://bracha.org/pluggableTypesPosition.pdf +RedirectTemp /15-43 https://www.researchgate.net/publication/213886116_Static_Typing_Where_Possible_Dynamic_Typing_When_Needed_The_End_of_the_Cold_War_Between_Programming_Languages +RedirectTemp /15-44 https://www.atomickotlin.com/atomickotlin/ +RedirectTemp /15-45 https://www.informit.com/store/effective-java-9780134685991 +RedirectTemp /15-46 https://www.manning.com/books/programming-with-types +RedirectTemp /15-47 https://www.oreilly.com/library/view/programming-typescript/9781492037644/ +RedirectTemp /15-48 https://www.informit.com/store/dart-programming-language-9780321927705 +RedirectTemp /15-49 https://www.yodaiken.com/2017/09/15/bad-ideas-in-type-theory/ +RedirectTemp /15-50 https://www.yodaiken.com/2017/11/30/types-considered-harmful-ii/ +RedirectTemp /15-51 https://web.archive.org/web/20071010002142/http://weblogs.java.net/blog/arnold/archive/2005/06/generics_consid_1.html +RedirectTemp /15-52 https://github.com/python/cpython/blob/3e7ee02327db13e4337374597cdc4458ecb9e3ad/Lib/asyncio/trsock.py#L5 +RedirectTemp /15-53 https://www.python.org/dev/peps/pep-0484/#covariance-and-contravariance ############################################################ 16 RedirectTemp /16-1 http://www.gotw.ca/publications/c_family_interview.htm RedirectTemp /16-2 https://docs.python.org/3/reference/expressions.html#unary-arithmetic-and-bitwise-operations +RedirectTemp /16-3 https://docs.python.org/3/reference/datamodel.html#object.__neg__ RedirectTemp /16-4 https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#boolean-indexing RedirectTemp /16-5 https://docs.python.org/3/library/collections.html#collections.Counter RedirectTemp /16-6 https://docs.python.org/3/reference/datamodel.html#emulating-container-types -RedirectTemp /16-8 https://docs.python.org/3/library/numbers.html#implementing-the-arithmetic-operations -RedirectTemp /16-10 https://www.fluentpython.com/lingo/#fail-fast -RedirectTemp /16-11 https://neopythonic.blogspot.com/2019/03/why-operators-are-useful.html -RedirectTemp /16-12 https://treyhunner.com/2019/03/python-deep-comparisons-and-code-readability/ -RedirectTemp /16-14 https://docs.python.org/3/library/numbers.html#implementing-the-arithmetic-operations -RedirectTemp /16-15 https://docs.python.org/3/library/pathlib.html -RedirectTemp /16-16 https://pypi.org/project/scapy/ -RedirectTemp /16-17 https://scapy.readthedocs.io/en/latest/usage.html#stacking-layers -RedirectTemp /16-18 https://docs.python.org/3/library/functools.html#functools.total_ordering -RedirectTemp /16-19 https://wiki.illinois.edu//wiki/download/attachments/273416327/ingalls.pdf -RedirectTemp /16-20 https://wiki.illinois.edu//wiki/download/attachments/273416327/double-dispatch.pdf -RedirectTemp /16-21 http://www.gotw.ca/publications/c_family_interview.htm -RedirectTemp /16-22 https://doc.rust-lang.org/std/ops/index.html -RedirectTemp /16-23 https://www.fluentpython.com/lingo/#lazy +RedirectTemp /16-7 https://docs.python.org/3/library/numbers.html#implementing-the-arithmetic-operations +RedirectTemp /16-8 https://www.fluentpython.com/lingo/#fail-fast +RedirectTemp /16-9 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Objects/typeobject.c#L4598 +RedirectTemp /16-10 https://neopythonic.blogspot.com/2019/03/why-operators-are-useful.html +RedirectTemp /16-11 https://treyhunner.com/2019/03/python-deep-comparisons-and-code-readability/ +RedirectTemp /16-12 https://docs.python.org/3/library/numbers.html#implementing-the-arithmetic-operations +RedirectTemp /16-13 https://docs.python.org/3/library/pathlib.html +RedirectTemp /16-14 https://pypi.org/project/scapy/ +RedirectTemp /16-15 https://scapy.readthedocs.io/en/latest/usage.html#stacking-layers +RedirectTemp /16-16 https://docs.python.org/3/library/functools.html#functools.total_ordering +RedirectTemp /16-17 https://wiki.illinois.edu//wiki/download/attachments/273416327/ingalls.pdf +RedirectTemp /16-18 https://wiki.illinois.edu//wiki/download/attachments/273416327/double-dispatch.pdf +RedirectTemp /16-19 http://www.gotw.ca/publications/c_family_interview.htm +RedirectTemp /16-20 http://www.gotw.ca/publications/c_family_interview.htm +RedirectTemp /16-21 https://doc.rust-lang.org/std/ops/index.html +RedirectTemp /16-22 https://www.fluentpython.com/lingo/#lazy ############################################################ 17 RedirectTemp /17-1 http://www.paulgraham.com/icad.html -RedirectTemp /17-5 https://en.wikipedia.org/wiki/Sentinel_value -RedirectTemp /17-6 https://docs.python.org/3.10/library/functions.html#iter -RedirectTemp /17-7 https://docs.python.org/3.10/library/functions.html#iter -RedirectTemp /17-8 https://github.com/python/cpython/blob/b1930bf75f276cd7ca08c4455298128d89adf7d1/Lib/_collections_abc.py#L271 -RedirectTemp /17-9 https://github.com/python/cpython/blob/main/Lib/types.py#L6 -RedirectTemp /17-10 https://en.wikipedia.org/wiki/CLU_(programming_language) -RedirectTemp /17-12 https://docs.python.org/3/glossary.html -RedirectTemp /17-13 https://docs.python.org/3/glossary.html#term-generator-iterator -RedirectTemp /17-14 https://docs.python.org/3/glossary.html#term-generator-expression -RedirectTemp /17-15 https://marc.info/?l=python-list&m=141826925106951&w=2 -RedirectTemp /17-17 https://docs.python.org/3/library/itertools.html -RedirectTemp /17-18 https://docs.python.org/3/library/exceptions.html#exception-hierarchy -RedirectTemp /17-19 https://en.wikipedia.org/wiki/Depth-first_search -RedirectTemp /17-20 https://docs.python.org/3.10/library/typing.html#typing.TypeAlias -RedirectTemp /17-22 https://docs.python.org/3/library/typing.html#typing.Generator -RedirectTemp /17-25 http://www.dabeaz.com/coroutines/Coroutines.pdf -RedirectTemp /17-26 http://www.dabeaz.com/coroutines/Coroutines.pdf -RedirectTemp /17-27 https://mail.python.org/pipermail/python-ideas/2009-April/003841.html -RedirectTemp /17-28 https://mail.python.org/pipermail/python-ideas/2009-April/003912.html -RedirectTemp /17-31 https://docs.python.org/3/library/exceptions.html#StopIteration -RedirectTemp /17-32 https://docs.python.org/3/reference/expressions.html#yield-expressions -RedirectTemp /17-33 https://docs.python.org/3/reference/index.html -RedirectTemp /17-36 http://catb.org/~esr/jargon/html/G/grok.html -RedirectTemp /17-37 https://docs.python.org/3/reference/expressions.html#yieldexpr -RedirectTemp /17-39 https://docs.python.org/3/library/itertools.html#itertools-recipes -RedirectTemp /17-40 https://more-itertools.readthedocs.io/en/stable/index.html -RedirectTemp /17-41 https://rittau.org/2006/11/java-iterators-are-not-iterable/ -RedirectTemp /17-42 https://docs.python.org/3/whatsnew/3.3.html#pep-380-syntax-for-delegating-to-a-subgenerator -RedirectTemp /17-45 http://www.dabeaz.com/generators/ -RedirectTemp /17-46 http://www.dabeaz.com/coroutines/ -RedirectTemp /17-47 https://archive.org/details/pyvideo_213___pycon-2009-a-curious-course-on-coroutines-and-concurrency-part-1-of-3 -RedirectTemp /17-48 https://archive.org/details/pyvideo_215___pycon-2009-a-curious-course-on-coroutines-and-concurrency-part-2-of-3 -RedirectTemp /17-49 https://archive.org/details/pyvideo_214___pycon-2009-a-curious-course-on-coroutines-and-concurrency-part-3-of-3 -RedirectTemp /17-50 http://www.dabeaz.com/finalgenerator/ -RedirectTemp /17-51 https://web.archive.org/web/20200218150637/http://seriously.dontusethiscode.com/2013/05/01/greedy-coroutine.html -RedirectTemp /17-52 https://effectivepython.com/ -RedirectTemp /17-53 https://effectivepython.com/2015/03/10/consider-coroutines-to-run-many-functions-concurrently -RedirectTemp /17-54 https://en.wikipedia.org/wiki/Conway's_Game_of_Life -RedirectTemp /17-55 https://gist.github.com/ramalho/da5590bc38c973408839 -RedirectTemp /17-56 https://gist.github.com/ramalho/da5590bc38c973408839 -RedirectTemp /17-57 https://journal.code4lib.org/articles/4893 -RedirectTemp /17-58 https://github.com/fluentpython/isis2json -RedirectTemp /17-59 https://github.com/fluentpython/isis2json/blob/master/README.rst +RedirectTemp /17-2 https://en.wikipedia.org/wiki/Sentinel_value +RedirectTemp /17-3 https://docs.python.org/3.10/library/functions.html#iter +RedirectTemp /17-4 https://docs.python.org/3.10/library/functions.html#iter +RedirectTemp /17-5 https://github.com/python/cpython/blob/b1930bf75f276cd7ca08c4455298128d89adf7d1/Lib/_collections_abc.py#L271 +RedirectTemp /17-6 https://github.com/python/cpython/blob/main/Lib/types.py#L6 +RedirectTemp /17-7 https://en.wikipedia.org/wiki/CLU_(programming_language) +RedirectTemp /17-8 https://docs.python.org/3/glossary.html +RedirectTemp /17-9 https://docs.python.org/3/glossary.html#term-generator-iterator +RedirectTemp /17-10 https://docs.python.org/3/glossary.html#term-generator-expression +RedirectTemp /17-11 https://marc.info/?l=python-list&m=141826925106951&w=2 +RedirectTemp /17-12 https://docs.python.org/3/library/os.html#os.walk +RedirectTemp /17-13 https://docs.python.org/3/library/itertools.html +RedirectTemp /17-14 https://docs.python.org/3/library/exceptions.html#exception-hierarchy +RedirectTemp /17-15 https://en.wikipedia.org/wiki/Depth-first_search +RedirectTemp /17-16 https://docs.python.org/3.10/library/typing.html#typing.TypeAlias +RedirectTemp /17-17 https://docs.python.org/3/library/typing.html#typing.Generator +RedirectTemp /17-18 http://www.dabeaz.com/coroutines/Coroutines.pdf +RedirectTemp /17-19 http://www.dabeaz.com/coroutines/Coroutines.pdf +RedirectTemp /17-20 https://mail.python.org/pipermail/python-ideas/2009-April/003841.html +RedirectTemp /17-21 https://mail.python.org/pipermail/python-ideas/2009-April/003912.html +RedirectTemp /17-22 https://docs.python.org/3/library/exceptions.html#StopIteration +RedirectTemp /17-23 https://docs.python.org/3/reference/expressions.html#yield-expressions +RedirectTemp /17-24 https://docs.python.org/3/reference/index.html +RedirectTemp /17-25 https://github.com/python/cpython/blob/6f743e7a4da904f61dfa84cc7d7385e4dcc79ac5/Lib/typing.py#L2060 +RedirectTemp /17-26 http://catb.org/~esr/jargon/html/G/grok.html +RedirectTemp /17-27 https://docs.python.org/3/reference/expressions.html#yieldexpr +RedirectTemp /17-28 https://docs.python.org/3/library/itertools.html +RedirectTemp /17-29 https://docs.python.org/3/library/itertools.html#itertools-recipes +RedirectTemp /17-30 https://more-itertools.readthedocs.io/en/stable/index.html +RedirectTemp /17-31 https://rittau.org/2006/11/java-iterators-are-not-iterable/ +RedirectTemp /17-32 https://docs.python.org/3/whatsnew/3.3.html#pep-380-syntax-for-delegating-to-a-subgenerator +RedirectTemp /17-33 http://www.dabeaz.com/generators/ +RedirectTemp /17-34 http://www.dabeaz.com/coroutines/ +RedirectTemp /17-35 https://archive.org/details/pyvideo_213___pycon-2009-a-curious-course-on-coroutines-and-concurrency-part-1-of-3 +RedirectTemp /17-36 https://archive.org/details/pyvideo_215___pycon-2009-a-curious-course-on-coroutines-and-concurrency-part-2-of-3 +RedirectTemp /17-37 https://archive.org/details/pyvideo_214___pycon-2009-a-curious-course-on-coroutines-and-concurrency-part-3-of-3 +RedirectTemp /17-38 http://www.dabeaz.com/finalgenerator/ +RedirectTemp /17-39 https://web.archive.org/web/20200218150637/http://seriously.dontusethiscode.com/2013/05/01/greedy-coroutine.html +RedirectTemp /17-40 https://effectivepython.com/ +RedirectTemp /17-41 https://effectivepython.com/2015/03/10/consider-coroutines-to-run-many-functions-concurrently +RedirectTemp /17-42 https://en.wikipedia.org/wiki/Conway's_Game_of_Life +RedirectTemp /17-43 https://gist.github.com/ramalho/da5590bc38c973408839 +RedirectTemp /17-44 https://gist.github.com/ramalho/da5590bc38c973408839 +RedirectTemp /17-45 https://journal.code4lib.org/articles/4893 +RedirectTemp /17-46 https://github.com/fluentpython/isis2json +RedirectTemp /17-47 https://github.com/fluentpython/isis2json/blob/master/README.rst ############################################################ 18 RedirectTemp /18-1 https://pyvideo.org/video/1669/keynote-3/ RedirectTemp /18-2 https://docs.python.org/3/library/sqlite3.html#using-the-connection-as-a-context-manager @@ -678,42 +726,53 @@ RedirectTemp /18-4 https://docs.python.org/3/library/decimal.html#decimal.localc RedirectTemp /18-5 https://docs.python.org/3/library/unittest.mock.html#patch RedirectTemp /18-6 https://docs.python.org/3/library/contextlib.html#contextlib.redirect_stdout RedirectTemp /18-7 https://docs.python.org/3/library/sys.html#sys.exc_info -RedirectTemp /18-9 https://en.wikipedia.org/wiki/LL_parser -RedirectTemp /18-10 https://docs.python.org/3/library/contextlib.html +RedirectTemp /18-8 https://en.wikipedia.org/wiki/LL_parser +RedirectTemp /18-9 https://docs.python.org/3/library/contextlib.html +RedirectTemp /18-10 https://github.com/python/cpython/blob/8afab2ebbc1b343cd88d058914cf622fe687a2be/Lib/contextlib.py#L123 RedirectTemp /18-11 https://www.zopatista.com/python/2013/11/26/inplace-file-rewriting/ RedirectTemp /18-12 https://docs.python.org/3/library/fileinput.html#fileinput.input RedirectTemp /18-13 https://www.zopatista.com/python/2013/11/26/inplace-file-rewriting/ RedirectTemp /18-14 https://en.wikipedia.org/wiki/Euclidean_algorithm RedirectTemp /18-15 https://github.com/fluentpython/example-code-2e/tree/master/18-with-match/lispy/py3.10/ -RedirectTemp /18-17 https://github.com/python/typeshed/issues/6042 -RedirectTemp /18-18 https://github.com/fluentpython/lispy/tree/main/mylis -RedirectTemp /18-19 https://mitpress.mit.edu/sites/default/files/sicp/index.html -RedirectTemp /18-20 https://www.python.org/dev/peps/pep-0634/#or-patterns -RedirectTemp /18-21 https://en.wikipedia.org/wiki/Lambda#Character_encodings -RedirectTemp /18-22 https://docs.python.org/3/reference/compound_stmts.html -RedirectTemp /18-23 https://docs.python.org/3/glossary.html#term-eafp -RedirectTemp /18-24 https://speakerdeck.com/pyconslides/pycon-keynote-python-is-awesome-by-raymond-hettinger?slide=21 -RedirectTemp /18-25 https://docs.python.org/3/reference/compound_stmts.html -RedirectTemp /18-26 https://stackoverflow.com/questions/16138232/is-it-a-good-practice-to-use-try-except-else-in-python -RedirectTemp /18-27 https://docs.python.org/3/library/stdtypes.html#typecontextmanager -RedirectTemp /18-28 https://docs.python.org/3/reference/datamodel.html#with-statement-context-managers -RedirectTemp /18-30 https://speakerdeck.com/pyconslides/pycon-keynote-python-is-awesome-by-raymond-hettinger?slide=21 -RedirectTemp /18-31 https://speakerdeck.com/pyconslides/transforming-code-into-beautiful-idiomatic-python-by-raymond-hettinger-1?slide=34 -RedirectTemp /18-32 https://preshing.com/20110920/the-python-with-statement-by-example/ -RedirectTemp /18-33 https://www.rath.org/on-the-beauty-of-pythons-exitstack.html -RedirectTemp /18-34 https://github.com/norvig/pytudes -RedirectTemp /18-35 https://github.com/fluentpython/lispy -RedirectTemp /18-36 https://racket-lang.org/ -RedirectTemp /18-37 https://pyvideo.org/video/1669/keynote-3/ -RedirectTemp /18-38 https://en.wikipedia.org/wiki/Tail_call -RedirectTemp /18-39 https://2ality.com/2015/06/tail-call-optimization.html -RedirectTemp /18-40 http://neopythonic.blogspot.com/2009/04/final-words-on-tail-calls.html -RedirectTemp /18-41 https://webkit.org/blog/6240/ecmascript-6-proper-tail-calls-in-webkit/ -RedirectTemp /18-42 http://kangax.github.io/compat-table/es6/ -RedirectTemp /18-43 https://world.hey.com/mgmarlow/what-happened-to-proper-tail-calls-in-javascript-5494c256 -RedirectTemp /18-44 http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html -RedirectTemp /18-45 https://github.com/fluentpython/lispy/blob/main/mylis/mylis_2/lis.py -RedirectTemp /18-46 https://github.com/fluentpython/lispy/tree/main/mylis +RedirectTemp /18-16 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/original/lispy.py +RedirectTemp /18-17 https://github.com/fluentpython/example-code-2e/blob/6527037ae7319ba370a1ee2d9fe79214d0ed9452/18-with-match/lispy/py3.10/lis.py#L35 +RedirectTemp /18-18 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/py3.10/examples_test.py +RedirectTemp /18-19 https://github.com/python/typeshed/issues/6042 +RedirectTemp /18-20 https://github.com/fluentpython/lispy/tree/main/mylis +RedirectTemp /18-21 https://github.com/fluentpython/example-code-2e/blob/00e4741926e1b771ee7c753148b1415c0bd12e39/02-array-seq/lispy/py3.10/examples_test.py +RedirectTemp /18-22 https://mitpress.mit.edu/sites/default/files/sicp/index.html +RedirectTemp /18-23 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/py3.10/examples_test.py +RedirectTemp /18-24 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/py3.10/lis.py +RedirectTemp /18-25 https://www.python.org/dev/peps/pep-0634/#or-patterns +RedirectTemp /18-26 https://en.wikipedia.org/wiki/Lambda#Character_encodings +RedirectTemp /18-27 https://docs.python.org/3/reference/compound_stmts.html +RedirectTemp /18-28 https://docs.python.org/3/glossary.html#term-eafp +RedirectTemp /18-29 https://speakerdeck.com/pyconslides/pycon-keynote-python-is-awesome-by-raymond-hettinger?slide=21 +RedirectTemp /18-30 https://docs.python.org/3/reference/compound_stmts.html +RedirectTemp /18-31 https://stackoverflow.com/questions/16138232/is-it-a-good-practice-to-use-try-except-else-in-python +RedirectTemp /18-32 https://docs.python.org/3/library/stdtypes.html#typecontextmanager +RedirectTemp /18-33 https://docs.python.org/3/reference/datamodel.html#with-statement-context-managers +RedirectTemp /18-34 https://speakerdeck.com/pyconslides/pycon-keynote-python-is-awesome-by-raymond-hettinger?slide=21 +RedirectTemp /18-35 https://speakerdeck.com/pyconslides/transforming-code-into-beautiful-idiomatic-python-by-raymond-hettinger-1?slide=34 +RedirectTemp /18-36 https://preshing.com/20110920/the-python-with-statement-by-example/ +RedirectTemp /18-37 https://www.rath.org/on-the-beauty-of-pythons-exitstack.html +RedirectTemp /18-38 https://norvig.com/lispy.html +RedirectTemp /18-39 https://norvig.com/lispy2.html +RedirectTemp /18-40 https://github.com/norvig/pytudes +RedirectTemp /18-41 https://github.com/fluentpython/lispy +RedirectTemp /18-42 https://racket-lang.org/ +RedirectTemp /18-43 https://pyvideo.org/video/1669/keynote-3/ +RedirectTemp /18-44 https://en.wikipedia.org/wiki/Tail_call +RedirectTemp /18-45 https://2ality.com/2015/06/tail-call-optimization.html +RedirectTemp /18-46 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/original/lis.py +RedirectTemp /18-47 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/original/lispy.py +RedirectTemp /18-48 http://neopythonic.blogspot.com/2009/04/final-words-on-tail-calls.html +RedirectTemp /18-49 https://webkit.org/blog/6240/ecmascript-6-proper-tail-calls-in-webkit/ +RedirectTemp /18-50 http://kangax.github.io/compat-table/es6/ +RedirectTemp /18-51 https://world.hey.com/mgmarlow/what-happened-to-proper-tail-calls-in-javascript-5494c256 +RedirectTemp /18-52 http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html +RedirectTemp /18-53 https://github.com/fluentpython/lispy/blob/main/mylis/mylis_2/lis.py +RedirectTemp /18-54 https://github.com/fluentpython/lispy/tree/main/mylis ############################################################ 19 RedirectTemp /19-1 https://go.dev/blog/waza-talk RedirectTemp /19-2 https://en.wikipedia.org/wiki/Graphics_processing_unit @@ -721,69 +780,81 @@ RedirectTemp /19-3 https://docs.python.org/3/library/sys.html#sys.getswitchinter RedirectTemp /19-4 https://docs.python.org/3/library/sys.html#sys.setswitchinterval RedirectTemp /19-5 https://en.wikipedia.org/wiki/System_call RedirectTemp /19-6 https://mail.python.org/pipermail/python-dev/2009-October/093356.html -RedirectTemp /19-8 http://www.dabeaz.com/finalgenerator/ -RedirectTemp /19-9 https://docs.python.org/3/library/threading.html#thread-objects -RedirectTemp /19-10 https://www.pypy.org/ -RedirectTemp /19-11 https://mail.python.org/pipermail/python-list/2009-February/675659.html -RedirectTemp /19-12 https://en.wikipedia.org/wiki/Braille_Patterns -RedirectTemp /19-13 https://docs.python.org/3/library/multiprocessing.shared_memory.html +RedirectTemp /19-7 http://www.dabeaz.com/finalgenerator/ +RedirectTemp /19-8 https://docs.python.org/3/library/threading.html#thread-objects +RedirectTemp /19-9 https://www.pypy.org/ +RedirectTemp /19-10 https://mail.python.org/pipermail/python-list/2009-February/675659.html +RedirectTemp /19-11 https://en.wikipedia.org/wiki/Braille_Patterns +RedirectTemp /19-12 https://docs.python.org/3/library/multiprocessing.shared_memory.html +RedirectTemp /19-13 https://docs.python.org/3/library/multiprocessing.shared_memory.html#multiprocessing.shared_memory.ShareableList RedirectTemp /19-14 https://greenlet.readthedocs.io/en/latest/ -RedirectTemp /19-15 https://docs.sqlalchemy.org/en/14/orm/extensions/asyncio.html -RedirectTemp /19-16 http://www.gevent.org/ -RedirectTemp /19-17 https://github.com/gevent/gevent/wiki/Projects +RedirectTemp /19-15 https://docs.sqlalchemy.org/en/14/changelog/migration_14.html#asynchronous-io-support-for-core-and-orm +RedirectTemp /19-16 https://docs.sqlalchemy.org/en/14/orm/extensions/asyncio.html +RedirectTemp /19-17 http://www.gevent.org/ +RedirectTemp /19-18 https://github.com/gevent/gevent/wiki/Projects RedirectTemp /19-19 https://docs.python.org/3/library/concurrent.futures.html#processpoolexecutor-example RedirectTemp /19-20 https://github.com/python/asyncio/issues/284 RedirectTemp /19-21 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor +RedirectTemp /19-22 https://mail.python.org/archives/list/python-dev@python.org/message/JBYXQH3NV3YBF7P2HLHB5CD6V3GVTY55/ RedirectTemp /19-23 https://docs.python.org/3/library/queue.html#queue.SimpleQueue.get RedirectTemp /19-24 https://en.wikipedia.org/wiki/Race_condition -RedirectTemp /19-26 https://en.wikipedia.org/wiki/Context_switch -RedirectTemp /19-27 http://www.gotw.ca/publications/concurrency-ddj.htm -RedirectTemp /19-28 https://www.ansible.com/ -RedirectTemp /19-29 https://saltproject.io/ -RedirectTemp /19-30 https://www.fabfile.org/ -RedirectTemp /19-31 https://jupyter.org/ -RedirectTemp /19-32 https://docs.bokeh.org/en/latest/index.html -RedirectTemp /19-33 https://www.tensorflow.org/ -RedirectTemp /19-34 https://pytorch.org/ -RedirectTemp /19-35 https://www.oreilly.com/radar/where-programming-ops-ai-and-the-cloud-are-headed-in-2021/ -RedirectTemp /19-38 https://www.youtube.com/watch?v=ods97a5Pzw0 -RedirectTemp /19-39 https://www.thoughtworks.com/radar/techniques/high-performance-envy-web-scale-envy +RedirectTemp /19-25 https://github.com/fluentpython/example-code-2e/commit/2c1230579db99738a5e5e6802063bda585f6476d +RedirectTemp /19-26 https://github.com/fluentpython/example-code-2e/blob/master/19-concurrency/primes/README.md +RedirectTemp /19-27 https://github.com/fluentpython/example-code-2e/blob/master/19-concurrency/primes/threads.py +RedirectTemp /19-28 https://en.wikipedia.org/wiki/Context_switch +RedirectTemp /19-29 http://www.gotw.ca/publications/concurrency-ddj.htm +RedirectTemp /19-30 https://www.ansible.com/ +RedirectTemp /19-31 https://saltproject.io/ +RedirectTemp /19-32 https://www.fabfile.org/ +RedirectTemp /19-33 https://engineering.fb.com/2016/05/27/production-engineering/python-in-production-engineering/ +RedirectTemp /19-34 https://jupyter.org/ +RedirectTemp /19-35 https://docs.bokeh.org/en/latest/index.html +RedirectTemp /19-36 https://www.tensorflow.org/ +RedirectTemp /19-37 https://pytorch.org/ +RedirectTemp /19-38 https://www.oreilly.com/radar/where-programming-ops-ai-and-the-cloud-are-headed-in-2021/ +RedirectTemp /19-39 https://www.youtube.com/watch?v=ods97a5Pzw0 +RedirectTemp /19-40 https://www.thoughtworks.com/radar/techniques/high-performance-envy-web-scale-envy RedirectTemp /19-41 https://modwsgi.readthedocs.io/en/master/ RedirectTemp /19-42 https://uwsgi-docs.readthedocs.io/en/latest/ -RedirectTemp /19-44 https://unit.nginx.org/ -RedirectTemp /19-45 https://www.techatbloomberg.com/blog/configuring-uwsgi-production-deployment/ -RedirectTemp /19-46 https://www.youtube.com/watch?v=p6R1h2Nn468 -RedirectTemp /19-47 https://asgi.readthedocs.io/en/latest/index.html -RedirectTemp /19-48 https://docs.celeryproject.org/en/stable/getting-started/introduction.html -RedirectTemp /19-49 https://python-rq.org/ +RedirectTemp /19-43 https://unit.nginx.org/ +RedirectTemp /19-44 https://www.techatbloomberg.com/blog/configuring-uwsgi-production-deployment/ +RedirectTemp /19-45 https://www.youtube.com/watch?v=p6R1h2Nn468 +RedirectTemp /19-46 https://asgi.readthedocs.io/en/latest/index.html +RedirectTemp /19-47 https://docs.celeryproject.org/en/stable/getting-started/introduction.html +RedirectTemp /19-48 https://python-rq.org/ +RedirectTemp /19-49 https://docs.celeryproject.org/en/stable/faq.html#what-kinds-of-things-should-i-use-celery-for RedirectTemp /19-50 https://redis.io/ RedirectTemp /19-51 https://realpython.com/intro-to-python-threading/ RedirectTemp /19-52 https://pymotw.com/3/concurrency.html +RedirectTemp /19-53 https://www.pearson.com/us/higher-education/program/Hellmann-Python-3-Standard-Library-by-Example-The/PGM328871.html RedirectTemp /19-54 https://docs.python.org/3/library/multiprocessing.html#programming-guidelines -RedirectTemp /19-56 https://docs.python.org/3/library/multiprocessing.html -RedirectTemp /19-57 https://www.oreilly.com/library/view/high-performance-python/9781492055013/ -RedirectTemp /19-58 https://link.springer.com/book/10.1007/978-1-4842-5793-7?error=cookies_not_supported&code=2ed5d61d-ae9f-4f3d-94ac-0f68cf45ea4f -RedirectTemp /19-59 https://www.packtpub.com/product/parallel-programming-with-python/9781783288397 -RedirectTemp /19-61 https://greenteapress.com/wp/semaphores/ -RedirectTemp /19-62 https://docs.python.org/3/c-api/init.html#thread-state-and-the-global-interpreter-lock -RedirectTemp /19-63 https://www.artima.com/weblogs/viewpost.jsp?thread=214235 -RedirectTemp /19-64 http://jessenoller.com/blog/2009/02/01/python-threads-and-the-global-interpreter-lock -RedirectTemp /19-65 https://realpython.com/products/cpython-internals-book/ -RedirectTemp /19-66 http://www.dabeaz.com/GIL/ -RedirectTemp /19-67 http://www.dabeaz.com/python/UnderstandingGIL.pdf -RedirectTemp /19-68 https://bugs.python.org/issue7946#msg223110 -RedirectTemp /19-69 https://bugs.python.org/issue7946 -RedirectTemp /19-70 https://www.fullstackpython.com/ -RedirectTemp /19-71 https://www.oreilly.com/library/view/high-performance-python/9781492055013/ -RedirectTemp /19-72 https://www.packtpub.com/product/parallel-programming-with-python/9781783288397 -RedirectTemp /19-73 https://www.packtpub.com/product/distributed-computing-with-python/9781785889691 -RedirectTemp /19-74 https://towardsdatascience.com/python-performance-and-gpus-1be860ffd58d?gi=6a57a172ab5e +RedirectTemp /19-55 https://docs.python.org/3/library/multiprocessing.html +RedirectTemp /19-56 https://www.oreilly.com/library/view/high-performance-python/9781492055013/ +RedirectTemp /19-57 https://link.springer.com/book/10.1007/978-1-4842-5793-7?error=cookies_not_supported&code=2ed5d61d-ae9f-4f3d-94ac-0f68cf45ea4f +RedirectTemp /19-58 https://www.packtpub.com/product/parallel-programming-with-python/9781783288397 +RedirectTemp /19-59 https://greenteapress.com/wp/semaphores/ +RedirectTemp /19-60 https://docs.python.org/3/c-api/init.html#thread-state-and-the-global-interpreter-lock +RedirectTemp /19-61 https://docs.python.org/3/faq/library.html#can-t-we-get-rid-of-the-global-interpreter-lock +RedirectTemp /19-62 https://www.artima.com/weblogs/viewpost.jsp?thread=214235 +RedirectTemp /19-63 http://jessenoller.com/blog/2009/02/01/python-threads-and-the-global-interpreter-lock +RedirectTemp /19-64 https://realpython.com/products/cpython-internals-book/ +RedirectTemp /19-65 http://www.dabeaz.com/GIL/ +RedirectTemp /19-66 http://www.dabeaz.com/python/UnderstandingGIL.pdf +RedirectTemp /19-67 https://bugs.python.org/issue7946#msg223110 +RedirectTemp /19-68 https://bugs.python.org/issue7946 +RedirectTemp /19-69 https://www.fullstackpython.com/ +RedirectTemp /19-70 https://www.oreilly.com/library/view/high-performance-python/9781492055013/ +RedirectTemp /19-71 https://www.packtpub.com/product/parallel-programming-with-python/9781783288397 +RedirectTemp /19-72 https://www.packtpub.com/product/distributed-computing-with-python/9781785889691 +RedirectTemp /19-73 https://towardsdatascience.com/python-performance-and-gpus-1be860ffd58d?gi=a7d537cc2fb4 +RedirectTemp /19-74 https://instagram-engineering.com/web-service-efficiency-at-instagram-with-python-4976d078e366?gi=12a441991c88 RedirectTemp /19-75 https://www.oreilly.com/library/view/architecture-patterns-with/9781492052197/ RedirectTemp /19-76 https://www.cosmicpython.com/ RedirectTemp /19-77 https://pypi.org/project/lelo/ RedirectTemp /19-78 https://github.com/npryce/python-parallelize RedirectTemp /19-79 https://github.com/ericsnowcurrently/multi-core-python/wiki -RedirectTemp /19-81 https://gist.github.com/markshannon/79cace3656b40e21b7021504daee950c +RedirectTemp /19-80 https://gist.github.com/markshannon/79cace3656b40e21b7021504daee950c +RedirectTemp /19-81 https://mail.python.org/archives/list/python-dev@python.org/message/YOOQZCFOKEPQ24YHWWLQSJ3RCXFMS7D7/ RedirectTemp /19-82 https://en.wikipedia.org/wiki/Communicating_sequential_processes RedirectTemp /19-83 https://github.com/stackless-dev/stackless/wiki RedirectTemp /19-84 https://www.eveonline.com @@ -792,14 +863,15 @@ RedirectTemp /19-86 https://stackless.readthedocs.io/en/3.6-slp/stackless-python RedirectTemp /19-87 https://doc.pypy.org/en/latest/stackless.html RedirectTemp /19-88 https://greenlet.readthedocs.io/en/latest/ RedirectTemp /19-89 http://www.gevent.org/ -RedirectTemp /19-91 http://thespianpy.com/doc/ -RedirectTemp /19-92 https://pykka.readthedocs.io/en/latest/ -RedirectTemp /19-93 https://www.manning.com/books/rabbitmq-in-action -RedirectTemp /19-94 https://pragprog.com/titles/pb7con/seven-concurrency-models-in-seven-weeks/ -RedirectTemp /19-95 https://en.wikipedia.org/wiki/OpenCL -RedirectTemp /19-96 https://media.pragprog.com/titles/pb7con/Bonus_Chapter.pdf -RedirectTemp /19-97 https://martinfowler.com/ -RedirectTemp /19-98 https://martinfowler.com/articles/patterns-of-distributed-systems/ +RedirectTemp /19-90 http://thespianpy.com/doc/ +RedirectTemp /19-91 https://pykka.readthedocs.io/en/latest/ +RedirectTemp /19-92 https://www.manning.com/books/rabbitmq-in-action +RedirectTemp /19-93 https://pragprog.com/titles/pb7con/seven-concurrency-models-in-seven-weeks/ +RedirectTemp /19-94 https://en.wikipedia.org/wiki/OpenCL +RedirectTemp /19-95 https://media.pragprog.com/titles/pb7con/Bonus_Chapter.pdf +RedirectTemp /19-96 https://martinfowler.com/ +RedirectTemp /19-97 https://martinfowler.com/articles/patterns-of-distributed-systems/ +RedirectTemp /19-98 https://www.oreilly.com/library/view/designing-data-intensive-applications/9781491903063/ RedirectTemp /19-99 https://www.oreilly.com/library/view/oscon-2016-video/9781491965153/video247021.html RedirectTemp /19-100 https://www.oreilly.com/library/view/designing-for-scalability/9781449361556/ RedirectTemp /19-101 https://www.thoughtworks.com/radar/techniques/high-performance-envy-web-scale-envy @@ -807,176 +879,191 @@ RedirectTemp /19-102 https://en.wikipedia.org/wiki/KISS_principle RedirectTemp /19-103 https://www.usenix.org/conference/hotos15/workshop-program/presentation/mcsherry ############################################################ 20 RedirectTemp /20-1 https://www.artima.com/weblogs/viewpost.jsp?thread=299551 -RedirectTemp /20-3 https://docs.python.org/3/library/http.server.html -RedirectTemp /20-4 https://www.youtube.com/watch?v=A9e9Cy1UkME -RedirectTemp /20-5 https://www.cia.gov/the-world-factbook/ -RedirectTemp /20-7 https://docs.python-requests.org/en/latest/ -RedirectTemp /20-8 https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.as_completed -RedirectTemp /20-9 https://docs.python.org/3/library/concurrent.futures.html -RedirectTemp /20-10 https://docs.python.org/3.10/library/concurrent.futures.html#concurrent.futures.Executor -RedirectTemp /20-12 https://github.com/noamraph/tqdm -RedirectTemp /20-13 https://www.youtube.com/watch?v=M8Z65tAl5l4 -RedirectTemp /20-14 https://github.com/noamraph/tqdm/blob/master/README.md -RedirectTemp /20-15 https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.as_completed -RedirectTemp /20-16 https://docs.python.org/3/library/asyncio-task.html#asyncio.as_completed -RedirectTemp /20-17 https://www.cloudflare.com/ -RedirectTemp /20-19 https://github.com/fluentpython/example-code-2e/tree/master/20-executors/getflags -RedirectTemp /20-21 https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/418 -RedirectTemp /20-22 https://en.wikipedia.org/wiki/Embarrassingly_parallel -RedirectTemp /20-23 https://pyvideo.org/video/480/pyconau-2010--the-future-is-soon/ -RedirectTemp /20-25 http://www.dabeaz.com/coroutines/ -RedirectTemp /20-26 https://en.wikipedia.org/wiki/POSIX_Threads -RedirectTemp /20-27 https://en.wikipedia.org/wiki/C_dynamic_memory_allocation -RedirectTemp /20-28 https://pragprog.com/titles/pb7con/seven-concurrency-models-in-seven-weeks/ -RedirectTemp /20-29 https://hexdocs.pm/ecto/getting-started.html +RedirectTemp /20-2 https://docs.python.org/3/library/http.server.html +RedirectTemp /20-3 https://www.youtube.com/watch?v=A9e9Cy1UkME +RedirectTemp /20-4 https://www.cia.gov/the-world-factbook/ +RedirectTemp /20-5 https://docs.python-requests.org/en/latest/ +RedirectTemp /20-6 https://docs.python.org/3.10/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor +RedirectTemp /20-7 https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.as_completed +RedirectTemp /20-8 https://docs.python.org/3/library/concurrent.futures.html +RedirectTemp /20-9 https://docs.python.org/3.10/library/concurrent.futures.html#concurrent.futures.Executor +RedirectTemp /20-10 https://github.com/fluentpython/example-code-2e/blob/master/20-executors/getflags/flags2_common.py +RedirectTemp /20-11 https://github.com/noamraph/tqdm +RedirectTemp /20-12 https://www.youtube.com/watch?v=M8Z65tAl5l4 +RedirectTemp /20-13 https://github.com/noamraph/tqdm/blob/master/README.md +RedirectTemp /20-14 https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.as_completed +RedirectTemp /20-15 https://docs.python.org/3/library/asyncio-task.html#asyncio.as_completed +RedirectTemp /20-16 https://www.cloudflare.com/ +RedirectTemp /20-17 https://github.com/fluentpython/example-code-2e/tree/master/20-executors/getflags +RedirectTemp /20-18 https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/418 +RedirectTemp /20-19 https://en.wikipedia.org/wiki/Embarrassingly_parallel +RedirectTemp /20-20 https://pyvideo.org/video/480/pyconau-2010--the-future-is-soon/ +RedirectTemp /20-21 http://www.dabeaz.com/coroutines/ +RedirectTemp /20-22 https://en.wikipedia.org/wiki/POSIX_Threads +RedirectTemp /20-23 https://en.wikipedia.org/wiki/C_dynamic_memory_allocation +RedirectTemp /20-24 https://pragprog.com/titles/pb7con/seven-concurrency-models-in-seven-weeks/ +RedirectTemp /20-25 https://hexdocs.pm/ecto/getting-started.html ############################################################ 21 RedirectTemp /21-1 https://docs.python.org/3/library/asyncio.html -RedirectTemp /21-6 https://bugs.python.org/issue43216 -RedirectTemp /21-7 https://bugs.python.org/issue36921 -RedirectTemp /21-8 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.getaddrinfo -RedirectTemp /21-9 https://docs.python.org/3/library/socket.html#socket.getaddrinfo -RedirectTemp /21-10 https://docs.python.org/3.10/library/asyncio-eventloop.html#asyncio.get_event_loop -RedirectTemp /21-11 https://www.python.org/dev/peps/pep-0492/#await-expression -RedirectTemp /21-14 https://www.fluentpython.com/extra/classic-coroutines/#yield_from_meaning_sec -RedirectTemp /21-17 https://github.com/fluentpython/example-code-2e/tree/master/20-executors/getflags -RedirectTemp /21-18 https://magicstack.github.io/asyncpg/current/ -RedirectTemp /21-19 https://magicstack.github.io/asyncpg/current/api/index.html#transactions -RedirectTemp /21-21 https://magicstack.github.io/asyncpg/current/api/index.html#transactions -RedirectTemp /21-22 https://magicstack.github.io/asyncpg/current/usage.html#connection-pools -RedirectTemp /21-23 https://gist.github.com/jboner/2841832 -RedirectTemp /21-24 https://en.wikipedia.org/wiki/Network-attached_storage -RedirectTemp /21-25 https://en.wikipedia.org/wiki/Semaphore_(programming) -RedirectTemp /21-26 https://en.wikipedia.org/wiki/Semaphore_(programming) -RedirectTemp /21-27 https://groups.google.com/forum/#!msg/python-tulip/PdAEtwpaJHs/7fqb-Qj2zJoJ -RedirectTemp /21-28 https://tritarget.org/#blog/2012/11/28/the-pyramid-of-doom-a-javascript-style-trap -RedirectTemp /21-29 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor -RedirectTemp /21-30 https://motor.readthedocs.io/en/stable/ -RedirectTemp /21-31 https://emptysqua.re/blog/response-to-asynchronous-python-and-databases/ -RedirectTemp /21-33 https://docs.python.org/3/library/asyncio-stream.html#tcp-echo-server-using-streams -RedirectTemp /21-35 https://en.wikipedia.org/wiki/Phaistos_Disc -RedirectTemp /21-36 https://en.wikipedia.org/wiki/Inverted_index -RedirectTemp /21-37 https://fastapi.tiangolo.com/ -RedirectTemp /21-38 https://swagger.io/specification/ -RedirectTemp /21-40 https://asgi.readthedocs.io/en/latest/implementations.html -RedirectTemp /21-41 https://pydantic-docs.helpmanual.io/ -RedirectTemp /21-42 https://doc.traefik.io/traefik/ -RedirectTemp /21-43 https://fastapi.tiangolo.com/project-generation/ -RedirectTemp /21-44 https://fastapi.tiangolo.com/tutorial/response-model/ -RedirectTemp /21-45 https://docs.python.org/3/library/asyncio-stream.html#asyncio.start_server -RedirectTemp /21-46 https://github.com/python/typeshed/issues/5535 -RedirectTemp /21-47 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.Server.serve_forever -RedirectTemp /21-48 https://docs.python.org/3/library/asyncio-stream.html#asyncio.StreamWriter.close -RedirectTemp /21-49 https://docs.python.org/3/library/asyncio-stream.html#streamwriter -RedirectTemp /21-50 https://docs.python.org/3/library/asyncio-stream.html -RedirectTemp /21-51 https://docs.python.org/3/library/asyncio-protocol.html -RedirectTemp /21-52 https://docs.python.org/3/library/asyncio-protocol.html#tcp-echo-server -RedirectTemp /21-53 https://github.com/aio-libs/aiopg -RedirectTemp /21-54 https://docs.python.org/3/whatsnew/3.8.html#asyncio -RedirectTemp /21-56 https://datatracker.ietf.org/doc/html/rfc6761 -RedirectTemp /21-57 https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager -RedirectTemp /21-59 https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager -RedirectTemp /21-61 https://docs.python.org/3/library/asyncio-task.html#asyncio.gather -RedirectTemp /21-62 https://curio.readthedocs.io/en/latest/index.html -RedirectTemp /21-63 https://curio.readthedocs.io/en/latest/reference.html#task-groups -RedirectTemp /21-64 https://en.wikipedia.org/wiki/Structured_concurrency -RedirectTemp /21-66 https://www.python.org/dev/peps/pep-0654/#motivation -RedirectTemp /21-67 https://curio.readthedocs.io/en/latest/reference.html#AWAIT -RedirectTemp /21-68 https://www.python-httpx.org/async/#curio -RedirectTemp /21-69 https://github.com/dabeaz/curio/tree/78bca8a6ad677ef51e1568ac7b3e51441ab49c42/examples -RedirectTemp /21-70 https://datatracker.ietf.org/doc/html/rfc8305 -RedirectTemp /21-71 https://trio.readthedocs.io/en/stable/ -RedirectTemp /21-72 https://www.youtube.com/watch?v=M-sc73Y-zQA -RedirectTemp /21-73 https://en.wikipedia.org/wiki/Technical_debt -RedirectTemp /21-74 https://www.youtube.com/watch?v=E-1Y4kSsAFc -RedirectTemp /21-76 https://github.com/dabeaz/curio -RedirectTemp /21-77 https://trio.readthedocs.io/en/stable/ -RedirectTemp /21-78 https://curio.readthedocs.io/en/latest/#curio-university -RedirectTemp /21-79 https://docs.python.org/3/library/asyncio.html -RedirectTemp /21-80 https://bugs.python.org/issue33649 -RedirectTemp /21-82 https://docs.python.org/3/library/asyncio-dev.html -RedirectTemp /21-83 https://www.youtube.com/watch?v=iG6fr81xHKA -RedirectTemp /21-84 https://www.youtube.com/watch?v=F19R_M4Nay4 -RedirectTemp /21-85 https://asherman.io/projects/unsync.html -RedirectTemp /21-86 https://pyladies.com/ -RedirectTemp /21-87 https://www.youtube.com/watch?v=sW76-pRkZk8 -RedirectTemp /21-88 https://www.youtube.com/watch?v=Xbl7XjFYsN4 -RedirectTemp /21-89 https://www.youtube.com/watch?v=02CLD-42VdI -RedirectTemp /21-90 https://micropython.org/ -RedirectTemp /21-91 https://docs.micropython.org/en/latest/library/uasyncio.html -RedirectTemp /21-92 https://www.encode.io/articles/python-async-frameworks-beyond-developer-tribalism -RedirectTemp /21-93 https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/ -RedirectTemp /21-94 https://github.com/MagicStack/uvloop -RedirectTemp /21-95 http://magic.io/blog/uvloop-blazing-fast-python-networking/ -RedirectTemp /21-96 https://github.com/MagicStack/httptools -RedirectTemp /21-97 https://docs.aiohttp.org/en/stable/ -RedirectTemp /21-98 https://github.com/wg/wrk -RedirectTemp /21-99 https://twistedmatrix.com/trac/ +RedirectTemp /21-2 https://bugs.python.org/issue43216 +RedirectTemp /21-3 https://bugs.python.org/issue36921 +RedirectTemp /21-4 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.getaddrinfo +RedirectTemp /21-5 https://docs.python.org/3/library/socket.html#socket.getaddrinfo +RedirectTemp /21-6 https://docs.python.org/3.10/library/asyncio-eventloop.html#asyncio.get_event_loop +RedirectTemp /21-7 https://www.python.org/dev/peps/pep-0492/#await-expression +RedirectTemp /21-8 https://www.fluentpython.com/extra/classic-coroutines/#yield_from_meaning_sec +RedirectTemp /21-9 https://github.com/fluentpython/example-code-2e/tree/master/20-executors/getflags +RedirectTemp /21-10 https://magicstack.github.io/asyncpg/current/ +RedirectTemp /21-11 https://magicstack.github.io/asyncpg/current/api/index.html#transactions +RedirectTemp /21-12 https://magicstack.github.io/asyncpg/current/api/index.html#transactions +RedirectTemp /21-13 https://github.com/MagicStack/asyncpg/blob/4d39a05268ce4cc01b00458223a767542da048b8/asyncpg/transaction.py#L57 +RedirectTemp /21-14 https://magicstack.github.io/asyncpg/current/usage.html#connection-pools +RedirectTemp /21-15 https://gist.github.com/jboner/2841832 +RedirectTemp /21-16 https://en.wikipedia.org/wiki/Network-attached_storage +RedirectTemp /21-17 https://en.wikipedia.org/wiki/Semaphore_(programming) +RedirectTemp /21-18 https://en.wikipedia.org/wiki/Semaphore_(programming) +RedirectTemp /21-19 https://groups.google.com/forum/#!msg/python-tulip/PdAEtwpaJHs/7fqb-Qj2zJoJ +RedirectTemp /21-20 https://web.archive.org/web/20151209151711/http://tritarget.org/blog/2012/11/28/the-pyramid-of-doom-a-javascript-style-trap +RedirectTemp /21-21 https://stackoverflow.com/questions/53701841/what-is-the-use-case-for-future-add-done-callback/53710563 +RedirectTemp /21-22 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor +RedirectTemp /21-23 https://motor.readthedocs.io/en/stable/ +RedirectTemp /21-24 https://emptysqua.re/blog/response-to-asynchronous-python-and-databases/ +RedirectTemp /21-25 https://docs.python.org/3/library/asyncio-stream.html#tcp-echo-server-using-streams +RedirectTemp /21-26 https://en.wikipedia.org/wiki/Phaistos_Disc +RedirectTemp /21-27 https://en.wikipedia.org/wiki/Inverted_index +RedirectTemp /21-28 https://fastapi.tiangolo.com/ +RedirectTemp /21-29 https://swagger.io/specification/ +RedirectTemp /21-30 https://asgi.readthedocs.io/en/latest/implementations.html +RedirectTemp /21-31 https://pydantic-docs.helpmanual.io/ +RedirectTemp /21-32 https://doc.traefik.io/traefik/ +RedirectTemp /21-33 https://fastapi.tiangolo.com/project-generation/ +RedirectTemp /21-34 https://fastapi.tiangolo.com/tutorial/response-model/ +RedirectTemp /21-35 https://docs.python.org/3/library/asyncio-stream.html#asyncio.start_server +RedirectTemp /21-36 https://github.com/python/typeshed/issues/5535 +RedirectTemp /21-37 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.Server.serve_forever +RedirectTemp /21-38 https://docs.python.org/3/library/asyncio-stream.html#asyncio.StreamWriter.close +RedirectTemp /21-39 https://docs.python.org/3/library/asyncio-stream.html#streamwriter +RedirectTemp /21-40 https://docs.python.org/3/library/asyncio-stream.html +RedirectTemp /21-41 https://docs.python.org/3/library/asyncio-protocol.html +RedirectTemp /21-42 https://docs.python.org/3/library/asyncio-protocol.html#tcp-echo-server +RedirectTemp /21-43 https://github.com/aio-libs/aiopg +RedirectTemp /21-44 https://docs.python.org/3/whatsnew/3.8.html#asyncio +RedirectTemp /21-45 https://datatracker.ietf.org/doc/html/rfc6761 +RedirectTemp /21-46 https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager +RedirectTemp /21-47 https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager +RedirectTemp /21-48 https://docs.python.org/3/library/asyncio-task.html#asyncio.gather +RedirectTemp /21-49 https://curio.readthedocs.io/en/latest/index.html +RedirectTemp /21-50 https://curio.readthedocs.io/en/latest/reference.html#task-groups +RedirectTemp /21-51 https://en.wikipedia.org/wiki/Structured_concurrency +RedirectTemp /21-52 https://mail.python.org/archives/list/python-dev@python.org/thread/2ORDAW74LGE3ZI2QETPJRT2ZL7MCCPG2/ +RedirectTemp /21-53 https://www.python.org/dev/peps/pep-0654/#motivation +RedirectTemp /21-54 https://curio.readthedocs.io/en/latest/reference.html#AWAIT +RedirectTemp /21-55 https://www.python-httpx.org/async/#curio +RedirectTemp /21-56 https://github.com/dabeaz/curio/tree/78bca8a6ad677ef51e1568ac7b3e51441ab49c42/examples +RedirectTemp /21-57 https://datatracker.ietf.org/doc/html/rfc8305 +RedirectTemp /21-58 https://trio.readthedocs.io/en/stable/ +RedirectTemp /21-59 https://www.youtube.com/watch?v=M-sc73Y-zQA +RedirectTemp /21-60 https://en.wikipedia.org/wiki/Technical_debt +RedirectTemp /21-61 https://www.youtube.com/watch?v=E-1Y4kSsAFc +RedirectTemp /21-62 https://github.com/dabeaz/curio +RedirectTemp /21-63 https://trio.readthedocs.io/en/stable/ +RedirectTemp /21-64 https://curio.readthedocs.io/en/latest/#curio-university +RedirectTemp /21-65 https://vorpus.org/blog/some-thoughts-on-asynchronous-api-design-in-a-post-asyncawait-world/ +RedirectTemp /21-66 https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/ +RedirectTemp /21-67 https://stackoverflow.com/questions/49482969/what-is-the-core-difference-between-asyncio-and-trio +RedirectTemp /21-68 https://docs.python.org/3/library/asyncio.html +RedirectTemp /21-69 https://bugs.python.org/issue33649 +RedirectTemp /21-70 https://docs.python.org/3/library/asyncio-dev.html +RedirectTemp /21-71 https://www.youtube.com/watch?v=iG6fr81xHKA +RedirectTemp /21-72 https://www.youtube.com/watch?v=F19R_M4Nay4 +RedirectTemp /21-73 https://asherman.io/projects/unsync.html +RedirectTemp /21-74 https://pyladies.com/ +RedirectTemp /21-75 https://www.youtube.com/watch?v=sW76-pRkZk8 +RedirectTemp /21-76 https://www.youtube.com/watch?v=Xbl7XjFYsN4 +RedirectTemp /21-77 https://www.youtube.com/watch?v=02CLD-42VdI +RedirectTemp /21-78 https://micropython.org/ +RedirectTemp /21-79 https://docs.micropython.org/en/latest/library/uasyncio.html +RedirectTemp /21-80 https://www.encode.io/articles/python-async-frameworks-beyond-developer-tribalism +RedirectTemp /21-81 https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/ +RedirectTemp /21-82 https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/ +RedirectTemp /21-83 https://github.com/MagicStack/uvloop +RedirectTemp /21-84 http://magic.io/blog/uvloop-blazing-fast-python-networking/ +RedirectTemp /21-85 https://github.com/MagicStack/httptools +RedirectTemp /21-86 https://docs.aiohttp.org/en/stable/ +RedirectTemp /21-87 https://github.com/wg/wrk +RedirectTemp /21-88 https://twistedmatrix.com/trac/ ############################################################ 22 -RedirectTemp /22-4 https://pypi.org/project/attrdict/ -RedirectTemp /22-5 https://pypi.org/project/addict/ -RedirectTemp /22-7 https://github.com/ActiveState/code/tree/master/recipes/Python/52308_simple_but_handy_collector_bunch_named_stuff -RedirectTemp /22-8 https://docs.python.org/3/library/types.html#types.SimpleNamespace -RedirectTemp /22-9 https://docs.python.org/3/library/argparse.html#argparse.Namespace -RedirectTemp /22-12 https://docs.python.org/3/library/functools.html#functools.cached_property -RedirectTemp /22-13 https://docs.python.org/3/library/functools.html#functools.cached_property -RedirectTemp /22-14 https://bugs.python.org/issue42781 -RedirectTemp /22-15 https://docs.python.org/3/howto/descriptor.html -RedirectTemp /22-16 https://docs.python.org/3/library/threading.html#rlock-objects -RedirectTemp /22-17 https://docs.python.org/3.10/library/functools.html#functools.cached_property -RedirectTemp /22-18 https://www.wsj.com/articles/SB10001424052970203914304576627102996831200 -RedirectTemp /22-19 https://www.youtube.com/watch?v=s35rVw1zskA&feature=youtu.be -RedirectTemp /22-20 https://docs.python.org/3/library/functions.html#dir -RedirectTemp /22-21 https://docs.python.org/3/library/functions.html#hasattr -RedirectTemp /22-22 https://docs.python.org/3.10/reference/datamodel.html#special-method-lookup -RedirectTemp /22-23 https://docs.python.org/3/library/functions.html -RedirectTemp /22-24 https://docs.python.org/3/reference/datamodel.html#customizing-attribute-access -RedirectTemp /22-25 https://docs.python.org/3/reference/datamodel.html#special-method-lookup -RedirectTemp /22-26 https://docs.python.org/3/library/stdtypes.html#special-attributes -RedirectTemp /22-27 http://wiki.c2.com/?WelcomeVisitors -RedirectTemp /22-28 http://wiki.c2.com/?UniformAccessPrinciple -RedirectTemp /22-29 https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html -RedirectTemp /22-30 http://www.pingo.io/docs/ -RedirectTemp /22-31 https://www.drdobbs.com/javas-new-considered-harmful/184405016 -RedirectTemp /22-32 https://www.python.org/dev/peps/pep-0008/#class-names +RedirectTemp /22-1 https://github.com/fluentpython/example-code-2e/blob/master/22-dyn-attr-prop/oscon/data/osconfeed.json +RedirectTemp /22-2 https://pypi.org/project/attrdict/ +RedirectTemp /22-3 https://pypi.org/project/addict/ +RedirectTemp /22-4 https://github.com/ActiveState/code/tree/master/recipes/Python/52308_simple_but_handy_collector_bunch_named_stuff +RedirectTemp /22-5 https://docs.python.org/3/library/types.html#types.SimpleNamespace +RedirectTemp /22-6 https://docs.python.org/3/library/argparse.html#argparse.Namespace +RedirectTemp /22-7 https://docs.python.org/3/library/multiprocessing.html#multiprocessing.managers.Namespace +RedirectTemp /22-8 https://github.com/fluentpython/example-code-2e/blob/master/22-dyn-attr-prop/oscon/schedule_v2.py +RedirectTemp /22-9 https://docs.python.org/3/library/functools.html#functools.cached_property +RedirectTemp /22-10 https://docs.python.org/3/library/functools.html#functools.cached_property +RedirectTemp /22-11 https://bugs.python.org/issue42781 +RedirectTemp /22-12 https://docs.python.org/3/howto/descriptor.html +RedirectTemp /22-13 https://github.com/python/cpython/blob/e6d0107e13ed957109e79b796984d3d026a8660d/Lib/functools.py#L926 +RedirectTemp /22-14 https://docs.python.org/3/library/threading.html#rlock-objects +RedirectTemp /22-15 https://docs.python.org/3.10/library/functools.html#functools.cached_property +RedirectTemp /22-16 https://www.wsj.com/articles/SB10001424052970203914304576627102996831200 +RedirectTemp /22-17 https://www.youtube.com/watch?v=s35rVw1zskA&feature=youtu.be +RedirectTemp /22-18 https://docs.python.org/3/library/functions.html#dir +RedirectTemp /22-19 https://github.com/python/cpython/blob/19903085c3ad7a17c8047e1556c700f2eb109931/Lib/cmd.py#L214 +RedirectTemp /22-20 https://docs.python.org/3/library/functions.html#hasattr +RedirectTemp /22-21 https://docs.python.org/3.10/reference/datamodel.html#special-method-lookup +RedirectTemp /22-22 https://docs.python.org/3/library/functions.html +RedirectTemp /22-23 https://docs.python.org/3/reference/datamodel.html#customizing-attribute-access +RedirectTemp /22-24 https://docs.python.org/3/reference/datamodel.html#special-method-lookup +RedirectTemp /22-25 https://docs.python.org/3/library/stdtypes.html#special-attributes +RedirectTemp /22-26 http://wiki.c2.com/?WelcomeVisitors +RedirectTemp /22-27 http://wiki.c2.com/?UniformAccessPrinciple +RedirectTemp /22-28 https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html +RedirectTemp /22-29 http://www.pingo.io/docs/ +RedirectTemp /22-30 https://www.drdobbs.com/javas-new-considered-harmful/184405016 +RedirectTemp /22-31 https://www.python.org/dev/peps/pep-0008/#class-names ############################################################ 23 -RedirectTemp /23-2 http://www.aleax.it/goo_pydp.pdf -RedirectTemp /23-3 https://docs.python.org/3.10/reference/datamodel.html#implementing-descriptors -RedirectTemp /23-6 https://docs.python.org/3/howto/descriptor.html -RedirectTemp /23-7 https://docs.python.org/3/howto/ -RedirectTemp /23-8 http://www.aleax.it/Python/nylug05_om.pdf -RedirectTemp /23-9 https://www.youtube.com/watch?v=VOzvpHoYQoo -RedirectTemp /23-11 https://www.python.org/dev/peps/pep-0487/#trait-descriptors -RedirectTemp /23-12 https://dreamsongs.com/RiseOfWorseIsBetter.html -RedirectTemp /23-13 http://web.archive.org/web/20031002184114/www.amk.ca/python/writing/warts.html -RedirectTemp /23-14 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this -RedirectTemp /23-15 http://python-history.blogspot.com/2009/02/adding-support-for-user-defined-classes.html +RedirectTemp /23-1 http://www.aleax.it/goo_pydp.pdf +RedirectTemp /23-2 https://docs.python.org/3.10/reference/datamodel.html#implementing-descriptors +RedirectTemp /23-3 https://docs.python.org/3/howto/descriptor.html +RedirectTemp /23-4 https://docs.python.org/3/howto/ +RedirectTemp /23-5 http://www.aleax.it/Python/nylug05_om.pdf +RedirectTemp /23-6 https://www.youtube.com/watch?v=VOzvpHoYQoo +RedirectTemp /23-7 https://www.python.org/dev/peps/pep-0487/#trait-descriptors +RedirectTemp /23-8 https://dreamsongs.com/RiseOfWorseIsBetter.html +RedirectTemp /23-9 http://web.archive.org/web/20031002184114/www.amk.ca/python/writing/warts.html +RedirectTemp /23-10 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this +RedirectTemp /23-11 http://python-history.blogspot.com/2009/02/adding-support-for-user-defined-classes.html ############################################################ 24 -RedirectTemp /24-2 https://docs.python.org/3/library/stdtypes.html#special-attributes -RedirectTemp /24-3 https://docs.djangoproject.com/en/3.2/topics/db/models/#meta-options -RedirectTemp /24-4 https://www.python.org/dev/peps/pep-3155/ -RedirectTemp /24-7 https://en.wikipedia.org/wiki/Tony_Hoare#Apologies_and_retractions -RedirectTemp /24-8 https://go.dev/tour/basics/12 -RedirectTemp /24-9 https://bugs.python.org/issue42102 -RedirectTemp /24-11 https://www.python.org/dev/peps/pep-0557/#abstract -RedirectTemp /24-12 https://github.com/python/cpython/blob/3.9/Lib/dataclasses.py -RedirectTemp /24-13 https://docs.python.org/3/reference/datamodel.html#creating-the-class-object -RedirectTemp /24-15 https://mail.python.org/pipermail/python-list/2002-December/134521.html -RedirectTemp /24-16 https://www.oreilly.com/library/view/python-in-a/9781491913833/ -RedirectTemp /24-17 https://mail.python.org/pipermail/python-list/2002-July/162558.html -RedirectTemp /24-18 https://github.com/fluentpython/example-code/tree/master/21-class-metaprog/bulkfood -RedirectTemp /24-19 https://en.wikipedia.org/wiki/Principle_of_least_astonishment -RedirectTemp /24-21 https://en.wikipedia.org/wiki/Trait_(computer_programming) -RedirectTemp /24-22 https://en.wikipedia.org/wiki/Aspect-oriented_programming -RedirectTemp /24-23 https://dhh.dk/arc/000416.html -RedirectTemp /24-24 https://github.com/cjrh/autoslot -RedirectTemp /24-25 https://docs.python.org/3/reference/datamodel.html#customizing-class-creation -RedirectTemp /24-26 https://docs.python.org/3/library/functions.html#type -RedirectTemp /24-27 https://docs.python.org/3/library/stdtypes.html#special-attributes -RedirectTemp /24-28 https://docs.python.org/3/library/types.html -RedirectTemp /24-29 https://www.python.org/dev/peps/pep-3129/ -RedirectTemp /24-30 https://www.youtube.com/watch?v=cAGliEJV9_o -RedirectTemp /24-31 https://docs.python.org/3/library/functools.html#functools.total_ordering -RedirectTemp /24-33 https://www.oreilly.com/library/view/python-in-a/9781491913833/ -RedirectTemp /24-36 https://www.python.org/download/releases/2.2.3/descrintro/ -RedirectTemp /24-42 https://github.com/lihaoyi/macropy -RedirectTemp /24-43 https://people.eecs.berkeley.edu/~bh/ss-toc2.html +RedirectTemp /24-1 https://docs.python.org/3/library/stdtypes.html#special-attributes +RedirectTemp /24-2 https://docs.djangoproject.com/en/3.2/topics/db/models/#meta-options +RedirectTemp /24-3 https://www.python.org/dev/peps/pep-3155/ +RedirectTemp /24-4 https://github.com/python/cpython/blob/3.9/Lib/collections/__init__.py +RedirectTemp /24-5 https://en.wikipedia.org/wiki/Tony_Hoare#Apologies_and_retractions +RedirectTemp /24-6 https://go.dev/tour/basics/12 +RedirectTemp /24-7 https://bugs.python.org/issue42102 +RedirectTemp /24-8 https://docs.python.org/3/reference/datamodel.html#object.__init_subclass__ +RedirectTemp /24-9 https://www.python.org/dev/peps/pep-0557/#abstract +RedirectTemp /24-10 https://github.com/python/cpython/blob/3.9/Lib/dataclasses.py +RedirectTemp /24-11 https://docs.python.org/3/reference/datamodel.html#creating-the-class-object +RedirectTemp /24-12 https://mail.python.org/pipermail/python-list/2002-December/134521.html +RedirectTemp /24-13 https://mail.python.org/pipermail/python-list/2002-July/162558.html +RedirectTemp /24-14 https://github.com/fluentpython/example-code/tree/master/21-class-metaprog/bulkfood +RedirectTemp /24-15 https://en.wikipedia.org/wiki/Principle_of_least_astonishment +RedirectTemp /24-16 https://docs.python.org/3/reference/datamodel.html#object.__class_getitem__ +RedirectTemp /24-17 https://en.wikipedia.org/wiki/Trait_(computer_programming) +RedirectTemp /24-18 https://en.wikipedia.org/wiki/Aspect-oriented_programming +RedirectTemp /24-19 https://dhh.dk/arc/000416.html +RedirectTemp /24-20 https://github.com/cjrh/autoslot +RedirectTemp /24-21 https://docs.python.org/3/reference/datamodel.html#customizing-class-creation +RedirectTemp /24-22 https://docs.python.org/3/library/functions.html#type +RedirectTemp /24-23 https://docs.python.org/3/library/stdtypes.html#special-attributes +RedirectTemp /24-24 https://docs.python.org/3/library/types.html +RedirectTemp /24-25 https://www.python.org/dev/peps/pep-3129/ +RedirectTemp /24-26 https://www.youtube.com/watch?v=cAGliEJV9_o +RedirectTemp /24-27 https://docs.python.org/3/library/functools.html#functools.total_ordering +RedirectTemp /24-28 https://www.python.org/download/releases/2.2.3/descrintro/ +RedirectTemp /24-29 https://github.com/lihaoyi/macropy +RedirectTemp /24-30 https://people.eecs.berkeley.edu/~bh/ss-toc2.html diff --git a/links/custom.htaccess b/links/custom.htaccess index 52649db..b9bc509 100644 --- a/links/custom.htaccess +++ b/links/custom.htaccess @@ -25,6 +25,17 @@ RedirectTemp /norvigdp http://norvig.com/design-patterns/ RedirectTemp /nsphere https://en.wikipedia.org/wiki/N-sphere RedirectTemp /oldcoro https://www.fluentpython.com/extra/classic-coroutines/ RedirectTemp /pandas https://pandas.pydata.org/ +RedirectTemp /pycook3 https://www.oreilly.com/library/view/python-cookbook-3rd/9781449357337/ +RedirectTemp /pynut3 https://www.oreilly.com/library/view/python-in-a/9781491913833/ +RedirectTemp /pypydif https://doc.pypy.org/en/latest/cpython_differences.html#subclasses-of-built-in-types +RedirectTemp /shed4051 https://github.com/python/typeshed/issues/4051 +RedirectTemp /slatkin https://effectivepython.com/ +RedirectTemp /specattr https://docs.python.org/3/library/stdtypes.html#special-attributes +RedirectTemp /typecoro https://docs.python.org/3.10/library/typing.html#typing.Coroutine +RedirectTemp /typing https://docs.python.org/3/library/typing.html +RedirectTemp /weakref https://www.fluentpython.com/extra/weak-references/ + +# Python Enhancement Proposals RedirectTemp /pep218 https://www.python.org/dev/peps/pep-0218/ RedirectTemp /pep227 https://www.python.org/dev/peps/pep-0227/ RedirectTemp /pep255 https://www.python.org/dev/peps/pep-0255/ @@ -100,10 +111,3 @@ RedirectTemp /pep3141 https://www.python.org/dev/peps/pep-3141/ RedirectTemp /pep3148 https://www.python.org/dev/peps/pep-3148/ RedirectTemp /pep3155 https://www.python.org/dev/peps/pep-3155/ RedirectTemp /pep3333 https://www.python.org/dev/peps/pep-3333/ -RedirectTemp /pypydif https://doc.pypy.org/en/latest/cpython_differences.html#subclasses-of-built-in-types -RedirectTemp /shed4051 https://github.com/python/typeshed/issues/4051 -RedirectTemp /slatkin https://effectivepython.com/ -RedirectTemp /specattr https://docs.python.org/3/library/stdtypes.html#special-attributes -RedirectTemp /typecoro https://docs.python.org/3.10/library/typing.html#typing.Coroutine -RedirectTemp /typing https://docs.python.org/3/library/typing.html -RedirectTemp /weakref https://www.fluentpython.com/extra/weak-references/ From 08318a657a683c7d80b06a94aeee3f8f36ffbb25 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Mon, 17 Jan 2022 15:22:20 -0300 Subject: [PATCH 36/66] harmless edits in .htaccess --- links/FPY.LI.htaccess | 12 ++++++------ links/custom.htaccess | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/links/FPY.LI.htaccess b/links/FPY.LI.htaccess index 9f960f1..6e324d0 100644 --- a/links/FPY.LI.htaccess +++ b/links/FPY.LI.htaccess @@ -1,19 +1,20 @@ ErrorDocument 404 /404.html # main resources +RedirectTemp /book https://www.oreilly.com/library/view/fluent-python-2nd/9781492056348/ RedirectTemp /code https://github.com/fluentpython/example-code-2e RedirectTemp /home https://www.fluentpython.com/ # URLs mentioned at least three times RedirectTemp /bisect https://www.fluentpython.com/extra/ordered-sequences-with-bisect/ -RedirectTemp /cardxvi https://www.python.org/dev/peps/pep-0484/#the-numeric-tower +RedirectTemp /cardxvi https://www.python.org/dev/peps/pep-0484/#the-numeric-tower RedirectTemp /collec https://docs.python.org/3/library/collections.html RedirectTemp /dask https://dask.org/ RedirectTemp /dtmodel https://docs.python.org/3/reference/datamodel.html RedirectTemp /descr101 https://www.python.org/download/releases/2.2.3/descrintro/ RedirectTemp /descrhow https://docs.python.org/3/howto/descriptor.html RedirectTemp /doctest https://docs.python.org/3/library/doctest.html -RedirectTemp /effectpy https://effectivepython.com/ +RedirectTemp /effectpy https://effectivepython.com/ RedirectTemp /fmtspec https://docs.python.org/3/library/string.html#formatspec RedirectTemp /gunicorn https://gunicorn.org/ RedirectTemp /hashint https://www.fluentpython.com/extra/internals-of-sets-and-dicts/ @@ -25,13 +26,12 @@ RedirectTemp /norvigdp http://norvig.com/design-patterns/ RedirectTemp /nsphere https://en.wikipedia.org/wiki/N-sphere RedirectTemp /oldcoro https://www.fluentpython.com/extra/classic-coroutines/ RedirectTemp /pandas https://pandas.pydata.org/ -RedirectTemp /pycook3 https://www.oreilly.com/library/view/python-cookbook-3rd/9781449357337/ -RedirectTemp /pynut3 https://www.oreilly.com/library/view/python-in-a/9781491913833/ +RedirectTemp /pycook3 https://www.oreilly.com/library/view/python-cookbook-3rd/9781449357337/ +RedirectTemp /pynut3 https://www.oreilly.com/library/view/python-in-a/9781491913833/ RedirectTemp /pypydif https://doc.pypy.org/en/latest/cpython_differences.html#subclasses-of-built-in-types RedirectTemp /shed4051 https://github.com/python/typeshed/issues/4051 -RedirectTemp /slatkin https://effectivepython.com/ RedirectTemp /specattr https://docs.python.org/3/library/stdtypes.html#special-attributes -RedirectTemp /typecoro https://docs.python.org/3.10/library/typing.html#typing.Coroutine +RedirectTemp /typecoro https://docs.python.org/3.10/library/typing.html#typing.Coroutine RedirectTemp /typing https://docs.python.org/3/library/typing.html RedirectTemp /weakref https://www.fluentpython.com/extra/weak-references/ diff --git a/links/custom.htaccess b/links/custom.htaccess index b9bc509..a13b9f8 100644 --- a/links/custom.htaccess +++ b/links/custom.htaccess @@ -1,19 +1,20 @@ ErrorDocument 404 /404.html # main resources +RedirectTemp /book https://www.oreilly.com/library/view/fluent-python-2nd/9781492056348/ RedirectTemp /code https://github.com/fluentpython/example-code-2e RedirectTemp /home https://www.fluentpython.com/ # URLs mentioned at least three times RedirectTemp /bisect https://www.fluentpython.com/extra/ordered-sequences-with-bisect/ -RedirectTemp /cardxvi https://www.python.org/dev/peps/pep-0484/#the-numeric-tower +RedirectTemp /cardxvi https://www.python.org/dev/peps/pep-0484/#the-numeric-tower RedirectTemp /collec https://docs.python.org/3/library/collections.html RedirectTemp /dask https://dask.org/ RedirectTemp /dtmodel https://docs.python.org/3/reference/datamodel.html RedirectTemp /descr101 https://www.python.org/download/releases/2.2.3/descrintro/ RedirectTemp /descrhow https://docs.python.org/3/howto/descriptor.html RedirectTemp /doctest https://docs.python.org/3/library/doctest.html -RedirectTemp /effectpy https://effectivepython.com/ +RedirectTemp /effectpy https://effectivepython.com/ RedirectTemp /fmtspec https://docs.python.org/3/library/string.html#formatspec RedirectTemp /gunicorn https://gunicorn.org/ RedirectTemp /hashint https://www.fluentpython.com/extra/internals-of-sets-and-dicts/ @@ -25,13 +26,12 @@ RedirectTemp /norvigdp http://norvig.com/design-patterns/ RedirectTemp /nsphere https://en.wikipedia.org/wiki/N-sphere RedirectTemp /oldcoro https://www.fluentpython.com/extra/classic-coroutines/ RedirectTemp /pandas https://pandas.pydata.org/ -RedirectTemp /pycook3 https://www.oreilly.com/library/view/python-cookbook-3rd/9781449357337/ -RedirectTemp /pynut3 https://www.oreilly.com/library/view/python-in-a/9781491913833/ +RedirectTemp /pycook3 https://www.oreilly.com/library/view/python-cookbook-3rd/9781449357337/ +RedirectTemp /pynut3 https://www.oreilly.com/library/view/python-in-a/9781491913833/ RedirectTemp /pypydif https://doc.pypy.org/en/latest/cpython_differences.html#subclasses-of-built-in-types RedirectTemp /shed4051 https://github.com/python/typeshed/issues/4051 -RedirectTemp /slatkin https://effectivepython.com/ RedirectTemp /specattr https://docs.python.org/3/library/stdtypes.html#special-attributes -RedirectTemp /typecoro https://docs.python.org/3.10/library/typing.html#typing.Coroutine +RedirectTemp /typecoro https://docs.python.org/3.10/library/typing.html#typing.Coroutine RedirectTemp /typing https://docs.python.org/3/library/typing.html RedirectTemp /weakref https://www.fluentpython.com/extra/weak-references/ From b39c1c1f049ec5b0c6e1686cda20b39f45072824 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Wed, 16 Feb 2022 14:40:49 -0300 Subject: [PATCH 37/66] added bdfl short URL --- links/FPY.LI.htaccess | 3 +++ links/README.md | 5 ++++- links/custom.htaccess | 3 +++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/links/FPY.LI.htaccess b/links/FPY.LI.htaccess index 6e324d0..d38c973 100644 --- a/links/FPY.LI.htaccess +++ b/links/FPY.LI.htaccess @@ -35,6 +35,9 @@ RedirectTemp /typecoro https://docs.python.org/3.10/library/typing.html#typing.C RedirectTemp /typing https://docs.python.org/3/library/typing.html RedirectTemp /weakref https://www.fluentpython.com/extra/weak-references/ +# URLs added during QA of the Second Edition +RedirectTemp /bdfl https://www.artima.com/weblogs/viewpost.jsp?thread=235725 + # Python Enhancement Proposals RedirectTemp /pep218 https://www.python.org/dev/peps/pep-0218/ RedirectTemp /pep227 https://www.python.org/dev/peps/pep-0227/ diff --git a/links/README.md b/links/README.md index 09c808a..6da595c 100644 --- a/links/README.md +++ b/links/README.md @@ -12,7 +12,10 @@ I replaced almost all URLs in the book with shortened versions that go through t The site has an `.htaccess` file with *temporary* redirects. When I find out a link is stale, I can thange the redirect in `.htaccess` to a new target, -so the link in the book is back in service through the updated redirect. +which may be a link to copy in the Internet Archive's +[Wayback Machine](https://archive.org/web/) +o the link in the book is back in service through the updated redirect. + ## Help wanted diff --git a/links/custom.htaccess b/links/custom.htaccess index a13b9f8..9e070f1 100644 --- a/links/custom.htaccess +++ b/links/custom.htaccess @@ -35,6 +35,9 @@ RedirectTemp /typecoro https://docs.python.org/3.10/library/typing.html#typing.C RedirectTemp /typing https://docs.python.org/3/library/typing.html RedirectTemp /weakref https://www.fluentpython.com/extra/weak-references/ +# URLs added during QA of the Second Edition +RedirectTemp /bdfl https://www.artima.com/weblogs/viewpost.jsp?thread=235725 + # Python Enhancement Proposals RedirectTemp /pep218 https://www.python.org/dev/peps/pep-0218/ RedirectTemp /pep227 https://www.python.org/dev/peps/pep-0227/ From 5f2c3abfc76c906003cb35dbb4e50bd0cb6e0206 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Wed, 16 Feb 2022 14:46:28 -0300 Subject: [PATCH 38/66] added bdfl short URL --- links/FPY.LI.htaccess | 2 +- links/custom.htaccess | 2 +- links/deploy.sh | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) create mode 100755 links/deploy.sh diff --git a/links/FPY.LI.htaccess b/links/FPY.LI.htaccess index d38c973..44d2530 100644 --- a/links/FPY.LI.htaccess +++ b/links/FPY.LI.htaccess @@ -35,7 +35,7 @@ RedirectTemp /typecoro https://docs.python.org/3.10/library/typing.html#typing.C RedirectTemp /typing https://docs.python.org/3/library/typing.html RedirectTemp /weakref https://www.fluentpython.com/extra/weak-references/ -# URLs added during QA of the Second Edition +# URL added during QA of the Second Edition RedirectTemp /bdfl https://www.artima.com/weblogs/viewpost.jsp?thread=235725 # Python Enhancement Proposals diff --git a/links/custom.htaccess b/links/custom.htaccess index 9e070f1..ad10802 100644 --- a/links/custom.htaccess +++ b/links/custom.htaccess @@ -35,7 +35,7 @@ RedirectTemp /typecoro https://docs.python.org/3.10/library/typing.html#typing.C RedirectTemp /typing https://docs.python.org/3/library/typing.html RedirectTemp /weakref https://www.fluentpython.com/extra/weak-references/ -# URLs added during QA of the Second Edition +# URL added during QA of the Second Edition RedirectTemp /bdfl https://www.artima.com/weblogs/viewpost.jsp?thread=235725 # Python Enhancement Proposals diff --git a/links/deploy.sh b/links/deploy.sh new file mode 100755 index 0000000..ced9bd9 --- /dev/null +++ b/links/deploy.sh @@ -0,0 +1,2 @@ +#!/bin/bash +scp FPY.LI.htaccess dh_i4p2ka@fpy.li:~/fpy.li/.htaccess From 536e68686fed2c51a29b6dc0e2acbff7aeb3ee3f Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Mon, 21 Feb 2022 18:21:28 -0300 Subject: [PATCH 39/66] updated link to String Format String Syntax in Python 3 --- links/FPY.LI.htaccess | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/links/FPY.LI.htaccess b/links/FPY.LI.htaccess index 44d2530..cc779db 100644 --- a/links/FPY.LI.htaccess +++ b/links/FPY.LI.htaccess @@ -152,7 +152,7 @@ RedirectTemp /a-18 https://www.python.org/doc/essays/ RedirectTemp /1-1 http://hugunin.net/story_of_jython.html RedirectTemp /1-2 https://www.oreilly.com/library/view/jython-essentials/9781449397364/ RedirectTemp /1-3 https://docs.python.org/3/reference/lexical_analysis.html#reserved-classes-of-identifiers -RedirectTemp /1-4 https://docs.python.org/2/library/string.html#format-string-syntax +RedirectTemp /1-4 https://docs.python.org/3.10/library/string.html#format-string-syntax RedirectTemp /1-5 https://stackoverflow.com/questions/1436703/what-is-the-difference-between-str-and-repr RedirectTemp /1-6 https://docs.python.org/3/library/stdtypes.html#truth RedirectTemp /1-7 https://docs.python.org/3/tutorial/controlflow.html#unpacking-argument-lists From a40bd03b0eb9e88884b93377dea7238038893916 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Wed, 9 Mar 2022 18:35:41 -0300 Subject: [PATCH 40/66] renumbered book parts --- README.md | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 96273ac..234c8da 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,7 @@ # Fluent Python 2e example code -Example code for the book **Fluent Python, 2nd edition** by Luciano Ramalho (O'Reilly, 2021). +Example code for the book **Fluent Python, Second Edition** by Luciano Ramalho (O'Reilly, 2022). -> **BEWARE**: This is a work in progress! -> -> * Code here may change and disappear without warning. -> -> * Major reorganizations may happen at any time. -> -> * No promises. No guarantees. Use at own risk. ## Table of Contents @@ -16,37 +9,37 @@ All chapters are undergoing review and updates, including significant rewrites i New chapters in **Fluent Python 2e** are marked with 🆕. -🚨 This table of contents is subject to change at any time until the book goes to the printer. +> 🚨  This table of contents is subject to change at any time until the book goes to the printer.
+Latest change: Old **Part I—Prologue** merged into new **Part I—Data Structures**; parts renumbered accordingly; chapter numbers unchanged. Part / Chapter #|Title|Directory|1st ed. Chapter # ---:|---|---|:---: -**I – Prologue**| +**I – Data Structures**| 1|The Python Data Model|[01-data-model](01-data-model)|1 -**II – Data Structures**| 2|An Array of Sequences|[02-array-seq](02-array-seq)|2 3|Dictionaries and Sets|[03-dict-set](03-dict-set)|3 4|Unicode Text versus Bytes|[04-text-byte](04-text-byte)|4 5|Data Class Builders|[05-data-classes](05-data-classes)|🆕 6|Object References, Mutability, and Recycling|[06-obj-ref](06-obj-ref)|8 -**III – Functions as Objects**| +**II – Functions as Objects**| 7|Funcions as First-Class Objects|[07-1class-func](07-1class-func)|5 -8|Type Hints in Function Definitions|[08-def-type-hints](08-def-type-hints)|🆕 -9|Function Decorators and Closures|[09-closure-deco](09-closure-deco)|7 +8|Type Hints in Functions|[08-def-type-hints](08-def-type-hints)|🆕 +9|Decorators and Closures|[09-closure-deco](09-closure-deco)|7 10|Design Patterns with First-Class Functions|[10-dp-1class-func](10-dp-1class-func)|6 -**IV – Object-Oriented Idioms**| +**III – Object-Oriented Idioms**| 11|A Pythonic Object|[11-pythonic-obj](11-pythonic-obj)|9 -12|Sequence Hacking, Hashing, and Slicing|[12-seq-hacking](12-seq-hacking)|10 +12|Special Methods for Sequences|[12-seq-hacking](12-seq-hacking)|10 13|Interfaces, Protocols, and ABCs|[13-protocl-abc](13-protocol-abc)|11 -14|Inheritance: For Good or For Worse|[14-inheritance](14-inheritance)|12 +14|Inheritance: For Better or For Worse|[14-inheritance](14-inheritance)|12 15|More About Type Hints|[15-more-types](15-more-types)|🆕 -16|Operator Overloading: Doing It Right|[16-op-overloading](16-op-overloading)|13 -**V – Control Flow**| +16|Operator Overloading|[16-op-overloading](16-op-overloading)|13 +**IV – Control Flow**| 17|Iterators, Generators, and Classic Coroutines|[17-it-generator](17-it-generator)|14 -18|Context Managers and else Blocks|[18-with-match](18-with-match)|15 +18|with, match, and else Blocks|[18-with-match](18-with-match)|15 19|Concurrency Models in Python|[19-concurrency](19-concurrency)|🆕 20|Concurrent Executors|[20-executors](20-executors)|17 21|Asynchronous Programming|[21-async](21-async)|18 -**VI – Metaprogramming**| +**V – Metaprogramming**| 22|Dynamic Attributes and Properties|[22-dyn-attr-prop](22-dyn-attr-prop)|19 23|Attribute Descriptors|[23-descriptor](23-descriptor)|20 24|Class Metaprogramming|[24-class-metaprog](24-class-metaprog)|21 From 8158222f2224c95ae57a4f8599073245ee94dc06 Mon Sep 17 00:00:00 2001 From: Scott McCormack Date: Mon, 14 Mar 2022 21:58:48 +0800 Subject: [PATCH 41/66] 2nd edition updates --- 02-array-seq/array-seq.ipynb | 1834 ++++++++++++++++++++++------------ 1 file changed, 1201 insertions(+), 633 deletions(-) diff --git a/02-array-seq/array-seq.ipynb b/02-array-seq/array-seq.ipynb index 032d811..afdbf6b 100644 --- a/02-array-seq/array-seq.ipynb +++ b/02-array-seq/array-seq.ipynb @@ -9,12 +9,14 @@ "**Sections with code snippets in this chapter:**\n", "\n", "* [List Comprehensions and Generator Expressions](#List-Comprehensions-and-Generator-Expressions)\n", + "* [Tuples Are Not Just Immutable Lists](#Tuples-Are-Not-Just-Immutable-Lists)\n", + "* [Unpacking sequences and iterables](#Unpacking-sequences-and-iterables)\n", + "* [Pattern Matching with Sequences](#Pattern-Matching-with-Sequences)\n", "* [Slicing](#Slicing)\n", - "* [Building Lists of Lists](#Building-Lists-of-Lists)\n", + "* [Using + and * with Sequences](#Using-+-and-*-with-Sequences)\n", "* [Augmented Assignment with Sequences](#Augmented-Assignment-with-Sequences)\n", "* [list.sort and the sorted Built-In Function](#list.sort-and-the-sorted-Built-In-Function)\n", - "* [Managing Ordered Sequences with bisect](#Managing-Ordered-Sequences-with-bisect)\n", - "* [Arrays](#Arrays)\n", + "* [When a List Is Not the Answer](#When-a-List-Is-Not-the-Answer)\n", "* [Memory Views](#Memory-Views)\n", "* [NumPy and SciPy](#NumPy-and-SciPy)\n", "* [Deques and Other Queues](#Deques-and-Other-Queues)\n", @@ -42,9 +44,7 @@ "outputs": [ { "data": { - "text/plain": [ - "[36, 162, 163, 165, 8364, 164]" - ] + "text/plain": "[36, 162, 163, 165, 8364, 164]" }, "execution_count": 1, "metadata": {}, @@ -65,7 +65,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#### Example 2-2. Build a list of Unicode codepoints from a string, take 2" + "#### Example 2-2. Build a list of Unicode codepoints from a string, using a listcomp" ] }, { @@ -75,9 +75,7 @@ "outputs": [ { "data": { - "text/plain": [ - "[36, 162, 163, 165, 8364, 164]" - ] + "text/plain": "[36, 162, 163, 165, 8364, 164]" }, "execution_count": 2, "metadata": {}, @@ -106,9 +104,7 @@ "outputs": [ { "data": { - "text/plain": [ - "'ABC'" - ] + "text/plain": "'ABC'" }, "execution_count": 3, "metadata": {}, @@ -128,9 +124,7 @@ "outputs": [ { "data": { - "text/plain": [ - "[65, 66, 67]" - ] + "text/plain": "[65, 66, 67]" }, "execution_count": 4, "metadata": {}, @@ -141,6 +135,30 @@ "codes" ] }, + { + "cell_type": "code", + "execution_count": 5, + "outputs": [ + { + "data": { + "text/plain": "67" + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "codes = [last := ord(c) for c in x]\n", + "last" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, { "cell_type": "markdown", "metadata": {}, @@ -150,214 +168,958 @@ }, { "cell_type": "code", - "execution_count": 5, - "metadata": {}, + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": "[162, 163, 165, 8364, 164]" + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "symbols = '$¢£¥€¤'\n", + "beyond_ascii = [ord(s) for s in symbols if ord(s) > 127]\n", + "beyond_ascii" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": "[162, 163, 165, 8364, 164]" + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "beyond_ascii = list(filter(lambda c: c > 127, map(ord, symbols)))\n", + "beyond_ascii" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Example 2-4. Cartesian product using a list comprehension" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": "[('black', 'S'),\n ('black', 'M'),\n ('black', 'L'),\n ('white', 'S'),\n ('white', 'M'),\n ('white', 'L')]" + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "colors = ['black', 'white']\n", + "sizes = ['S', 'M', 'L']\n", + "tshirts = [(color, size) for color in colors for size in sizes]\n", + "tshirts" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "('black', 'S')\n", + "('black', 'M')\n", + "('black', 'L')\n", + "('white', 'S')\n", + "('white', 'M')\n", + "('white', 'L')\n" + ] + } + ], + "source": [ + "for color in colors:\n", + " for size in sizes:\n", + " print((color, size))" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": "[('black', 'S'),\n ('black', 'M'),\n ('black', 'L'),\n ('white', 'S'),\n ('white', 'M'),\n ('white', 'L')]" + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "shirts = [(color, size) for size in sizes\n", + " for color in colors]\n", + "tshirts" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Example 2-5. Initializing a tuple and an array from a generator expression" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": "(36, 162, 163, 165, 8364, 164)" + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "symbols = '$¢£¥€¤'\n", + "tuple(ord(symbol) for symbol in symbols)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": "array('I', [36, 162, 163, 165, 8364, 164])" + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import array\n", + "\n", + "array.array('I', (ord(symbol) for symbol in symbols))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Example 2-6. Cartesian product in a generator expression" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "black S\n", + "black M\n", + "black L\n", + "white S\n", + "white M\n", + "white L\n" + ] + } + ], + "source": [ + "colors = ['black', 'white']\n", + "sizes = ['S', 'M', 'L']\n", + "\n", + "for tshirt in ('%s %s' % (c, s) for c in colors for s in sizes):\n", + " print(tshirt)" + ] + }, + { + "cell_type": "markdown", + "source": [ + "## Tuples Are Not Just Immutable Lists" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + }, + "execution_count": 73 + }, + { + "cell_type": "markdown", + "source": [ + "#### Example 2-7. Tuples used as records" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 14, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "BRA/CE342567\n", + "ESP/XDA205856\n", + "USA/31195855\n" + ] + } + ], + "source": [ + "lax_coordinates = (33.9425, -118.408056)\n", + "city, year, pop, chg, area = ('Tokyo', 2003, 32_450, 0.66, 8014)\n", + "traveler_ids = [('USA', '31195855'), ('BRA', 'CE342567'), ('ESP', 'XDA205856')]\n", + "\n", + "for passport in sorted(traveler_ids):\n", + " print('%s/%s' % passport)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 15, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "USA\n", + "BRA\n", + "ESP\n" + ] + } + ], + "source": [ + "for country, _ in traveler_ids:\n", + " print(country)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "### Tuples as Immutable Lists" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 16, + "outputs": [ + { + "data": { + "text/plain": "True" + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a = (10, 'alpha', [1, 2])\n", + "b = (10, 'alpha', [1, 2])\n", + "a == b" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 17, + "outputs": [ + { + "data": { + "text/plain": "False" + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "b[-1].append(99)\n", + "a == b" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 18, + "outputs": [ + { + "data": { + "text/plain": "(10, 'alpha', [1, 2, 99])" + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "b" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 19, + "outputs": [ + { + "data": { + "text/plain": "True" + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def fixed(o):\n", + " try:\n", + " hash(o)\n", + " except TypeError:\n", + " return False\n", + " return True\n", + "\n", + "\n", + "tf = (10, 'alpha', (1, 2)) # Contains no mutable items\n", + "tm = (10, 'alpha', [1, 2]) # Contains a mutable item (list)\n", + "fixed(tf)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 20, + "outputs": [ + { + "data": { + "text/plain": "False" + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fixed(tm)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "## Unpacking sequences and iterables" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 21, + "outputs": [ + { + "data": { + "text/plain": "33.9425" + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lax_coordinates = (33.9425, -118.408056)\n", + "latitude, longitude = lax_coordinates # unpacking\n", + "latitude" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 22, + "outputs": [ + { + "data": { + "text/plain": "-118.408056" + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "longitude" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 23, + "outputs": [ + { + "data": { + "text/plain": "(2, 4)" + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "divmod(20, 8)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 24, + "outputs": [ + { + "data": { + "text/plain": "(2, 4)" + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t = (20, 8)\n", + "divmod(*t)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 25, + "outputs": [ + { + "data": { + "text/plain": "(2, 4)" + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "quotient, remainder = divmod(*t)\n", + "quotient, remainder" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 26, + "outputs": [ + { + "data": { + "text/plain": "'id_rsa.pub'" + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import os\n", + "\n", + "_, filename = os.path.split('/home/luciano/.ssh/id_rsa.pub')\n", + "filename" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "### Using * to grab excess items" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 27, + "outputs": [ + { + "data": { + "text/plain": "(0, 1, [2, 3, 4])" + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a, b, *rest = range(5)\n", + "a, b, rest" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 28, + "outputs": [ + { + "data": { + "text/plain": "(0, 1, [2])" + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a, b, *rest = range(3)\n", + "a, b, rest" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 29, "outputs": [ { "data": { - "text/plain": [ - "[162, 163, 165, 8364, 164]" - ] + "text/plain": "(0, 1, [])" }, - "execution_count": 5, + "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "symbols = '$¢£¥€¤'\n", - "beyond_ascii = [ord(s) for s in symbols if ord(s) > 127]\n", - "beyond_ascii" - ] + "a, b, *rest = range(2)\n", + "a, b, rest" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } }, { "cell_type": "code", - "execution_count": 6, - "metadata": {}, + "execution_count": 30, "outputs": [ { "data": { - "text/plain": [ - "[162, 163, 165, 8364, 164]" - ] + "text/plain": "(0, [1, 2], 3, 4)" }, - "execution_count": 6, + "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "beyond_ascii = list(filter(lambda c: c > 127, map(ord, symbols)))\n", - "beyond_ascii" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Example 2-4. Cartesian product using a list comprehension" - ] + "a, *body, c, d = range(5)\n", + "a, body, c, d" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } }, { "cell_type": "code", - "execution_count": 7, - "metadata": {}, + "execution_count": 31, "outputs": [ { "data": { - "text/plain": [ - "[('black', 'S'),\n", - " ('black', 'M'),\n", - " ('black', 'L'),\n", - " ('white', 'S'),\n", - " ('white', 'M'),\n", - " ('white', 'L')]" - ] + "text/plain": "([0, 1], 2, 3, 4)" }, - "execution_count": 7, + "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "colors = ['black', 'white']\n", - "sizes = ['S', 'M', 'L']\n", - "tshirts = [(color, size) for color in colors for size in sizes]\n", - "tshirts" - ] + "*head, b, c, d = range(5)\n", + "head, b, c, d" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "### Unpacking with * in function calls and sequence literals" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } }, { "cell_type": "code", - "execution_count": 8, - "metadata": {}, + "execution_count": 32, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "('black', 'S')\n", - "('black', 'M')\n", - "('black', 'L')\n", - "('white', 'S')\n", - "('white', 'M')\n", - "('white', 'L')\n" - ] + "data": { + "text/plain": "(1, 2, 3, 4, (5, 6))" + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ - "for color in colors:\n", - " for size in sizes:\n", - " print((color, size))" - ] + "def fun(a, b, c, d, *rest):\n", + " return a, b, c, d, rest\n", + "\n", + "\n", + "fun(*[1, 2], 3, *range(4, 7))" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } }, { "cell_type": "code", - "execution_count": 9, - "metadata": {}, + "execution_count": 33, "outputs": [ { "data": { - "text/plain": [ - "[('black', 'S'),\n", - " ('black', 'M'),\n", - " ('black', 'L'),\n", - " ('white', 'S'),\n", - " ('white', 'M'),\n", - " ('white', 'L')]" - ] + "text/plain": "(0, 1, 2, 3, 4)" }, - "execution_count": 9, + "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "shirts = [(color, size) for size in sizes\n", - " for color in colors]\n", - "tshirts" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Example 2-5. Initializing a tuple and an array from a generator expression" - ] + "*range(4), 4" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } }, { "cell_type": "code", - "execution_count": 10, - "metadata": {}, + "execution_count": 34, "outputs": [ { "data": { - "text/plain": [ - "(36, 162, 163, 165, 8364, 164)" - ] + "text/plain": "[0, 1, 2, 3, 4]" }, - "execution_count": 10, + "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "symbols = '$¢£¥€¤'\n", - "tuple(ord(symbol) for symbol in symbols)" - ] + "[*range(4), 4]" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } }, { "cell_type": "code", - "execution_count": 11, - "metadata": {}, + "execution_count": 35, "outputs": [ { "data": { - "text/plain": [ - "array('I', [36, 162, 163, 165, 8364, 164])" - ] + "text/plain": "{0, 1, 2, 3, 4, 5, 6, 7}" }, - "execution_count": 11, + "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "import array\n", - "array.array('I', (ord(symbol) for symbol in symbols))" - ] + "{*range(4), 4, *(5, 6, 7)}" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } }, { "cell_type": "markdown", - "metadata": {}, "source": [ - "#### Example 2-6. Cartesian product in a generator expression" - ] + "### Nested unpacking\n", + "#### Example 2-8. Unpacking nested tuples to access the longitude\n", + "\n", + "[02-array-seq/metro_lat_lon.py](02-array-seq/metro_lat_lon.py)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "## Pattern Matching with Sequences\n", + "#### Example 2-9. Method from an imaginary Robot class" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } }, { "cell_type": "code", - "execution_count": 12, - "metadata": {}, + "execution_count": 36, + "outputs": [], + "source": [ + "# def handle_command(self, message):\n", + "# match message:\n", + "# case ['BEEPER', frequency, times]:\n", + "# self.beep(times, frequency)\n", + "# case ['NECK', angle]:\n", + "# self.rotate_neck(angle)\n", + "# case ['LED', ident, intensity]:\n", + "# self.leds[ident].set_brightness(ident, intensity)\n", + "# case ['LED', ident, red, green, blue]:\n", + "# self.leds[ident].set_color(ident, red, green, blue)\n", + "# case _:\n", + "# raise InvalidCommand(message)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "#### Example 2-10. Destructuring nested tuples—requires Python ≥ 3.10.\n", + "[02-array-seq/match_lat_lon.py](02-array-seq/match_lat_lon.py)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 37, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "black S\n", - "black M\n", - "black L\n", - "white S\n", - "white M\n", - "white L\n" + " | latitude | longitude\n", + "Mexico City | 19.4333 | -99.1333\n", + "New York-Newark | 40.8086 | -74.0204\n", + "São Paulo | -23.5478 | -46.6358\n" ] } ], "source": [ - "colors = ['black', 'white']\n", - "sizes = ['S', 'M', 'L']\n", + "metro_areas = [\n", + " ('Tokyo', 'JP', 36.933, (35.689722, 139.691667)),\n", + " ('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889)),\n", + " ('Mexico City', 'MX', 20.142, (19.433333, -99.133333)),\n", + " ('New York-Newark', 'US', 20.104, (40.808611, -74.020386)),\n", + " ('São Paulo', 'BR', 19.649, (-23.547778, -46.635833)),\n", + "]\n", "\n", - "for tshirt in ('%s %s' % (c, s) for c in colors for s in sizes):\n", - " print(tshirt)" - ] + "def main():\n", + " print(f'{\"\":15} | {\"latitude\":>9} | {\"longitude\":>9}')\n", + " for record in metro_areas:\n", + " match record:\n", + " case [name, _, _, (lat, lon)] if lon <= 0:\n", + " print(f'{name:15} | {lat:9.4f} | {lon:9.4f}')\n", + "main()" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "### Pattern Matching Sequences in an Interpreter\n", + "#### Example 2-11. Matching patterns without match/case.\n", + "[02-array-seq/lispy/py3.9/lis.py](02-array-seq/lispy/py3.9/lis.py)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "#### Example 2-12. Pattern matching with match/case—requires Python ≥ 3.10.\n", + "[02-array-seq/lispy/py3.10/lis.py](02-array-seq/lispy/py3.10/lis.py)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "markdown", + "source": [], + "metadata": { + "collapsed": false + } }, { "cell_type": "markdown", @@ -375,16 +1137,14 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 38, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "[10, 20]" - ] + "text/plain": "[10, 20]" }, - "execution_count": 13, + "execution_count": 38, "metadata": {}, "output_type": "execute_result" } @@ -397,16 +1157,14 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 39, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "[30, 40, 50, 60]" - ] + "text/plain": "[30, 40, 50, 60]" }, - "execution_count": 14, + "execution_count": 39, "metadata": {}, "output_type": "execute_result" } @@ -417,16 +1175,14 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 40, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "[10, 20, 30]" - ] + "text/plain": "[10, 20, 30]" }, - "execution_count": 15, + "execution_count": 40, "metadata": {}, "output_type": "execute_result" } @@ -437,16 +1193,14 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 41, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "[40, 50, 60]" - ] + "text/plain": "[40, 50, 60]" }, - "execution_count": 16, + "execution_count": 41, "metadata": {}, "output_type": "execute_result" } @@ -464,16 +1218,14 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 42, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "'bye'" - ] + "text/plain": "'bye'" }, - "execution_count": 17, + "execution_count": 42, "metadata": {}, "output_type": "execute_result" } @@ -485,16 +1237,14 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 43, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "'elcycib'" - ] + "text/plain": "'elcycib'" }, - "execution_count": 18, + "execution_count": 43, "metadata": {}, "output_type": "execute_result" } @@ -505,16 +1255,14 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 44, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "'eccb'" - ] + "text/plain": "'eccb'" }, - "execution_count": 19, + "execution_count": 44, "metadata": {}, "output_type": "execute_result" } @@ -527,12 +1275,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#### Example 2-9. Line items from a flat-file invoice" + "#### Example 2-13. Line items from a flat-file invoice" ] }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 45, "metadata": {}, "outputs": [ { @@ -577,16 +1325,14 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 46, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]" - ] + "text/plain": "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]" }, - "execution_count": 21, + "execution_count": 46, "metadata": {}, "output_type": "execute_result" } @@ -598,16 +1344,14 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 47, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "[0, 1, 20, 30, 5, 6, 7, 8, 9]" - ] + "text/plain": "[0, 1, 20, 30, 5, 6, 7, 8, 9]" }, - "execution_count": 22, + "execution_count": 47, "metadata": {}, "output_type": "execute_result" } @@ -619,16 +1363,14 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 48, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "[0, 1, 20, 30, 5, 8, 9]" - ] + "text/plain": "[0, 1, 20, 30, 5, 8, 9]" }, - "execution_count": 23, + "execution_count": 48, "metadata": {}, "output_type": "execute_result" } @@ -640,16 +1382,14 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 49, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "[0, 1, 20, 11, 5, 22, 9]" - ] + "text/plain": "[0, 1, 20, 11, 5, 22, 9]" }, - "execution_count": 24, + "execution_count": 49, "metadata": {}, "output_type": "execute_result" } @@ -668,7 +1408,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 50, "metadata": {}, "outputs": [ { @@ -688,16 +1428,14 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 51, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "[0, 1, 100, 22, 9]" - ] + "text/plain": "[0, 1, 100, 22, 9]" }, - "execution_count": 26, + "execution_count": 51, "metadata": {}, "output_type": "execute_result" } @@ -711,21 +1449,19 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Using + and * with Sequences" + "## Using + and * with Sequences" ] }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 52, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]" - ] + "text/plain": "[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]" }, - "execution_count": 27, + "execution_count": 52, "metadata": {}, "output_type": "execute_result" } @@ -737,16 +1473,14 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 53, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "'abcdabcdabcdabcdabcd'" - ] + "text/plain": "'abcdabcdabcdabcdabcd'" }, - "execution_count": 28, + "execution_count": 53, "metadata": {}, "output_type": "execute_result" } @@ -766,21 +1500,19 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#### Example 2-10. A list with three lists of length 3 can represent a tic-tac-toe board" + "#### Example 2-14. A list with three lists of length 3 can represent a tic-tac-toe board" ] }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 54, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]" - ] + "text/plain": "[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]" }, - "execution_count": 29, + "execution_count": 54, "metadata": {}, "output_type": "execute_result" } @@ -792,16 +1524,14 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 55, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "[['_', '_', '_'], ['_', '_', 'X'], ['_', '_', '_']]" - ] + "text/plain": "[['_', '_', '_'], ['_', '_', 'X'], ['_', '_', '_']]" }, - "execution_count": 30, + "execution_count": 55, "metadata": {}, "output_type": "execute_result" } @@ -815,21 +1545,19 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#### Example 2-11. A list with three references to the same list is useless" + "#### Example 2-15. A list with three references to the same list is useless" ] }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 56, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]" - ] + "text/plain": "[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]" }, - "execution_count": 31, + "execution_count": 56, "metadata": {}, "output_type": "execute_result" } @@ -841,16 +1569,14 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 57, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "[['_', '_', 'O'], ['_', '_', 'O'], ['_', '_', 'O']]" - ] + "text/plain": "[['_', '_', 'O'], ['_', '_', 'O'], ['_', '_', 'O']]" }, - "execution_count": 32, + "execution_count": 57, "metadata": {}, "output_type": "execute_result" } @@ -869,16 +1595,14 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 58, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]" - ] + "text/plain": "[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]" }, - "execution_count": 33, + "execution_count": 58, "metadata": {}, "output_type": "execute_result" } @@ -893,16 +1617,14 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 59, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "[['_', '_', '_'], ['_', '_', '_'], ['X', '_', '_']]" - ] + "text/plain": "[['_', '_', '_'], ['_', '_', '_'], ['X', '_', '_']]" }, - "execution_count": 34, + "execution_count": 59, "metadata": {}, "output_type": "execute_result" } @@ -921,7 +1643,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 60, "metadata": {}, "outputs": [], "source": [ @@ -931,16 +1653,14 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 61, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "4414271936" - ] + "text/plain": "140694277263808" }, - "execution_count": 36, + "execution_count": 61, "metadata": {}, "output_type": "execute_result" } @@ -952,16 +1672,14 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 62, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "[1, 2, 3, 1, 2, 3]" - ] + "text/plain": "[1, 2, 3, 1, 2, 3]" }, - "execution_count": 37, + "execution_count": 62, "metadata": {}, "output_type": "execute_result" } @@ -973,16 +1691,14 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 63, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "True" - ] + "text/plain": "True" }, - "execution_count": 38, + "execution_count": 63, "metadata": {}, "output_type": "execute_result" } @@ -993,7 +1709,7 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 64, "metadata": {}, "outputs": [], "source": [ @@ -1003,16 +1719,14 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 65, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "4414275328" - ] + "text/plain": "140694329335488" }, - "execution_count": 40, + "execution_count": 65, "metadata": {}, "output_type": "execute_result" } @@ -1024,35 +1738,34 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 66, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "False" - ] + "text/plain": "False" }, - "execution_count": 41, + "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t *= 2\n", - "id(t) == idt # new tuple" + "id(t) == idt # new tuple" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### A += Assignment Puzzler" + "### A += Assignment Puzzler\n", + "#### Example 2-16. A riddle" ] }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 67, "metadata": {}, "outputs": [ { @@ -1071,18 +1784,28 @@ " print(repr(e))" ] }, + { + "cell_type": "markdown", + "source": [ + "#### Example 2-17. The unexpected result: item t2 is changed and an exception is raised" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 68, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "(1, 2, [30, 40, 50, 60])" - ] + "text/plain": "(1, 2, [30, 40, 50, 60])" }, - "execution_count": 43, + "execution_count": 68, "metadata": {}, "output_type": "execute_result" } @@ -1095,12 +1818,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#### Example 2-14. Bytecode for the expression s[a] += b" + "#### Example 2-18. Bytecode for the expression s[a] += b" ] }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 69, "metadata": {}, "outputs": [ { @@ -1135,16 +1858,14 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 70, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "['apple', 'banana', 'grape', 'raspberry']" - ] + "text/plain": "['apple', 'banana', 'grape', 'raspberry']" }, - "execution_count": 45, + "execution_count": 70, "metadata": {}, "output_type": "execute_result" } @@ -1156,16 +1877,14 @@ }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 71, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "['grape', 'raspberry', 'apple', 'banana']" - ] + "text/plain": "['grape', 'raspberry', 'apple', 'banana']" }, - "execution_count": 46, + "execution_count": 71, "metadata": {}, "output_type": "execute_result" } @@ -1176,16 +1895,14 @@ }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 72, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "['raspberry', 'grape', 'banana', 'apple']" - ] + "text/plain": "['raspberry', 'grape', 'banana', 'apple']" }, - "execution_count": 47, + "execution_count": 72, "metadata": {}, "output_type": "execute_result" } @@ -1196,16 +1913,14 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 73, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "['grape', 'apple', 'banana', 'raspberry']" - ] + "text/plain": "['grape', 'apple', 'banana', 'raspberry']" }, - "execution_count": 48, + "execution_count": 73, "metadata": {}, "output_type": "execute_result" } @@ -1216,16 +1931,14 @@ }, { "cell_type": "code", - "execution_count": 49, + "execution_count": 74, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "['raspberry', 'banana', 'grape', 'apple']" - ] + "text/plain": "['raspberry', 'banana', 'grape', 'apple']" }, - "execution_count": 49, + "execution_count": 74, "metadata": {}, "output_type": "execute_result" } @@ -1236,16 +1949,14 @@ }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 75, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "['grape', 'raspberry', 'apple', 'banana']" - ] + "text/plain": "['grape', 'raspberry', 'apple', 'banana']" }, - "execution_count": 50, + "execution_count": 75, "metadata": {}, "output_type": "execute_result" } @@ -1256,16 +1967,14 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 76, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "['apple', 'banana', 'grape', 'raspberry']" - ] + "text/plain": "['apple', 'banana', 'grape', 'raspberry']" }, - "execution_count": 51, + "execution_count": 76, "metadata": {}, "output_type": "execute_result" } @@ -1279,322 +1988,231 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Managing Ordered Sequences with bisect" + "## When a List Is Not the Answer" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "#### Example 2-15. bisect finds insertion points for items in a sorted sequence" - ] - }, - { - "cell_type": "code", - "execution_count": 52, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DEMO: bisect_right\n", - "haystack -> 1 4 5 6 8 12 15 20 21 23 23 26 29 30\n", - "31 @ 14 | | | | | | | | | | | | | |31\n", - "30 @ 14 | | | | | | | | | | | | | |30\n", - "29 @ 13 | | | | | | | | | | | | |29\n", - "23 @ 11 | | | | | | | | | | |23\n", - "22 @ 9 | | | | | | | | |22\n", - "10 @ 5 | | | | |10\n", - " 8 @ 5 | | | | |8 \n", - " 5 @ 3 | | |5 \n", - " 2 @ 1 |2 \n", - " 1 @ 1 |1 \n", - " 0 @ 0 0 \n" - ] - } - ], - "source": [ - "# BEGIN BISECT_DEMO\n", - "import bisect\n", - "import sys\n", - "\n", - "HAYSTACK = [1, 4, 5, 6, 8, 12, 15, 20, 21, 23, 23, 26, 29, 30]\n", - "NEEDLES = [0, 1, 2, 5, 8, 10, 22, 23, 29, 30, 31]\n", - "\n", - "ROW_FMT = '{0:2d} @ {1:2d} {2}{0:<2d}'\n", - "\n", - "def demo(haystack, needles, bisect_fn):\n", - " print('DEMO:', bisect_fn.__name__) # <1>\n", - " print('haystack ->', ' '.join('%2d' % n for n in haystack))\n", - " for needle in reversed(needles):\n", - " position = bisect_fn(haystack, needle) # <2>\n", - " offset = position * ' |' # <3>\n", - " print(ROW_FMT.format(needle, position, offset)) # <4>\n", - "\n", - "demo(HAYSTACK, NEEDLES, bisect.bisect) # <5>\n", - "# END BISECT_DEMO" - ] - }, - { - "cell_type": "code", - "execution_count": 53, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DEMO: bisect_left\n", - "haystack -> 1 4 5 6 8 12 15 20 21 23 23 26 29 30\n", - "31 @ 14 | | | | | | | | | | | | | |31\n", - "30 @ 13 | | | | | | | | | | | | |30\n", - "29 @ 12 | | | | | | | | | | | |29\n", - "23 @ 9 | | | | | | | | |23\n", - "22 @ 9 | | | | | | | | |22\n", - "10 @ 5 | | | | |10\n", - " 8 @ 4 | | | |8 \n", - " 5 @ 2 | |5 \n", - " 2 @ 1 |2 \n", - " 1 @ 0 1 \n", - " 0 @ 0 0 \n" - ] - } - ], - "source": [ - "demo(HAYSTACK, NEEDLES, bisect.bisect_left)" + "### Arrays" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "#### Example 2-16. Given a test score, grade returns the corresponding letter grade" + "#### Example 2-19. Creating, saving, and loading a large array of floats" ] }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 77, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "['F', 'D', 'D', 'C', 'C', 'B', 'B', 'A', 'A']" - ] + "text/plain": "0.8190492979077034" }, - "execution_count": 54, + "execution_count": 77, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "def grade(score, breakpoints=[60, 70, 80, 90], grades='FDCBA'):\n", - " i = bisect.bisect(breakpoints, score)\n", - " return grades[i]\n", + "from array import array\n", + "from random import random, seed\n", + "seed(10) # Use seed to make the output consistent\n", "\n", - "[grade(score) for score in [55, 60, 65, 70, 75, 80, 85, 90, 95]]" + "floats = array('d', (random() for i in range(10 ** 7)))\n", + "floats[-1]" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 78, "metadata": {}, + "outputs": [], "source": [ - "#### Example 2-17. bisect_left maps a score of 60 to grade F, not D as in Example 2-16." + "with open('floats.bin', 'wb') as fp:\n", + " floats.tofile(fp)" ] }, { "cell_type": "code", - "execution_count": 55, + "execution_count": 79, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "['F', 'F', 'D', 'D', 'C', 'C', 'B', 'B', 'A']" - ] + "text/plain": "0.8190492979077034" }, - "execution_count": 55, + "execution_count": 79, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "def grade(score, breakpoints=[60, 70, 80, 90], grades='FDCBA'):\n", - " i = bisect.bisect_left(breakpoints, score)\n", - " return grades[i]\n", + "floats2 = array('d')\n", "\n", - "[grade(score) for score in [55, 60, 65, 70, 75, 80, 85, 90, 95]]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Example 2-18. Insort keeps a sorted sequence always sorted" + "with open('floats.bin', 'rb') as fp:\n", + " floats2.fromfile(fp, 10 ** 7)\n", + "\n", + "floats2[-1]" ] }, { "cell_type": "code", - "execution_count": 56, + "execution_count": 80, "metadata": {}, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "insert 10 -> [10]\n", - "insert 0 -> [0, 10]\n", - "insert 6 -> [0, 6, 10]\n", - "insert 8 -> [0, 6, 8, 10]\n", - "insert 7 -> [0, 6, 7, 8, 10]\n", - "insert 2 -> [0, 2, 6, 7, 8, 10]\n", - "insert 10 -> [0, 2, 6, 7, 8, 10, 10]\n" - ] + "data": { + "text/plain": "True" + }, + "execution_count": 80, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ - "import bisect\n", - "import random\n", - "\n", - "SIZE = 7\n", - "\n", - "random.seed(1729)\n", - "\n", - "my_list = []\n", - "\n", - "for i in range(SIZE):\n", - " new_item = random.randrange(SIZE*2)\n", - " bisect.insort(my_list, new_item)\n", - " print(f'insert {new_item:2d} -> {my_list}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## When a List Is Not the Answer" + "floats2 == floats" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Arrays" + "### Memory Views" ] }, { "cell_type": "markdown", - "metadata": {}, "source": [ - "#### Example 2-19. Creating, saving, and loading a large array of floats" - ] + "#### Example 2-20. Handling 6 bytes memory of as 1×6, 2×3, and 3×2 views" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } }, { "cell_type": "code", - "execution_count": 57, - "metadata": {}, + "execution_count": 81, "outputs": [ { "data": { - "text/plain": [ - "0.5963321947530882" - ] + "text/plain": "[0, 1, 2, 3, 4, 5]" }, - "execution_count": 57, + "execution_count": 81, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "from array import array\n", - "from random import random\n", - "\n", - "floats = array('d', (random() for i in range(10**7)))\n", - "floats[-1]" - ] + "octets = array('B', range(6))\n", + "m1 = memoryview(octets)\n", + "m1.tolist()" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } }, { "cell_type": "code", - "execution_count": 58, - "metadata": {}, - "outputs": [], + "execution_count": 82, + "outputs": [ + { + "data": { + "text/plain": "[[0, 1, 2], [3, 4, 5]]" + }, + "execution_count": 82, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "with open('floats.bin', 'wb') as fp:\n", - " floats.tofile(fp)" - ] + "m2 = m1.cast('B', [2, 3])\n", + "m2.tolist()" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } }, { "cell_type": "code", - "execution_count": 59, - "metadata": {}, + "execution_count": 83, "outputs": [ { "data": { - "text/plain": [ - "0.5963321947530882" - ] + "text/plain": "[[0, 1], [2, 3], [4, 5]]" }, - "execution_count": 59, + "execution_count": 83, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "floats2 = array('d')\n", - "\n", - "with open('floats.bin', 'rb') as fp:\n", - " floats2.fromfile(fp, 10**7)\n", - "\n", - "floats2[-1]" - ] + "m3 = m1.cast('B', [3, 2])\n", + "m3.tolist()" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } }, { "cell_type": "code", - "execution_count": 60, - "metadata": {}, + "execution_count": 84, "outputs": [ { "data": { - "text/plain": [ - "True" - ] + "text/plain": "array('B', [0, 1, 2, 33, 22, 5])" }, - "execution_count": 60, + "execution_count": 84, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "floats2 == floats" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Memory Views" - ] + "m2[1,1] = 22\n", + "m3[1,1] = 33\n", + "octets" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } }, { "cell_type": "markdown", "metadata": {}, "source": [ - "#### Example 2-20. Changing the value of an array item by poking one of its bytes" + "#### Example 2-21. Changing the value of an 16-bit integer array item by poking one of its bytes" ] }, { "cell_type": "code", - "execution_count": 61, + "execution_count": 85, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "5" - ] + "text/plain": "5" }, - "execution_count": 61, + "execution_count": 85, "metadata": {}, "output_type": "execute_result" } @@ -1607,16 +2225,14 @@ }, { "cell_type": "code", - "execution_count": 62, + "execution_count": 86, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "-2" - ] + "text/plain": "-2" }, - "execution_count": 62, + "execution_count": 86, "metadata": {}, "output_type": "execute_result" } @@ -1627,16 +2243,14 @@ }, { "cell_type": "code", - "execution_count": 63, + "execution_count": 87, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "[254, 255, 255, 255, 0, 0, 1, 0, 2, 0]" - ] + "text/plain": "[254, 255, 255, 255, 0, 0, 1, 0, 2, 0]" }, - "execution_count": 63, + "execution_count": 87, "metadata": {}, "output_type": "execute_result" } @@ -1648,16 +2262,14 @@ }, { "cell_type": "code", - "execution_count": 64, + "execution_count": 88, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "array('h', [-2, -1, 1024, 1, 2])" - ] + "text/plain": "array('h', [-2, -1, 1024, 1, 2])" }, - "execution_count": 64, + "execution_count": 88, "metadata": {}, "output_type": "execute_result" } @@ -1671,50 +2283,47 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### NumPy and SciPy" + "### NumPy" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "#### Example 2-21. Basic operations with rows and columns in a numpy.ndarray" + "#### Example 2-22. Basic operations with rows and columns in a numpy.ndarray" ] }, { "cell_type": "code", - "execution_count": 65, + "execution_count": 89, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])" - ] + "text/plain": "array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])" }, - "execution_count": 65, + "execution_count": 89, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import numpy as np\n", + "\n", "a = np.arange(12)\n", "a" ] }, { "cell_type": "code", - "execution_count": 66, + "execution_count": 90, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "numpy.ndarray" - ] + "text/plain": "numpy.ndarray" }, - "execution_count": 66, + "execution_count": 90, "metadata": {}, "output_type": "execute_result" } @@ -1725,16 +2334,14 @@ }, { "cell_type": "code", - "execution_count": 67, + "execution_count": 91, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "(12,)" - ] + "text/plain": "(12,)" }, - "execution_count": 67, + "execution_count": 91, "metadata": {}, "output_type": "execute_result" } @@ -1745,18 +2352,14 @@ }, { "cell_type": "code", - "execution_count": 68, + "execution_count": 92, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "array([[ 0, 1, 2, 3],\n", - " [ 4, 5, 6, 7],\n", - " [ 8, 9, 10, 11]])" - ] + "text/plain": "array([[ 0, 1, 2, 3],\n [ 4, 5, 6, 7],\n [ 8, 9, 10, 11]])" }, - "execution_count": 68, + "execution_count": 92, "metadata": {}, "output_type": "execute_result" } @@ -1768,16 +2371,14 @@ }, { "cell_type": "code", - "execution_count": 69, + "execution_count": 93, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "array([ 8, 9, 10, 11])" - ] + "text/plain": "array([ 8, 9, 10, 11])" }, - "execution_count": 69, + "execution_count": 93, "metadata": {}, "output_type": "execute_result" } @@ -1788,16 +2389,14 @@ }, { "cell_type": "code", - "execution_count": 70, + "execution_count": 94, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "9" - ] + "text/plain": "9" }, - "execution_count": 70, + "execution_count": 94, "metadata": {}, "output_type": "execute_result" } @@ -1808,16 +2407,14 @@ }, { "cell_type": "code", - "execution_count": 71, + "execution_count": 95, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "array([1, 5, 9])" - ] + "text/plain": "array([1, 5, 9])" }, - "execution_count": 71, + "execution_count": 95, "metadata": {}, "output_type": "execute_result" } @@ -1828,25 +2425,20 @@ }, { "cell_type": "code", - "execution_count": 72, + "execution_count": 96, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "array([[ 0, 4, 8],\n", - " [ 1, 5, 9],\n", - " [ 2, 6, 10],\n", - " [ 3, 7, 11]])" - ] + "text/plain": "array([[ 0, 4, 8],\n [ 1, 5, 9],\n [ 2, 6, 10],\n [ 3, 7, 11]])" }, - "execution_count": 72, + "execution_count": 96, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "a.transpose()\n" + "a.transpose()" ] }, { @@ -1858,7 +2450,7 @@ }, { "cell_type": "code", - "execution_count": 73, + "execution_count": 97, "metadata": {}, "outputs": [], "source": [ @@ -1869,7 +2461,7 @@ }, { "cell_type": "code", - "execution_count": 74, + "execution_count": 98, "metadata": {}, "outputs": [], "source": [ @@ -1878,16 +2470,14 @@ }, { "cell_type": "code", - "execution_count": 75, + "execution_count": 99, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "array([0.29150425, 0.33893554, 0.08112756])" - ] + "text/plain": "array([0.06078257, 0.61741189, 0.84349987])" }, - "execution_count": 75, + "execution_count": 99, "metadata": {}, "output_type": "execute_result" } @@ -1898,16 +2488,14 @@ }, { "cell_type": "code", - "execution_count": 76, + "execution_count": 100, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "array([0.14575213, 0.16946777, 0.04056378])" - ] + "text/plain": "array([0.03039128, 0.30870594, 0.42174994])" }, - "execution_count": 76, + "execution_count": 100, "metadata": {}, "output_type": "execute_result" } @@ -1919,16 +2507,14 @@ }, { "cell_type": "code", - "execution_count": 77, + "execution_count": 101, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "True" - ] + "text/plain": "True" }, - "execution_count": 77, + "execution_count": 101, "metadata": {}, "output_type": "execute_result" } @@ -1943,7 +2529,7 @@ }, { "cell_type": "code", - "execution_count": 78, + "execution_count": 102, "metadata": {}, "outputs": [], "source": [ @@ -1954,16 +2540,14 @@ }, { "cell_type": "code", - "execution_count": 79, + "execution_count": 103, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "memmap([0.29150425, 0.33893554, 0.08112756])" - ] + "text/plain": "memmap([0.06078257, 0.61741189, 0.84349987])" }, - "execution_count": 79, + "execution_count": 103, "metadata": {}, "output_type": "execute_result" } @@ -1983,21 +2567,19 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#### Example 2-22. Working with a deque" + "#### Example 2-23. Working with a deque" ] }, { "cell_type": "code", - "execution_count": 80, + "execution_count": 104, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" - ] + "text/plain": "deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" }, - "execution_count": 80, + "execution_count": 104, "metadata": {}, "output_type": "execute_result" } @@ -2011,16 +2593,14 @@ }, { "cell_type": "code", - "execution_count": 81, + "execution_count": 105, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "deque([7, 8, 9, 0, 1, 2, 3, 4, 5, 6])" - ] + "text/plain": "deque([7, 8, 9, 0, 1, 2, 3, 4, 5, 6])" }, - "execution_count": 81, + "execution_count": 105, "metadata": {}, "output_type": "execute_result" } @@ -2032,16 +2612,14 @@ }, { "cell_type": "code", - "execution_count": 82, + "execution_count": 106, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "deque([1, 2, 3, 4, 5, 6, 7, 8, 9, 0])" - ] + "text/plain": "deque([1, 2, 3, 4, 5, 6, 7, 8, 9, 0])" }, - "execution_count": 82, + "execution_count": 106, "metadata": {}, "output_type": "execute_result" } @@ -2053,16 +2631,14 @@ }, { "cell_type": "code", - "execution_count": 83, + "execution_count": 107, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "deque([-1, 1, 2, 3, 4, 5, 6, 7, 8, 9])" - ] + "text/plain": "deque([-1, 1, 2, 3, 4, 5, 6, 7, 8, 9])" }, - "execution_count": 83, + "execution_count": 107, "metadata": {}, "output_type": "execute_result" } @@ -2074,16 +2650,14 @@ }, { "cell_type": "code", - "execution_count": 84, + "execution_count": 108, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "deque([3, 4, 5, 6, 7, 8, 9, 11, 22, 33])" - ] + "text/plain": "deque([3, 4, 5, 6, 7, 8, 9, 11, 22, 33])" }, - "execution_count": 84, + "execution_count": 108, "metadata": {}, "output_type": "execute_result" } @@ -2095,16 +2669,14 @@ }, { "cell_type": "code", - "execution_count": 85, + "execution_count": 109, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "deque([40, 30, 20, 10, 3, 4, 5, 6, 7, 8])" - ] + "text/plain": "deque([40, 30, 20, 10, 3, 4, 5, 6, 7, 8])" }, - "execution_count": 85, + "execution_count": 109, "metadata": {}, "output_type": "execute_result" } @@ -2130,7 +2702,7 @@ }, { "cell_type": "code", - "execution_count": 86, + "execution_count": 110, "metadata": {}, "outputs": [], "source": [ @@ -2139,7 +2711,7 @@ }, { "cell_type": "code", - "execution_count": 87, + "execution_count": 111, "metadata": {}, "outputs": [ { @@ -2166,16 +2738,14 @@ }, { "cell_type": "code", - "execution_count": 88, + "execution_count": 112, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "[0, '1', 5, 6, '9', 14, 19, '23', 28, '28']" - ] + "text/plain": "[0, '1', 5, 6, '9', 14, 19, '23', 28, '28']" }, - "execution_count": 88, + "execution_count": 112, "metadata": {}, "output_type": "execute_result" } @@ -2188,16 +2758,14 @@ }, { "cell_type": "code", - "execution_count": 89, + "execution_count": 113, "metadata": {}, "outputs": [ { "data": { - "text/plain": [ - "[0, '1', 14, 19, '23', 28, '28', 5, 6, '9']" - ] + "text/plain": "[0, '1', 14, 19, '23', 28, '28', 5, 6, '9']" }, - "execution_count": 89, + "execution_count": 113, "metadata": {}, "output_type": "execute_result" } @@ -2208,7 +2776,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 113, "metadata": {}, "outputs": [], "source": [] @@ -2235,4 +2803,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file From 434f8d26b6a11e6f59aba288933192af92f211ad Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Fri, 1 Apr 2022 17:23:12 -0300 Subject: [PATCH 42/66] covariance v. contravariance in Callable --- 08-def-type-hints/callable/variance.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 08-def-type-hints/callable/variance.py diff --git a/08-def-type-hints/callable/variance.py b/08-def-type-hints/callable/variance.py new file mode 100644 index 0000000..fcddbde --- /dev/null +++ b/08-def-type-hints/callable/variance.py @@ -0,0 +1,22 @@ +from collections.abc import Callable + +def update( # <1> + probe: Callable[[], float], # <2> + display: Callable[[float], None] # <3> + ) -> None: + temperature = probe() + # imagine lots of control code here + display(temperature) + +def probe_ok() -> int: # <4> + return 42 + +def display_wrong(temperature: int) -> None: # <5> + print(hex(temperature)) + +update(probe_ok, display_wrong) # type error # <6> + +def display_ok(temperature: complex) -> None: # <7> + print(temperature) + +update(probe_ok, display_ok) # OK # <8> From 08230737cc9b32a87510b517c448a2ca71a0fa18 Mon Sep 17 00:00:00 2001 From: Eduardo Scartezini Date: Fri, 8 Jul 2022 17:44:09 +0100 Subject: [PATCH 43/66] Fix chapter number to 2ed edition On 2ed the chapter "Object references, mutability and recycling" from 8 to 6 This commit fixes the readme with the new chapter number --- 06-obj-ref/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/06-obj-ref/README.rst b/06-obj-ref/README.rst index deac2fa..0d705e6 100644 --- a/06-obj-ref/README.rst +++ b/06-obj-ref/README.rst @@ -1,4 +1,4 @@ -Sample code for Chapter 8 - "Object references, mutability and recycling" +Sample code for Chapter 6 - "Object references, mutability and recycling" From the book "Fluent Python" by Luciano Ramalho (O'Reilly, 2015) http://shop.oreilly.com/product/0636920032519.do From d00908d553a9746ea3c855c99c78a9d7308e1b23 Mon Sep 17 00:00:00 2001 From: Vlad Grin <67241634+grinvlad@users.noreply.github.com> Date: Sun, 31 Jul 2022 18:41:59 +0300 Subject: [PATCH 44/66] Fix filename in script --- 02-array-seq/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/02-array-seq/test.sh b/02-array-seq/test.sh index 4747320..906717d 100755 --- a/02-array-seq/test.sh +++ b/02-array-seq/test.sh @@ -1,4 +1,4 @@ #!/bin/bash python3 -m doctest bisect_demo.py -python3 -m doctest metro_lat_long.py +python3 -m doctest metro_lat_lon.py pytest -q --nbval From 3f9c89554aa5a14837e6f1977317b415ffab4ea1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 9 Dec 2022 05:48:20 +0000 Subject: [PATCH 45/66] build(deps): bump certifi in /20-executors/getflags Bumps [certifi](https://github.com/certifi/python-certifi) from 2021.5.30 to 2022.12.7. - [Release notes](https://github.com/certifi/python-certifi/releases) - [Commits](https://github.com/certifi/python-certifi/compare/2021.05.30...2022.12.07) --- updated-dependencies: - dependency-name: certifi dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- 20-executors/getflags/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/20-executors/getflags/requirements.txt b/20-executors/getflags/requirements.txt index b8bb630..5dc5007 100644 --- a/20-executors/getflags/requirements.txt +++ b/20-executors/getflags/requirements.txt @@ -1,5 +1,5 @@ anyio==3.3.2 -certifi==2021.5.30 +certifi==2022.12.7 charset-normalizer==2.0.6 h11==0.12.0 httpcore==0.13.7 From d3309f03e88ce449c8f45beee25621221db86217 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Feb 2023 22:09:42 +0000 Subject: [PATCH 46/66] build(deps): bump starlette in /21-async/mojifinder Bumps [starlette](https://github.com/encode/starlette) from 0.13.6 to 0.25.0. - [Release notes](https://github.com/encode/starlette/releases) - [Changelog](https://github.com/encode/starlette/blob/master/docs/release-notes.md) - [Commits](https://github.com/encode/starlette/compare/0.13.6...0.25.0) --- updated-dependencies: - dependency-name: starlette dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- 21-async/mojifinder/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/21-async/mojifinder/requirements.txt b/21-async/mojifinder/requirements.txt index 1f7c3d6..4a1c97a 100644 --- a/21-async/mojifinder/requirements.txt +++ b/21-async/mojifinder/requirements.txt @@ -2,6 +2,6 @@ click==7.1.2 fastapi==0.65.2 h11==0.12.0 pydantic==1.8.2 -starlette==0.13.6 +starlette==0.25.0 typing-extensions==3.7.4.3 uvicorn==0.13.4 From 51055887dd6cca6c0b67e1f0072ec33d1eaa6351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Andr=C3=A9s=20=C3=81lvarez=20Restrepo?= Date: Sun, 26 Mar 2023 17:28:08 -0500 Subject: [PATCH 47/66] Update flags2_asyncio.py Fix `error` variable not being reset when a successful coroutine call --- 20-executors/getflags/flags2_asyncio.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/20-executors/getflags/flags2_asyncio.py b/20-executors/getflags/flags2_asyncio.py index 4f1849a..b697840 100755 --- a/20-executors/getflags/flags2_asyncio.py +++ b/20-executors/getflags/flags2_asyncio.py @@ -79,6 +79,8 @@ async def supervisor(cc_list: list[str], error = exc # <10> except KeyboardInterrupt: break + else: + error = None if error: status = DownloadStatus.ERROR # <11> From 166a388ac84cbdea1c27404acfe1453c7bb6eb51 Mon Sep 17 00:00:00 2001 From: Mehdi Abbassi Date: Fri, 29 Sep 2023 07:46:37 +0330 Subject: [PATCH 48/66] using f-strings instead of % operator --- 01-data-model/data-model.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/01-data-model/data-model.ipynb b/01-data-model/data-model.ipynb index f525899..5b30397 100644 --- a/01-data-model/data-model.ipynb +++ b/01-data-model/data-model.ipynb @@ -482,7 +482,7 @@ " self.y = y\n", "\n", " def __repr__(self):\n", - " return 'Vector(%r, %r)' % (self.x, self.y)\n", + " return f'Vector({self.x!r}, {self.y!r})'\n", "\n", " def __abs__(self):\n", " return math.hypot(self.x, self.y)\n", From 567f3529e35fccc0087c9555f9fcd72c90043564 Mon Sep 17 00:00:00 2001 From: Tudor Capusan Date: Sun, 16 Jun 2024 11:37:29 -0400 Subject: [PATCH 49/66] fix spelling change from 'reminder' to 'remainder' to match intent --- 17-it-generator/columnize_iter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/17-it-generator/columnize_iter.py b/17-it-generator/columnize_iter.py index cee0f13..4362bc1 100644 --- a/17-it-generator/columnize_iter.py +++ b/17-it-generator/columnize_iter.py @@ -6,8 +6,8 @@ def columnize( ) -> Iterator[tuple[str, ...]]: # <1> if num_columns == 0: num_columns = round(len(sequence) ** 0.5) - num_rows, reminder = divmod(len(sequence), num_columns) - num_rows += bool(reminder) + num_rows, remainder = divmod(len(sequence), num_columns) + num_rows += bool(remainder) return (tuple(sequence[i::num_rows]) for i in range(num_rows)) # <2> # end::COLUMNIZE[] From 74ee1d4915d91b0af9013eb8fecf0302ca7f40c9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 19:51:04 +0000 Subject: [PATCH 50/66] build(deps): bump idna from 3.2 to 3.7 in /20-executors/getflags Bumps [idna](https://github.com/kjd/idna) from 3.2 to 3.7. - [Release notes](https://github.com/kjd/idna/releases) - [Changelog](https://github.com/kjd/idna/blob/master/HISTORY.rst) - [Commits](https://github.com/kjd/idna/compare/v3.2...v3.7) --- updated-dependencies: - dependency-name: idna dependency-version: '3.7' dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- 20-executors/getflags/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/20-executors/getflags/requirements.txt b/20-executors/getflags/requirements.txt index 5dc5007..c5fb66c 100644 --- a/20-executors/getflags/requirements.txt +++ b/20-executors/getflags/requirements.txt @@ -4,7 +4,7 @@ charset-normalizer==2.0.6 h11==0.12.0 httpcore==0.13.7 httpx==1.0.0b0 -idna==3.2 +idna==3.7 rfc3986==1.5.0 sniffio==1.2.0 tqdm==4.62.3 From 1b44dfaf11bf9bc8d87339f9fb8eddb294014f07 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 19:51:09 +0000 Subject: [PATCH 51/66] build(deps): bump starlette in /21-async/mojifinder Bumps [starlette](https://github.com/encode/starlette) from 0.25.0 to 0.40.0. - [Release notes](https://github.com/encode/starlette/releases) - [Changelog](https://github.com/encode/starlette/blob/master/docs/release-notes.md) - [Commits](https://github.com/encode/starlette/compare/0.25.0...0.40.0) --- updated-dependencies: - dependency-name: starlette dependency-version: 0.40.0 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- 21-async/mojifinder/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/21-async/mojifinder/requirements.txt b/21-async/mojifinder/requirements.txt index 4a1c97a..72231bf 100644 --- a/21-async/mojifinder/requirements.txt +++ b/21-async/mojifinder/requirements.txt @@ -2,6 +2,6 @@ click==7.1.2 fastapi==0.65.2 h11==0.12.0 pydantic==1.8.2 -starlette==0.25.0 +starlette==0.40.0 typing-extensions==3.7.4.3 uvicorn==0.13.4 From d14c7bed18737930eebb0d398c609b4b9657753a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 19:51:11 +0000 Subject: [PATCH 52/66] build(deps): bump certifi in /20-executors/getflags Bumps [certifi](https://github.com/certifi/python-certifi) from 2022.12.7 to 2024.7.4. - [Commits](https://github.com/certifi/python-certifi/compare/2022.12.07...2024.07.04) --- updated-dependencies: - dependency-name: certifi dependency-version: 2024.7.4 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- 20-executors/getflags/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/20-executors/getflags/requirements.txt b/20-executors/getflags/requirements.txt index 5dc5007..06da86c 100644 --- a/20-executors/getflags/requirements.txt +++ b/20-executors/getflags/requirements.txt @@ -1,5 +1,5 @@ anyio==3.3.2 -certifi==2022.12.7 +certifi==2024.7.4 charset-normalizer==2.0.6 h11==0.12.0 httpcore==0.13.7 From 8e911b19be0159c8d5ff6e36c56ddc7a799de788 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 19:51:51 +0000 Subject: [PATCH 53/66] build(deps): bump tqdm from 4.62.3 to 4.66.3 in /20-executors/getflags Bumps [tqdm](https://github.com/tqdm/tqdm) from 4.62.3 to 4.66.3. - [Release notes](https://github.com/tqdm/tqdm/releases) - [Commits](https://github.com/tqdm/tqdm/compare/v4.62.3...v4.66.3) --- updated-dependencies: - dependency-name: tqdm dependency-version: 4.66.3 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- 20-executors/getflags/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/20-executors/getflags/requirements.txt b/20-executors/getflags/requirements.txt index 5dc5007..5412046 100644 --- a/20-executors/getflags/requirements.txt +++ b/20-executors/getflags/requirements.txt @@ -7,4 +7,4 @@ httpx==1.0.0b0 idna==3.2 rfc3986==1.5.0 sniffio==1.2.0 -tqdm==4.62.3 +tqdm==4.66.3 From 68de220bd1950731b6cd50c0a0834647bbf6bd29 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 19:51:51 +0000 Subject: [PATCH 54/66] build(deps): bump future in /08-def-type-hints/coordinates Bumps [future](https://github.com/PythonCharmers/python-future) from 0.18.2 to 0.18.3. - [Release notes](https://github.com/PythonCharmers/python-future/releases) - [Changelog](https://github.com/PythonCharmers/python-future/blob/master/docs/changelog.rst) - [Commits](https://github.com/PythonCharmers/python-future/compare/v0.18.2...v0.18.3) --- updated-dependencies: - dependency-name: future dependency-version: 0.18.3 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- 08-def-type-hints/coordinates/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/08-def-type-hints/coordinates/requirements.txt b/08-def-type-hints/coordinates/requirements.txt index fb11094..7b7b424 100644 --- a/08-def-type-hints/coordinates/requirements.txt +++ b/08-def-type-hints/coordinates/requirements.txt @@ -1,2 +1,2 @@ geolib==1.0.7 -future==0.18.2 +future==0.18.3 From 74c52779b4fc88a217a96e0ec5a1c0029516096a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 19:53:20 +0000 Subject: [PATCH 55/66] build(deps): bump h11 from 0.12.0 to 0.16.0 in /20-executors/getflags Bumps [h11](https://github.com/python-hyper/h11) from 0.12.0 to 0.16.0. - [Commits](https://github.com/python-hyper/h11/compare/v0.12.0...v0.16.0) --- updated-dependencies: - dependency-name: h11 dependency-version: 0.16.0 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- 20-executors/getflags/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/20-executors/getflags/requirements.txt b/20-executors/getflags/requirements.txt index 464188b..6d74412 100644 --- a/20-executors/getflags/requirements.txt +++ b/20-executors/getflags/requirements.txt @@ -1,7 +1,7 @@ anyio==3.3.2 certifi==2024.7.4 charset-normalizer==2.0.6 -h11==0.12.0 +h11==0.16.0 httpcore==0.13.7 httpx==1.0.0b0 idna==3.2 From ab8a774924029233cfe1f6116d7c7a838c3485c7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 19:55:09 +0000 Subject: [PATCH 56/66] build(deps): bump pydantic from 1.8.2 to 1.10.13 in /21-async/mojifinder Bumps [pydantic](https://github.com/pydantic/pydantic) from 1.8.2 to 1.10.13. - [Release notes](https://github.com/pydantic/pydantic/releases) - [Changelog](https://github.com/pydantic/pydantic/blob/main/HISTORY.md) - [Commits](https://github.com/pydantic/pydantic/compare/v1.8.2...v1.10.13) --- updated-dependencies: - dependency-name: pydantic dependency-version: 1.10.13 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- 21-async/mojifinder/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/21-async/mojifinder/requirements.txt b/21-async/mojifinder/requirements.txt index 72231bf..f7de911 100644 --- a/21-async/mojifinder/requirements.txt +++ b/21-async/mojifinder/requirements.txt @@ -1,7 +1,7 @@ click==7.1.2 fastapi==0.65.2 h11==0.12.0 -pydantic==1.8.2 +pydantic==1.10.13 starlette==0.40.0 typing-extensions==3.7.4.3 uvicorn==0.13.4 From 1bd4b1e7be896069225e72ac89303a26a8be46f3 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Wed, 21 May 2025 12:00:57 -0300 Subject: [PATCH 57/66] documentando FPY.LI.htacess --- links/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/links/README.md b/links/README.md index 6da595c..6c9cfa8 100644 --- a/links/README.md +++ b/links/README.md @@ -23,6 +23,7 @@ Please report broken links as bugs in the [`FPY.LI.htaccess`](FPY.LI.htaccess) f Also, feel free to send pull requests with fixes to that file. When I accept a PR, I will redeploy it to `fpy.li/.htaccess`. + ## Details Almost all URLs in the book are replaced with shortened versions like @@ -37,4 +38,8 @@ Exceptions: - URLs with `oreilly` in them are unchanged; - `fluentpython.com` URL (with no path) is unchanged; +The `custom.htacess` file contains the top redirects, which have custom names. +`FPY.LI.htaccess` has the same content, plus numbered URLs generated +from the links in each chapter in the book. + The `FPY.LI.htaccess` is deployed at the root folder in `http://fpy.li`. From 3d5588b75ee44ce650b82b87922bc40b6ea6615c Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Thu, 22 May 2025 01:11:34 -0300 Subject: [PATCH 58/66] gerador de URLs curtas --- links/FPY.LI.htaccess | 1074 +---------------------------------------- links/README.md | 15 +- links/custom.htaccess | 956 ++++++++++++++++++++++++++++++++++++ links/short.htaccess | 1 + links/short.py | 81 ++++ 5 files changed, 1051 insertions(+), 1076 deletions(-) create mode 100644 links/short.htaccess create mode 100755 links/short.py diff --git a/links/FPY.LI.htaccess b/links/FPY.LI.htaccess index cc779db..7338157 100644 --- a/links/FPY.LI.htaccess +++ b/links/FPY.LI.htaccess @@ -1,1072 +1,2 @@ -ErrorDocument 404 /404.html - -# main resources -RedirectTemp /book https://www.oreilly.com/library/view/fluent-python-2nd/9781492056348/ -RedirectTemp /code https://github.com/fluentpython/example-code-2e -RedirectTemp /home https://www.fluentpython.com/ - -# URLs mentioned at least three times -RedirectTemp /bisect https://www.fluentpython.com/extra/ordered-sequences-with-bisect/ -RedirectTemp /cardxvi https://www.python.org/dev/peps/pep-0484/#the-numeric-tower -RedirectTemp /collec https://docs.python.org/3/library/collections.html -RedirectTemp /dask https://dask.org/ -RedirectTemp /dtmodel https://docs.python.org/3/reference/datamodel.html -RedirectTemp /descr101 https://www.python.org/download/releases/2.2.3/descrintro/ -RedirectTemp /descrhow https://docs.python.org/3/howto/descriptor.html -RedirectTemp /doctest https://docs.python.org/3/library/doctest.html -RedirectTemp /effectpy https://effectivepython.com/ -RedirectTemp /fmtspec https://docs.python.org/3/library/string.html#formatspec -RedirectTemp /gunicorn https://gunicorn.org/ -RedirectTemp /hashint https://www.fluentpython.com/extra/internals-of-sets-and-dicts/ -RedirectTemp /hattingh https://www.oreilly.com/library/view/using-asyncio-in/9781492075325/ -RedirectTemp /httpx https://www.python-httpx.org/ -RedirectTemp /initvar https://docs.python.org/3/library/dataclasses.html#init-only-variables -RedirectTemp /mypy https://mypy.readthedocs.io/en/stable/ -RedirectTemp /norvigdp http://norvig.com/design-patterns/ -RedirectTemp /nsphere https://en.wikipedia.org/wiki/N-sphere -RedirectTemp /oldcoro https://www.fluentpython.com/extra/classic-coroutines/ -RedirectTemp /pandas https://pandas.pydata.org/ -RedirectTemp /pycook3 https://www.oreilly.com/library/view/python-cookbook-3rd/9781449357337/ -RedirectTemp /pynut3 https://www.oreilly.com/library/view/python-in-a/9781491913833/ -RedirectTemp /pypydif https://doc.pypy.org/en/latest/cpython_differences.html#subclasses-of-built-in-types -RedirectTemp /shed4051 https://github.com/python/typeshed/issues/4051 -RedirectTemp /specattr https://docs.python.org/3/library/stdtypes.html#special-attributes -RedirectTemp /typecoro https://docs.python.org/3.10/library/typing.html#typing.Coroutine -RedirectTemp /typing https://docs.python.org/3/library/typing.html -RedirectTemp /weakref https://www.fluentpython.com/extra/weak-references/ - -# URL added during QA of the Second Edition -RedirectTemp /bdfl https://www.artima.com/weblogs/viewpost.jsp?thread=235725 - -# Python Enhancement Proposals -RedirectTemp /pep218 https://www.python.org/dev/peps/pep-0218/ -RedirectTemp /pep227 https://www.python.org/dev/peps/pep-0227/ -RedirectTemp /pep255 https://www.python.org/dev/peps/pep-0255/ -RedirectTemp /pep342 https://www.python.org/dev/peps/pep-0342/ -RedirectTemp /pep343 https://www.python.org/dev/peps/pep-0343/ -RedirectTemp /pep357 https://www.python.org/dev/peps/pep-0357/ -RedirectTemp /pep362 https://www.python.org/dev/peps/pep-0362/ -RedirectTemp /pep371 https://www.python.org/dev/peps/pep-0371/ -RedirectTemp /pep380 https://www.python.org/dev/peps/pep-0380/ -RedirectTemp /pep393 https://www.python.org/dev/peps/pep-0393/ -RedirectTemp /pep412 https://www.python.org/dev/peps/pep-0412/ -RedirectTemp /pep442 https://www.python.org/dev/peps/pep-0442/ -RedirectTemp /pep443 https://www.python.org/dev/peps/pep-0443/ -RedirectTemp /pep448 https://www.python.org/dev/peps/pep-0448/ -RedirectTemp /pep455 https://www.python.org/dev/peps/pep-0455/ -RedirectTemp /pep456 https://www.python.org/dev/peps/pep-0456/ -RedirectTemp /pep461 https://www.python.org/dev/peps/pep-0461/ -RedirectTemp /pep465 https://www.python.org/dev/peps/pep-0465/ -RedirectTemp /pep467 https://www.python.org/dev/peps/pep-0467/ -RedirectTemp /pep482 https://www.python.org/dev/peps/pep-0482/ -RedirectTemp /pep483 https://www.python.org/dev/peps/pep-0483/ -RedirectTemp /pep484 https://www.python.org/dev/peps/pep-0484/ -RedirectTemp /pep487 https://www.python.org/dev/peps/pep-0487/ -RedirectTemp /pep492 https://www.python.org/dev/peps/pep-0492/ -RedirectTemp /pep519 https://www.python.org/dev/peps/pep-0519/ -RedirectTemp /pep525 https://www.python.org/dev/peps/pep-0525/ -RedirectTemp /pep526 https://www.python.org/dev/peps/pep-0526/ -RedirectTemp /pep528 https://www.python.org/dev/peps/pep-0528/ -RedirectTemp /pep529 https://www.python.org/dev/peps/pep-0529/ -RedirectTemp /pep530 https://www.python.org/dev/peps/pep-0530/ -RedirectTemp /pep544 https://www.python.org/dev/peps/pep-0544/ -RedirectTemp /pep554 https://www.python.org/dev/peps/pep-0554/ -RedirectTemp /pep557 https://www.python.org/dev/peps/pep-0557/ -RedirectTemp /pep560 https://www.python.org/dev/peps/pep-0560/ -RedirectTemp /pep561 https://www.python.org/dev/peps/pep-0561/ -RedirectTemp /pep563 https://www.python.org/dev/peps/pep-0563/ -RedirectTemp /pep570 https://www.python.org/dev/peps/pep-0570/ -RedirectTemp /pep572 https://www.python.org/dev/peps/pep-0572/ -RedirectTemp /pep584 https://www.python.org/dev/peps/pep-0584/ -RedirectTemp /pep585 https://www.python.org/dev/peps/pep-0585/ -RedirectTemp /pep586 https://www.python.org/dev/peps/pep-0586/ -RedirectTemp /pep589 https://www.python.org/dev/peps/pep-0589/ -RedirectTemp /pep591 https://www.python.org/dev/peps/pep-0591/ -RedirectTemp /pep593 https://www.python.org/dev/peps/pep-0593/ -RedirectTemp /pep604 https://www.python.org/dev/peps/pep-0604/ -RedirectTemp /pep612 https://www.python.org/dev/peps/pep-0612/ -RedirectTemp /pep613 https://www.python.org/dev/peps/pep-0613/ -RedirectTemp /pep616 https://www.python.org/dev/peps/pep-0616/ -RedirectTemp /pep617 https://www.python.org/dev/peps/pep-0617/ -RedirectTemp /pep618 https://www.python.org/dev/peps/pep-0618/ -RedirectTemp /pep634 https://www.python.org/dev/peps/pep-0634/ -RedirectTemp /pep635 https://www.python.org/dev/peps/pep-0635/ -RedirectTemp /pep636 https://www.python.org/dev/peps/pep-0636/ -RedirectTemp /pep638 https://www.python.org/dev/peps/pep-0638/ -RedirectTemp /pep645 https://www.python.org/dev/peps/pep-0645/ -RedirectTemp /pep646 https://www.python.org/dev/peps/pep-0646/ -RedirectTemp /pep647 https://www.python.org/dev/peps/pep-0647/ -RedirectTemp /pep649 https://www.python.org/dev/peps/pep-0649/ -RedirectTemp /pep654 https://www.python.org/dev/peps/pep-0654/ -RedirectTemp /pep655 https://www.python.org/dev/peps/pep-0655/ -RedirectTemp /pep661 https://www.python.org/dev/peps/pep-0661/ -RedirectTemp /pep3099 https://www.python.org/dev/peps/pep-3099/ -RedirectTemp /pep3102 https://www.python.org/dev/peps/pep-3102/ -RedirectTemp /pep3104 https://www.python.org/dev/peps/pep-3104/ -RedirectTemp /pep3106 https://www.python.org/dev/peps/pep-3106/ -RedirectTemp /pep3107 https://www.python.org/dev/peps/pep-3107/ -RedirectTemp /pep3115 https://www.python.org/dev/peps/pep-3115/ -RedirectTemp /pep3118 https://www.python.org/dev/peps/pep-3118/ -RedirectTemp /pep3119 https://www.python.org/dev/peps/pep-3119/ -RedirectTemp /pep3129 https://www.python.org/dev/peps/pep-3129/ -RedirectTemp /pep3132 https://www.python.org/dev/peps/pep-3132/ -RedirectTemp /pep3141 https://www.python.org/dev/peps/pep-3141/ -RedirectTemp /pep3148 https://www.python.org/dev/peps/pep-3148/ -RedirectTemp /pep3155 https://www.python.org/dev/peps/pep-3155/ -RedirectTemp /pep3333 https://www.python.org/dev/peps/pep-3333/ - -# Remaining URLs by chapter - -############################################################ p -RedirectTemp /p-1 https://mail.python.org/pipermail/python-list/2002-December/134521.html -RedirectTemp /p-2 https://docs.python.org/3.10/tutorial/ -RedirectTemp /p-3 https://docs.python.org/3/tutorial/ -RedirectTemp /p-4 https://www.oreilly.com/library/view/fluent-python-2nd/9781492056348/ -RedirectTemp /p-5 https://www.oreilly.com/online-learning/try-now.html -RedirectTemp /p-6 https://www.oreilly.com/library/view/fluent-python-2nd/9781492056348/ -RedirectTemp /p-7 https://stackoverflow.com/users/95810/alex-martelli -RedirectTemp /p-8 https://pythonpro.com.br -RedirectTemp /p-9 https://groups.google.com/g/python-brasil -RedirectTemp /p-10 https://www.coffeelab.com.br/ -RedirectTemp /p-11 https://garoa.net.br/wiki/P%C3%A1gina_principal -############################################################ a -RedirectTemp /a-1 https://groups.google.com/forum/#!topic/python-tulip/Y4bhLNbKs74 -RedirectTemp /a-2 https://docs.python.org/3/library/asyncio-eventloop.html#executor -RedirectTemp /a-3 https://www.youtube.com/watch?v=x-kB2o8sd5c -RedirectTemp /a-4 https://www.youtube.com/watch?v=OSGv2VnC0go -RedirectTemp /a-5 https://mail.python.org/pipermail/python-ideas/2015-March/032557.html -RedirectTemp /a-6 https://pypi.org/project/pep8/ -RedirectTemp /a-7 https://pypi.org/project/flake8/ -RedirectTemp /a-8 https://pypi.org/project/pyflakes/ -RedirectTemp /a-9 https://pypi.org/project/mccabe/ -RedirectTemp /a-10 https://google.github.io/styleguide/pyguide.html -RedirectTemp /a-11 https://flask.palletsprojects.com/en/1.1.x/styleguide/ -RedirectTemp /a-12 https://docs.python-guide.org/ -RedirectTemp /a-13 https://david.goodger.org/projects/pycon/2007/idiomatic/handout.html -RedirectTemp /a-14 https://docs.mongodb.com/manual/about/#about-the-documentation-process -RedirectTemp /a-15 https://blog.startifact.com/posts/older/what-is-pythonic.html -RedirectTemp /a-16 https://mail.python.org/pipermail/tutor/2003-October/thread.html#25930 -RedirectTemp /a-17 https://mail.python.org/pipermail/python-list/2003-April/192027.html -RedirectTemp /a-18 https://www.python.org/doc/essays/ -############################################################ 01 -RedirectTemp /1-1 http://hugunin.net/story_of_jython.html -RedirectTemp /1-2 https://www.oreilly.com/library/view/jython-essentials/9781449397364/ -RedirectTemp /1-3 https://docs.python.org/3/reference/lexical_analysis.html#reserved-classes-of-identifiers -RedirectTemp /1-4 https://docs.python.org/3.10/library/string.html#format-string-syntax -RedirectTemp /1-5 https://stackoverflow.com/questions/1436703/what-is-the-difference-between-str-and-repr -RedirectTemp /1-6 https://docs.python.org/3/library/stdtypes.html#truth -RedirectTemp /1-7 https://docs.python.org/3/tutorial/controlflow.html#unpacking-argument-lists -RedirectTemp /1-8 https://www.python.org/doc/humor/#the-zen-of-python -RedirectTemp /1-9 https://stackoverflow.com/users/95810/alex-martelli -RedirectTemp /1-10 https://en.wikipedia.org/wiki/Object_model -RedirectTemp /1-11 https://www.dourish.com/goodies/jargon.html -RedirectTemp /1-12 https://zopeinterface.readthedocs.io/en/latest/ -RedirectTemp /1-13 https://plone.org/ -############################################################ 02 -RedirectTemp /2-1 https://github.com/fluentpython/example-code-2e/blob/master/02-array-seq/listcomp_speed.py -RedirectTemp /2-2 https://www.python.org/dev/peps/pep-3132/ -RedirectTemp /2-3 https://stackoverflow.com/questions/68630/are-tuples-more-efficient-than-lists-in-python/22140115#22140115 -RedirectTemp /2-4 https://docs.python.org/3/whatsnew/3.5.html#pep-448-additional-unpacking-generalizations -RedirectTemp /2-5 https://docs.python.org/3/whatsnew/3.5.html#pep-448-additional-unpacking-generalizations -RedirectTemp /2-6 https://docs.python.org/3.10/whatsnew/3.10.html#pep-634-structural-pattern-matching -RedirectTemp /2-7 https://docs.python.org/3.10/whatsnew/3.10.html -RedirectTemp /2-8 https://en.wikipedia.org/wiki/Switch_statement#Fallthrough -RedirectTemp /2-9 https://en.wikipedia.org/wiki/Dangling_else -RedirectTemp /2-10 https://github.com/gvanrossum/patma/blob/3ece6444ef70122876fd9f0099eb9490a2d630df/EXAMPLES.md#case-6-a-very-deep-iterable-and-type-match-with-extraction -RedirectTemp /2-11 https://github.com/fluentpython/lispy/blob/main/original/norvig/lis.py -RedirectTemp /2-12 https://norvig.com/lispy.html -RedirectTemp /2-13 https://numpy.org/doc/stable/user/quickstart.html#indexing-slicing-and-iterating -RedirectTemp /2-14 https://pythontutor.com/ -RedirectTemp /2-15 https://en.wikipedia.org/wiki/Fluent_interface -RedirectTemp /2-16 https://docs.python.org/3/library/bisect.html#bisect.insort -RedirectTemp /2-17 https://stackoverflow.com/questions/4845418/when-should-a-memoryview-be-used/ -RedirectTemp /2-18 https://www.fluentpython.com/extra/parsing-binary-struct/ -RedirectTemp /2-19 http://www.netlib.org -RedirectTemp /2-20 https://pandas.pydata.org/ -RedirectTemp /2-21 https://scikit-learn.org/stable/ -RedirectTemp /2-22 https://docs.python.org/3/howto/sorting.html -RedirectTemp /2-23 https://www.python.org/dev/peps/pep-3132/ -RedirectTemp /2-24 https://bugs.python.org/issue2292 -RedirectTemp /2-25 https://docs.python.org/3.10/whatsnew/3.10.html#pep-634-structural-pattern-matching -RedirectTemp /2-26 https://docs.python.org/3.10/whatsnew/3.10.html -RedirectTemp /2-27 https://www.python.org/dev/peps/pep-0636/#appendix-a-quick-intro -RedirectTemp /2-28 https://eli.thegreenplace.net/2011/11/28/less-copies-in-python-with-the-buffer-protocol-and-memoryviews/ -RedirectTemp /2-29 https://jakevdp.github.io/PythonDataScienceHandbook/ -RedirectTemp /2-30 https://www.oreilly.com/library/view/python-for-data/9781491957653/ -RedirectTemp /2-31 https://www.labri.fr/perso/nrougier/from-python-to-numpy/ -RedirectTemp /2-32 https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html -RedirectTemp /2-33 http://www.fonts101.com/fonts/view/Uncategorized/34398/Dijkstra -RedirectTemp /2-34 https://docs.python.org/3/reference/datamodel.html#objects-values-and-types -RedirectTemp /2-35 https://en.wikipedia.org/wiki/Timsort -RedirectTemp /2-36 http://www.groklaw.net/pdf3/OraGoogle-1202.pdf -RedirectTemp /2-37 https://www.python.org/doc/humor/#id9 -############################################################ 03 -RedirectTemp /3-1 https://www.python.org/dev/peps/pep-0584/#motivation -RedirectTemp /3-2 https://docs.python.org/3.10/c-api/typeobj.html#Py_TPFLAGS_MAPPING -RedirectTemp /3-3 https://docs.python.org/3/glossary.html#term-hashable -RedirectTemp /3-4 https://docs.python.org/3/glossary.html#term-hashable -RedirectTemp /3-5 http://www.aleax.it/Python/accu04_Relearn_Python_alex.pdf -RedirectTemp /3-6 https://github.com/pingo-io/pingo-py -RedirectTemp /3-7 https://github.com/fluentpython/example-code-2e/blob/master/03-dict-set/missing.py -RedirectTemp /3-8 https://docs.python.org/3/library/collections.html#collections.ChainMap -RedirectTemp /3-9 https://docs.python.org/3/library/collections.html#collections.Counter -RedirectTemp /3-10 https://docs.python.org/3/library/shelve.html -RedirectTemp /3-11 https://docs.python.org/3/library/dbm.html -RedirectTemp /3-12 https://docs.python.org/3/library/pickle.html -RedirectTemp /3-13 https://nedbatchelder.com/blog/202006/pickles_nine_flaws.html -RedirectTemp /3-14 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Lib/_collections_abc.py#L813 -RedirectTemp /3-15 https://mail.python.org/pipermail/python-dev/2015-May/140003.html -RedirectTemp /3-16 https://bugs.python.org/issue18986 -RedirectTemp /3-17 https://github.com/fluentpython/example-code-2e/blob/master/03-dict-set/transformdict.py -RedirectTemp /3-18 http://gandenberger.org/2018/03/10/ordered-dicts-vs-ordereddict/ -RedirectTemp /3-19 https://www.pypy.org/ -RedirectTemp /3-20 https://morepypy.blogspot.com/2015/01/faster-more-memory-efficient-and-more.html -RedirectTemp /3-21 https://www.npopov.com/2014/12/22/PHPs-new-hashtable-implementation.html -RedirectTemp /3-22 https://www.youtube.com/watch?v=66P5FMkWoVU -RedirectTemp /3-23 https://pyvideo.org/video/276/the-mighty-dictionary-55/ -RedirectTemp /3-24 https://www.youtube.com/watch?v=p33CVV29OG8 -RedirectTemp /3-25 https://docs.python.org/3/whatsnew/3.6.html#new-dict-implementation -RedirectTemp /3-26 https://github.com/python/cpython/blob/cf7eaa4617295747ee5646c4e2b7e7a16d7c64ab/Objects/dictobject.c -RedirectTemp /3-27 https://github.com/python/cpython/blob/cf7eaa4617295747ee5646c4e2b7e7a16d7c64ab/Objects/dictnotes.txt -RedirectTemp /3-28 https://www.youtube.com/watch?v=tGAngdU_8D8 -RedirectTemp /3-29 https://speakerdeck.com/ramalho/python-set-practice-at-pycon -RedirectTemp /3-30 https://github.com/standupdev/uintset -RedirectTemp /3-31 https://spectrum.ieee.org/hans-peter-luhn-and-the-birth-of-the-hashing-algorithm -RedirectTemp /3-32 http://www.json.org/fatfree.html -RedirectTemp /3-33 https://twitter.com/mitsuhiko/status/1229385843585974272 -############################################################ 04 -RedirectTemp /4-1 https://www.slideshare.net/fischertrav/character-encoding-unicode-how-to-with-dignity-33352863 -RedirectTemp /4-2 https://pyvideo.org/video/2625/character-encoding-and-unicode-in-python/ -RedirectTemp /4-3 https://www.fluentpython.com/extra/parsing-binary-struct/ -RedirectTemp /4-4 https://www.fluentpython.com/extra/multi-character-emojis/ -RedirectTemp /4-5 https://w3techs.com/technologies/overview/character_encoding -RedirectTemp /4-6 https://docs.python.org/3/library/codecs.html#codecs.register_error -RedirectTemp /4-7 https://docs.python.org/3/library/stdtypes.html#str.isascii -RedirectTemp /4-8 https://pypi.org/project/chardet/ -RedirectTemp /4-9 https://docs.python.org/3/library/codecs.html#encodings-and-unicode -RedirectTemp /4-10 https://nedbatchelder.com/text/unipain/unipain.html -RedirectTemp /4-11 https://devblogs.microsoft.com/commandline/windows-command-line-unicode-and-utf-8-output-text-buffer/ -RedirectTemp /4-12 https://docs.python.org/3/using/cmdline.html#envvar-PYTHONIOENCODING -RedirectTemp /4-13 https://docs.python.org/3/using/cmdline.html#envvar-PYTHONLEGACYWINDOWSSTDIO -RedirectTemp /4-14 https://docs.python.org/3/library/locale.html#locale.getpreferredencoding -RedirectTemp /4-15 http://www.w3.org/TR/charmod-norm/ -RedirectTemp /4-16 https://docs.python.org/3/library/locale.html?highlight=strxfrm#locale.strxfrm -RedirectTemp /4-17 https://pypi.org/project/pyuca/ -RedirectTemp /4-18 https://github.com/jtauber/pyuca -RedirectTemp /4-19 http://www.unicode.org/Public/UCA/6.3.0/allkeys.txt -RedirectTemp /4-20 https://pypi.org/project/PyICU/ -RedirectTemp /4-21 https://docs.python.org/3.10/library/stdtypes.html#str.isalpha -RedirectTemp /4-22 https://en.wikipedia.org/wiki/Unicode_character_property#General_Category -RedirectTemp /4-23 https://en.wikipedia.org/wiki/Unicode_character_property -RedirectTemp /4-24 https://github.com/microsoft/terminal -RedirectTemp /4-25 https://docs.python.org/3/library/unicodedata.html -RedirectTemp /4-26 https://docs.python.org/3/reference/lexical_analysis.html#string-literal-concatenation -RedirectTemp /4-27 https://docs.python.org/3/library/re.html -RedirectTemp /4-28 https://nedbatchelder.com/text/unipain.html -RedirectTemp /4-29 https://www.slideshare.net/fischertrav/character-encoding-unicode-how-to-with-dignity-33352863 -RedirectTemp /4-30 https://pyvideo.org/video/2625/character-encoding-and-unicode-in-python/ -RedirectTemp /4-31 https://regebro.wordpress.com/2011/03/23/unconfusing-unicode-what-is-unicode/ -RedirectTemp /4-32 https://docs.python.org/3/howto/unicode.html -RedirectTemp /4-33 https://diveintopython3.net/strings.html -RedirectTemp /4-34 https://diveintopython3.net/ -RedirectTemp /4-35 https://finderiko.com/python-book -RedirectTemp /4-36 https://docs.python.org/3.0/whatsnew/3.0.html#text-vs-data-instead-of-unicode-vs-8-bit -RedirectTemp /4-37 https://lucumr.pocoo.org/2013/7/2/the-updated-guide-to-unicode/ -RedirectTemp /4-38 http://python-notes.curiousefficiency.org/en/latest/python3/binary_protocols.html -RedirectTemp /4-39 http://python-notes.curiousefficiency.org/en/latest/python3/text_file_processing.html -RedirectTemp /4-40 https://docs.python.org/3/library/codecs.html#standard-encodings -RedirectTemp /4-41 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Tools/unicode/listcodecs.py -RedirectTemp /4-42 https://www.oreilly.com/library/view/unicode-explained/059610121X/ -RedirectTemp /4-43 https://www.informit.com/store/unicode-demystified-a-practical-programmers-guide-to-9780201700527 -RedirectTemp /4-44 https://unicodebook.readthedocs.io/index.html -RedirectTemp /4-45 https://www.w3.org/International/wiki/Case_folding -RedirectTemp /4-46 http://www.w3.org/TR/charmod-norm/ -RedirectTemp /4-47 http://unicode.org/reports/tr15/ -RedirectTemp /4-48 http://www.unicode.org/faq/normalization.html -RedirectTemp /4-49 http://www.unicode.org/ -RedirectTemp /4-50 http://www.macchiato.com/unicode/nfc-faq -RedirectTemp /4-51 https://stories.moma.org/the-original-emoji-set-has-been-added-to-the-museum-of-modern-arts-collection-c6060e141f61?gi=c403f5a840a5 -RedirectTemp /4-52 https://emojipedia.org/ -RedirectTemp /4-53 https://blog.emojipedia.org/correcting-the-record-on-the-first-emoji-set/ -RedirectTemp /4-54 http://emojitracker.com/ -RedirectTemp /4-55 http://www.unicode.org/glossary/#plain_text -RedirectTemp /4-56 http://www.methods.co.nz/asciidoc/ -RedirectTemp /4-57 https://atlas.oreilly.com/ -############################################################ 05 -RedirectTemp /5-1 https://docs.python.org/3/library/typing.html#typing.TypedDict -RedirectTemp /5-2 https://docs.python.org/3.10/library/inspect.html#inspect.get_annotations -RedirectTemp /5-3 https://docs.python.org/3/library/typing.html#typing.get_type_hints -RedirectTemp /5-4 https://docs.python.org/3.8/library/collections.html#collections.somenamedtuple._asdict -RedirectTemp /5-5 https://www.jetbrains.com/pycharm/ -RedirectTemp /5-6 https://www.python.org/dev/peps/pep-0484/#acceptable-type-hints -RedirectTemp /5-7 https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass -RedirectTemp /5-8 https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass -RedirectTemp /5-9 https://docs.python.org/3/library/dataclasses.html -RedirectTemp /5-10 https://docs.python.org/3/library/dataclasses.html#inheritance -RedirectTemp /5-11 https://www.python.org/dev/peps/pep-0526/#class-and-instance-variable-annotations -RedirectTemp /5-12 https://dublincore.org/specifications/dublin-core/ -RedirectTemp /5-13 https://en.wikipedia.org/wiki/Dublin_Core -RedirectTemp /5-14 https://martinfowler.com/bliki/CodeSmell.html -RedirectTemp /5-15 https://martinfowler.com/books/refactoring.html -RedirectTemp /5-16 https://www.python.org/dev/peps/pep-0634/#class-patterns -RedirectTemp /5-17 https://docs.python.org/3/library/dataclasses.html -RedirectTemp /5-18 https://www.python.org/dev/peps/pep-0557/#id47 -RedirectTemp /5-19 https://www.python.org/dev/peps/pep-0557/#id48 -RedirectTemp /5-20 https://www.python.org/dev/peps/pep-0557/#id33 -RedirectTemp /5-21 https://realpython.com -RedirectTemp /5-22 https://realpython.com/python-data-classes/ -RedirectTemp /5-23 https://www.youtube.com/watch?v=T-TwcmT6Rcw -RedirectTemp /5-24 https://www.attrs.org/en/stable/ -RedirectTemp /5-25 https://glyph.twistedmatrix.com/2016/08/attrs.html -RedirectTemp /5-26 https://www.attrs.org/en/stable/why.html -RedirectTemp /5-27 https://github.com/dabeaz/cluegen -RedirectTemp /5-28 https://refactoring.guru/ -RedirectTemp /5-29 https://refactoring.guru/smells/data-class -RedirectTemp /5-30 https://web.archive.org/web/20190204130328/http://catb.org/esr/jargon/html/G/Guido.html -RedirectTemp /5-31 https://web.archive.org/web/20190211161610/http://catb.org/esr/jargon/html/index.html -RedirectTemp /5-32 https://www.attrs.org/en/stable/ -############################################################ 06 -RedirectTemp /6-1 https://www.olin.edu/faculty/profile/lynn-andrea-stein/ -RedirectTemp /6-2 https://docs.python.org/3/reference/datamodel.html#objects-values-and-types -RedirectTemp /6-3 https://pythontutor.com/ -RedirectTemp /6-4 https://docs.python.org/3/library/copy.html -RedirectTemp /6-5 https://en.wikipedia.org/wiki/Principle_of_least_astonishment -RedirectTemp /6-6 https://docs.python.org/3/reference/datamodel.html#object.%5C_%5C_del__ -RedirectTemp /6-7 https://emptysqua.re/blog/pypy-garbage-collection-and-a-deadlock/ -RedirectTemp /6-8 https://www.youtube.com/watch?v=HHFCFJSPWrI&feature=youtu.be -RedirectTemp /6-9 http://pymotw.com/3/copy/ -RedirectTemp /6-10 http://pymotw.com/3/weakref/ -RedirectTemp /6-11 https://docs.python.org/3/library/gc.html -RedirectTemp /6-12 https://devguide.python.org/garbage_collector/ -RedirectTemp /6-13 https://devguide.python.org/ -RedirectTemp /6-14 https://www.python.org/dev/peps/pep-0442/ -RedirectTemp /6-15 https://en.wikipedia.org/wiki/String_interning -RedirectTemp /6-16 https://en.wikipedia.org/wiki/Haddocks%27_Eyes -RedirectTemp /6-17 https://thp.io/2012/python-gc/python_gc_final_2012-01-22.pdf -############################################################ 07 -RedirectTemp /7-1 http://python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html -RedirectTemp /7-2 https://www.fluentpython.com/extra/function-introspection/ -RedirectTemp /7-3 https://docs.python.org/3/library/functions.html#map -RedirectTemp /7-4 https://en.wikipedia.org/wiki/Functional_programming -RedirectTemp /7-5 https://docs.python.org/3/howto/functional.html -RedirectTemp /7-6 https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy -RedirectTemp /7-7 https://docs.python.org/3/whatsnew/3.8.html#positional-only-parameters -RedirectTemp /7-8 https://docs.python.org/3/whatsnew/3.8.html#positional-only-parameters -RedirectTemp /7-9 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Lib/functools.py#L341 -RedirectTemp /7-10 https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy -RedirectTemp /7-11 https://docs.python.org/3/howto/functional.html -RedirectTemp /7-12 https://stackoverflow.com/questions/3252228/python-why-is-functools-partial-necessary -RedirectTemp /7-13 https://speakerdeck.com/ramalho/beyond-paradigms-berlin-edition -RedirectTemp /7-14 https://www.youtube.com/watch?v=bF3a2VYXxa0 -RedirectTemp /7-15 http://cs.brown.edu/~sk/Publications/Papers/Published/sk-teach-pl-post-linnaean/ -RedirectTemp /7-16 http://python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html -RedirectTemp /7-17 https://raw.githubusercontent.com/python/cpython/main/Misc/HISTORY -RedirectTemp /7-18 http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html -############################################################ 08 -RedirectTemp /8-1 https://www.python.org/dev/peps/pep-0484/#non-goals -RedirectTemp /8-2 https://github.com/python/typing/issues/182 -RedirectTemp /8-3 https://github.com/python/mypy/issues/731 -RedirectTemp /8-4 https://github.com/google/pytype -RedirectTemp /8-5 https://github.com/Microsoft/pyright -RedirectTemp /8-6 https://pyre-check.org/ -RedirectTemp /8-7 https://mypy.readthedocs.io/en/stable/introduction.html -RedirectTemp /8-8 https://mypy.readthedocs.io/en/stable/config_file.html -RedirectTemp /8-9 https://pypi.org/project/flake8/ -RedirectTemp /8-10 https://pypi.org/project/blue/ -RedirectTemp /8-11 https://pypi.org/project/black/ -RedirectTemp /8-12 https://wefearchange.org/2020/11/steeringcouncil.rst.html -RedirectTemp /8-13 https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes -RedirectTemp /8-14 https://en.wikipedia.org/wiki/Barbara_Liskov -RedirectTemp /8-15 https://en.wikipedia.org/wiki/Behavioral_subtyping -RedirectTemp /8-16 https://www.python.org/dev/peps/pep-0585/#implementation -RedirectTemp /8-17 https://docs.python.org/3/library/typing.html#module-contents -RedirectTemp /8-18 https://en.wikipedia.org/wiki/Geohash -RedirectTemp /8-19 https://en.wikipedia.org/wiki/Inverted_index -RedirectTemp /8-20 https://docs.python.org/3/library/typing.html#typing.List -RedirectTemp /8-21 https://docs.python.org/3/library/typing.html#typing.Dict -RedirectTemp /8-22 https://docs.python.org/3/library/typing.html#typing.Set -RedirectTemp /8-23 https://www.python.org/dev/peps/pep-0585/#implementation -RedirectTemp /8-24 https://docs.python.org/3/library/numbers.html -RedirectTemp /8-25 https://docs.python.org/3/library/typing.html#typing.List -RedirectTemp /8-26 https://github.com/python/typeshed -RedirectTemp /8-27 https://github.com/python/typeshed/blob/66cd36268a6a667714efaa27198a41d0d7f89477/stdlib/2and3/math.pyi#L45 -RedirectTemp /8-28 https://docs.python.org/3/library/statistics.html#statistics.mode -RedirectTemp /8-29 https://github.com/python/cpython/blob/822efa5695b5ba6c2316c1400e4e9ec2546f7ea5/Lib/statistics.py#L534 -RedirectTemp /8-30 https://github.com/python/typeshed/blob/e1e99245bb46223928eba68d4fc74962240ba5b4/stdlib/3/statistics.pyi -RedirectTemp /8-31 https://docs.python.org/3/library/statistics.html#statistics.mode -RedirectTemp /8-32 https://github.com/python/typeshed/blob/a8834fcd46339e17fc8add82b5803a1ce53d3d60/stdlib/3/statistics.pyi#L32 -RedirectTemp /8-33 https://mail.python.org/archives/list/python-dev@python.org/thread/CLVXXPQ2T2LQ5MP2Y53VVQFCXYWQJHKZ/ -RedirectTemp /8-34 https://docs.python.org/3/library/typing.html#typing.Callable -RedirectTemp /8-35 https://pypi.org/project/blue/ -RedirectTemp /8-36 https://www.python.org/dev/peps/pep-0484/#id38 -RedirectTemp /8-37 https://docs.google.com/document/d/1aXs1tpwzPjW9MdsG5dI7clNFyYayFBkcXwRDo-qvbIk/preview -RedirectTemp /8-38 https://www.oreilly.com/library/view/the-best-software/9781590595008/ -RedirectTemp /8-39 https://www.youtube.com/watch?v=YFexUDjHO6w -RedirectTemp /8-40 https://www.youtube.com/watch?v=YFexUDjHO6w&t=13m40s -RedirectTemp /8-41 https://bernat.tech/posts/the-state-of-type-hints-in-python/ -RedirectTemp /8-42 https://realpython.com/python-type-checking/ -RedirectTemp /8-43 https://cjolowicz.github.io/posts/hypermodern-python-04-typing/ -RedirectTemp /8-44 https://mypy.readthedocs.io/en/stable/index.html -RedirectTemp /8-45 https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html -RedirectTemp /8-46 https://mypy.readthedocs.io/en/stable/common_issues.html -RedirectTemp /8-47 https://github.com/typeddjango/awesome-python-typing -RedirectTemp /8-48 https://docs.python.org/3/library/functions.html#max -RedirectTemp /8-49 https://en.wikipedia.org/wiki/Linguistic_relativity -RedirectTemp /8-50 https://pypistats.org/top -RedirectTemp /8-51 https://github.com/psf/requests/issues/3855 -RedirectTemp /8-52 https://lwn.net/Articles/643399/ -RedirectTemp /8-53 https://docs.python-requests.org/en/master/api/#requests.request -RedirectTemp /8-54 https://queue.acm.org/detail.cfm?id=1039523 -############################################################ 09 -RedirectTemp /9-1 https://docs.python.org/3/library/dis.html -RedirectTemp /9-2 https://en.wikipedia.org/wiki/Memoization -RedirectTemp /9-3 https://numpy.org/doc/stable/user/basics.types.html -RedirectTemp /9-4 https://docs.python.org/3/library/functools.html#functools.singledispatch -RedirectTemp /9-5 https://github.com/GrahamDumpleton/wrapt/blob/develop/blog/README.md -RedirectTemp /9-6 https://github.com/GrahamDumpleton/wrapt/blob/develop/blog/01-how-you-implemented-your-python-decorator-is-wrong.md -RedirectTemp /9-7 https://wrapt.readthedocs.io/en/latest/ -RedirectTemp /9-8 https://www.oreilly.com/library/view/python-cookbook-3rd/9781449357337/ch09.html -RedirectTemp /9-9 https://pypi.org/project/decorator/ -RedirectTemp /9-10 https://wiki.python.org/moin/PythonDecoratorLibrary -RedirectTemp /9-11 http://web.archive.org/web/20201109032203/http://effbot.org/zone/closure.htm -RedirectTemp /9-12 https://www.python.org/dev/peps/pep-3104/ -RedirectTemp /9-13 https://www.python.org/dev/peps/pep-0227/ -RedirectTemp /9-14 https://www.python.org/dev/peps/pep-0443/ -RedirectTemp /9-15 https://www.artima.com/weblogs/viewpost.jsp?thread=101605 -RedirectTemp /9-16 https://reg.readthedocs.io/en/latest/ -RedirectTemp /9-17 https://morepath.readthedocs.io/en/latest/ -RedirectTemp /9-18 https://www.gnu.org/software/emacs/manual/html_node/elisp/Dynamic-Binding.html -RedirectTemp /9-19 http://www.paulgraham.com/rootsoflisp.html -RedirectTemp /9-20 http://www-formal.stanford.edu/jmc/recursive/recursive.html -RedirectTemp /9-21 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this -############################################################ 10 -RedirectTemp /10-1 https://en.wikipedia.org/wiki/Software_design_pattern -RedirectTemp /10-2 https://en.wikipedia.org/wiki/Iterator_pattern -RedirectTemp /10-3 https://github.com/python/mypy/issues/9397 -RedirectTemp /10-4 http://www.norvig.com/design-patterns/index.htm -RedirectTemp /10-5 https://pyvideo.org/video/1110/python-design-patterns/ -RedirectTemp /10-6 http://www.aleax.it/gdd_pydp.pdf -RedirectTemp /10-7 https://perl.plover.com/yak/design/ -RedirectTemp /10-8 https://en.wikipedia.org/wiki/Turtles_all_the_way_down -############################################################ 11 -RedirectTemp /11-1 https://blog.startifact.com/posts/older/what-is-pythonic.html -RedirectTemp /11-2 https://julien.danjou.info/guide-python-static-class-abstract-methods/ -RedirectTemp /11-3 https://docs.python.org/3/library/string.html#formatspec -RedirectTemp /11-4 https://docs.python.org/3/reference/lexical_analysis.html#f-strings -RedirectTemp /11-5 https://docs.python.org/3/library/string.html#format-string-syntax -RedirectTemp /11-6 https://docs.python.org/3/library/string.html#formatspec -RedirectTemp /11-7 https://docs.python.org/3/reference/datamodel.html#object.__hash__ -RedirectTemp /11-8 https://web.archive.org/web/20161025185040/http://pythonpaste.org/StyleGuide.html -RedirectTemp /11-9 https://docs.python.org/3/tutorial/modules.html#more-on-modules -RedirectTemp /11-10 https://docs.python.org/3/library/gettext.html#gettext.NullTranslations -RedirectTemp /11-11 https://github.com/fluentpython/example-code-2e/blob/master/11-pythonic-obj/mem_test.py -RedirectTemp /11-12 https://docs.python.org/3/reference/datamodel.html#basic-customization -RedirectTemp /11-13 http://esug.org/data/HistoricalDocuments/TheSmalltalkReport/ST07/04wo.pdf -RedirectTemp /11-14 https://www.artima.com/articles/the-simplest-thing-that-could-possibly-work#part3 -RedirectTemp /11-15 https://docs.oracle.com/javase/tutorial/essential/environment/security.html -RedirectTemp /11-16 https://github.com/fluentpython/example-code-2e/blob/master/11-pythonic-obj/private/Expose.java -RedirectTemp /11-17 https://docs.oracle.com/javase/tutorial/essential/environment/security.html -############################################################ 12 -RedirectTemp /12-1 https://en.wikipedia.org/wiki/Vector_space_model -RedirectTemp /12-2 https://pypi.org/project/gensim/ -RedirectTemp /12-3 https://docs.python.org/3/library/functions.html#enumerate -RedirectTemp /12-4 https://mathworld.wolfram.com/Hypersphere.html -RedirectTemp /12-5 https://en.wikipedia.org/wiki/Fold_(higher-order_function) -RedirectTemp /12-6 https://docs.python.org/2.5/whatsnew/pep-357.html -RedirectTemp /12-7 https://docs.python.org/3/reference/datamodel.html#special-method-names -RedirectTemp /12-8 https://en.wikipedia.org/wiki/KISS_principle -RedirectTemp /12-9 https://mail.python.org/pipermail/python-list/2000-July/046184.html -RedirectTemp /12-10 https://en.wikipedia.org/wiki/Duck_typing -RedirectTemp /12-11 https://mail.python.org/mailman/listinfo/python-list -RedirectTemp /12-12 https://mail.python.org/pipermail/python-list/2003-April/218568.html -############################################################ 13 -RedirectTemp /13-1 https://docs.python.org/3/c-api/index.html -RedirectTemp /13-2 https://docs.python.org/3/c-api/sequence.html -RedirectTemp /13-3 https://github.com/python/cpython/blob/31ceccb2c77854893f3a754aca04bedd74bedb10/Lib/_collections_abc.py#L870 -RedirectTemp /13-4 https://en.wikipedia.org/wiki/Monkey_patch -RedirectTemp /13-5 https://www.gevent.org/api/gevent.monkey.html -RedirectTemp /13-6 https://docs.python.org/3/library/random.html#random.shuffle -RedirectTemp /13-7 https://docs.python.org/3/reference/datamodel.html#emulating-container-types -RedirectTemp /13-8 https://docs.python.org/3/library/collections.html#collections.namedtuple -RedirectTemp /13-9 https://github.com/python/typeshed/blob/24afb531ffd07083d6a74be917342195062f7277/stdlib/collections/__init__.pyi -RedirectTemp /13-10 https://docs.python.org/3/glossary.html#term-abstract-base-class -RedirectTemp /13-11 https://en.wikipedia.org/wiki/Duck_typing#History -RedirectTemp /13-12 http://ptgmedia.pearsoncmg.com/images/020163371x/items/item33.html -RedirectTemp /13-13 https://docs.python.org/3/library/bisect.html#bisect.bisect -RedirectTemp /13-14 https://github.com/python/cpython/blob/main/Lib/_collections_abc.py -RedirectTemp /13-15 https://github.com/python/cpython/blob/main/Lib/abc.py -RedirectTemp /13-16 https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes -RedirectTemp /13-17 https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable -RedirectTemp /13-18 https://docs.python.org/3/library/abc.html -RedirectTemp /13-19 https://docs.python.org/dev/library/abc.html#abc.abstractmethod -RedirectTemp /13-20 https://docs.python.org/dev/library/abc.html -RedirectTemp /13-21 https://docs.python.org/3/library/os.html#os.urandom -RedirectTemp /13-22 https://github.com/python/mypy/issues/2922 -RedirectTemp /13-23 https://docs.python.org/3/library/stdtypes.html#truth -RedirectTemp /13-24 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Lib/_collections_abc.py -RedirectTemp /13-25 https://github.com/python/cpython/blob/0fbddb14dc03f61738af01af88e7d8aa8df07336/Lib/_collections_abc.py#L369 -RedirectTemp /13-26 https://github.com/python/cpython/blob/c0a9afe2ac1820409e6173bd1893ebee2cf50270/Lib/abc.py#L196 -RedirectTemp /13-27 https://bugs.python.org/issue31333 -RedirectTemp /13-28 https://github.com/python/cpython/blob/3635388f52b42e5280229104747962117104c453/Modules/_abc.c#L605 -RedirectTemp /13-29 https://github.com/python/cpython/blob/0fbddb14dc03f61738af01af88e7d8aa8df07336/Lib/_collections_abc.py#L881 -RedirectTemp /13-30 https://docs.python.org/3/library/typing.html#protocols -RedirectTemp /13-31 https://github.com/python/cpython/blob/3635388f52b42e5280229104747962117104c453/Lib/typing.py#L1751 -RedirectTemp /13-32 https://mail.python.org/archives/list/python-dev@python.org/thread/CLVXXPQ2T2LQ5MP2Y53VVQFCXYWQJHKZ/ -RedirectTemp /13-33 https://martinfowler.com/bliki/RoleInterface.html -RedirectTemp /13-34 https://en.wikipedia.org/wiki/Interface_segregation_principle -RedirectTemp /13-35 https://github.com/python/typeshed/blob/master/CONTRIBUTING.md -RedirectTemp /13-36 https://gist.github.com/asukakenji/ac8a05644a2e98f1d5ea8c299541fce9 -RedirectTemp /13-37 https://www.python.org/dev/peps/pep-0544/#runtime-checkable-decorator-and-narrowing-types-by-isinstance -RedirectTemp /13-38 https://www.python.org/dev/peps/pep-0544/#merging-and-extending-protocols -RedirectTemp /13-39 https://numpy.org/devdocs/user/basics.types.html -RedirectTemp /13-40 https://github.com/python/typeshed/blob/master/stdlib/statistics.pyi -RedirectTemp /13-41 https://bugs.python.org/issue41974 -RedirectTemp /13-42 https://glyph.twistedmatrix.com/2020/07/new-duck.html -RedirectTemp /13-43 https://glyph.twistedmatrix.com/2021/03/interfaces-and-protocols.html -RedirectTemp /13-44 https://plone.org/ -RedirectTemp /13-45 https://trypyramid.com/ -RedirectTemp /13-46 https://twistedmatrix.com/trac/ -RedirectTemp /13-47 https://www.artima.com/articles/contracts-in-python -RedirectTemp /13-48 https://martinfowler.com/bliki/DynamicTyping.html -RedirectTemp /13-49 https://martinfowler.com/bliki/RoleInterface.html -RedirectTemp /13-50 https://mypy.readthedocs.io/en/stable/protocols.html -RedirectTemp /13-51 https://pymotw.com/3/abc/index.html -RedirectTemp /13-52 https://www.python.org/dev/peps/pep-3119/ -RedirectTemp /13-53 https://www.python.org/dev/peps/pep-3141/ -RedirectTemp /13-54 https://docs.python.org/3/library/numbers.html -RedirectTemp /13-55 https://github.com/python/mypy/issues/3186 -RedirectTemp /13-56 https://stackoverflow.com/questions/69334475/how-to-hint-at-number-types-i-e-subclasses-of-number-not-numbers-themselv/69383462#69383462 -RedirectTemp /13-57 https://github.com/python/mypy/issues/3186 -RedirectTemp /13-58 https://martinfowler.com/articles/lean-inception/ -RedirectTemp /13-59 https://martinfowler.com -RedirectTemp /13-60 https://www.jetbrains.com/pycharm/ -RedirectTemp /13-61 https://wingware.com/ -RedirectTemp /13-62 https://code.visualstudio.com/ -############################################################ 14 -RedirectTemp /14-1 http://worrydream.com/EarlyHistoryOfSmalltalk/ -RedirectTemp /14-2 https://docs.python.org/3/tutorial/classes.html -RedirectTemp /14-3 https://docs.python.org/3/library/collections.html#ordereddict-examples-and-recipes -RedirectTemp /14-4 https://discuss.python.org/t/is-it-time-to-deprecate-unbound-super-methods/1833 -RedirectTemp /14-5 https://doc.pypy.org/en/latest/cpython_differences.html#subclasses-of-built-in-types -RedirectTemp /14-6 https://docs.python.org/3/library/collections.html -RedirectTemp /14-7 https://github.com/fluentpython/example-code-2e/blob/master/14-inheritance/strkeydict_dictsub.py -RedirectTemp /14-8 https://doc.pypy.org/en/latest/cpython_differences.html#subclasses-of-built-in-types -RedirectTemp /14-9 https://en.wikipedia.org/wiki/Breadth-first_search -RedirectTemp /14-10 https://www.python.org/download/releases/2.3/mro/ -RedirectTemp /14-11 https://github.com/fluentpython/example-code-2e/blob/master/14-inheritance/uppermixin.py -RedirectTemp /14-12 https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html -RedirectTemp /14-13 https://docs.python.org/3/library/collections.abc.html -RedirectTemp /14-14 https://github.com/python/cpython/blob/8ece98a7e418c3c68a4c61bc47a2d0931b59a889/Lib/collections/__init__.py#L1084 -RedirectTemp /14-15 https://docs.python.org/3/library/http.server.html -RedirectTemp /14-16 https://github.com/python/cpython/blob/17c23167942498296f0bdfffe52e72d53d66d693/Lib/http/server.py#L144 -RedirectTemp /14-17 https://github.com/python/cpython/blob/699ee016af5736ffc80f68359617611a22b72943/Lib/socketserver.py#L664 -RedirectTemp /14-18 https://docs.python.org/3/library/socketserver.html#socketserver.ForkingMixIn -RedirectTemp /14-19 https://docs.python.org/3/library/os.html#os.fork -RedirectTemp /14-20 https://en.wikipedia.org/wiki/POSIX -RedirectTemp /14-21 http://ccbv.co.uk/ -RedirectTemp /14-22 https://github.com/django/django/tree/main/django/views/generic -RedirectTemp /14-23 https://en.wikipedia.org/wiki/Template_method_pattern -RedirectTemp /14-24 https://docs.python.org/3/library/tkinter.html -RedirectTemp /14-25 https://docs.python.org/3/library/tkinter.ttk.html -RedirectTemp /14-26 https://docs.oracle.com/javase/10/docs/api/java/awt/package-tree.html -RedirectTemp /14-27 https://docs.oracle.com/javase/10/docs/api/javax/swing/package-tree.html -RedirectTemp /14-28 https://squeak.org/ -RedirectTemp /14-29 https://github.com/django/django/blob/b64db05b9cedd96905d637a2d824cbbf428e40e7/django/views/generic/list.py#L194 -RedirectTemp /14-30 https://github.com/python/cpython/blob/8ed183391241f0c73e7ba7f42b1d49fc02985f7b/Lib/tkinter/__init__.py#L2618 -RedirectTemp /14-31 https://docs.python.org/3/library/socketserver.html -RedirectTemp /14-32 https://docs.python.org/3/library/socketserver.html#socketserver.BaseServer -RedirectTemp /14-33 https://github.com/python/cpython/blob/699ee016af5736ffc80f68359617611a22b72943/Lib/socketserver.py#L153 -RedirectTemp /14-34 https://docs.python.org/3/library/typing.html#typing.final -RedirectTemp /14-35 https://docs.python.org/3/library/typing.html#typing.Final -RedirectTemp /14-36 https://docs.python.org/3/library/collections.abc.html -RedirectTemp /14-37 https://hynek.me/articles/python-subclassing-redux/ -RedirectTemp /14-38 https://www.oreilly.com/library/view/python-cookbook-3rd/9781449357337/ch08.html#super -RedirectTemp /14-39 https://rhettinger.wordpress.com/2011/05/26/super-considered-super/ -RedirectTemp /14-40 https://fuhm.net/super-harmful/ -RedirectTemp /14-41 https://stackoverflow.com/questions/30190185/how-to-use-super-with-one-argument/30190341#30190341 -RedirectTemp /14-42 https://www.artima.com/weblogs/viewpost.jsp?thread=246488 -RedirectTemp /14-43 https://www.artima.com/weblogs/viewpost.jsp?thread=281127 -RedirectTemp /14-44 https://www.artima.com/weblogs/viewpost.jsp?thread=246341 -RedirectTemp /14-45 https://www.artima.com/weblogs/viewpost.jsp?thread=246483 -RedirectTemp /14-46 https://www.artima.com/weblogs/viewpost.jsp?thread=236275 -RedirectTemp /14-47 https://www.artima.com/weblogs/viewpost.jsp?thread=236278 -RedirectTemp /14-48 https://www.artima.com/weblogs/viewpost.jsp?thread=237121 -RedirectTemp /14-49 https://python-patterns.guide/gang-of-four/composition-over-inheritance/ -RedirectTemp /14-50 https://python-patterns.guide/ -RedirectTemp /14-51 https://www.youtube.com/watch?v=3MNVP9-hglc -RedirectTemp /14-52 http://worrydream.com/EarlyHistoryOfSmalltalk/ -RedirectTemp /14-53 https://en.wikipedia.org/wiki/Polymorphism_(computer_science) -############################################################ 15 -RedirectTemp /15-1 https://www.youtube.com/watch?v=csL8DLXGNlU&t=92m5s -RedirectTemp /15-2 https://github.com/python/typeshed/blob/a8834fcd46339e17fc8add82b5803a1ce53d3d60/stdlib/2and3/builtins.pyi#L1434 -RedirectTemp /15-3 https://github.com/python/typeshed/blob/a8834fcd46339e17fc8add82b5803a1ce53d3d60/stdlib/2and3/builtins.pyi -RedirectTemp /15-4 https://twitter.com/gwidion/status/1265384692464967680 -RedirectTemp /15-5 https://pypi.org/project/pydantic/ -RedirectTemp /15-6 https://google.github.io/pytype/faq.html -RedirectTemp /15-7 https://google.github.io/pytype/faq.html -RedirectTemp /15-8 https://lxml.de/ -RedirectTemp /15-9 https://docs.python.org/3/library/xml.etree.elementtree.html -RedirectTemp /15-10 https://mypy.readthedocs.io/en/stable/common_issues.html -RedirectTemp /15-11 https://mypy.readthedocs.io/en/stable/common_issues.html#types-of-empty-collections -RedirectTemp /15-12 https://github.com/python/typing/issues/182 -RedirectTemp /15-13 https://pypi.org/project/pydantic/ -RedirectTemp /15-14 https://mypy.readthedocs.io/en/stable/type_narrowing.html#casts -RedirectTemp /15-15 https://github.com/python/cpython/blob/bee66d3cb98e740f9d8057eb7f503122052ca5d8/Lib/typing.py#L1340 -RedirectTemp /15-16 https://www.python.org/dev/peps/pep-0484/#casts -RedirectTemp /15-17 https://github.com/python/typeshed/issues/5535 -RedirectTemp /15-18 https://docs.python.org/3/library/asyncio-stream.html#tcp-echo-server-using-streams -RedirectTemp /15-19 https://github.com/python/cpython/blob/b798ab06937f8bb24b444a49dd42e11fff15e654/Lib/test/test_asyncio/test_server.py#L55 -RedirectTemp /15-20 https://en.wikipedia.org/wiki/Code_smell -RedirectTemp /15-21 https://mail.python.org/archives/list/typing-sig@python.org/message/5LCWMN2UY2UQNLC5Z47GHBZKSPZW4I63/ -RedirectTemp /15-22 https://mypy.readthedocs.io/en/stable/error_codes.html#error-codes -RedirectTemp /15-23 https://github.com/fluentpython/example-code-2e/blob/master/15-more-types/clip_annot.py -RedirectTemp /15-24 https://docs.python.org/3/library/typing.html#introspection-helpers -RedirectTemp /15-25 https://docs.python.org/3.10/library/inspect.html#inspect.get_annotations -RedirectTemp /15-26 https://www.python.org/dev/peps/pep-0563/#abstract -RedirectTemp /15-27 https://mail.python.org/archives/list/python-dev@python.org/message/ZBJ7MD6CSGM6LZAOTET7GXAVBZB7O77O/ -RedirectTemp /15-28 https://docs.python.org/3.10/howto/annotations.html -RedirectTemp /15-29 https://docs.python.org/3/library/typing.html#user-defined-generic-types -RedirectTemp /15-30 https://github.com/python/typeshed/blob/bfc83c365a0b26ab16586beac77ff16729d0e473/stdlib/builtins.pyi#L743 -RedirectTemp /15-31 https://docs.python.org/3.10/library/typing.html#typing.FrozenSet -RedirectTemp /15-32 https://docs.python.org/3.10/library/typing.html#typing.Generator -RedirectTemp /15-33 https://docs.python.org/3.10/library/typing.html#typing.AsyncGenerator -RedirectTemp /15-34 https://github.com/python/cpython/blob/46b16d0bdbb1722daed10389e27226a2370f1635/Lib/typing.py#L1786 -RedirectTemp /15-35 https://github.com/python/typeshed/blob/2a9f081abbf01134e4e04ced6a750107db904d70/stdlib/builtins.pyi#L239 -RedirectTemp /15-36 https://www.oreilly.com/library/view/robust-python/9781098100650/ -RedirectTemp /15-37 https://www.python.org/dev/peps/pep-0484/#covariance-and-contravariance -RedirectTemp /15-38 https://mypy.readthedocs.io/en/stable/generics.html#variance-of-generic-types -RedirectTemp /15-39 https://mypy.readthedocs.io/en/stable/common_issues.html#variance -RedirectTemp /15-40 https://www.artima.com/weblogs/viewpost.jsp?thread=85551 -RedirectTemp /15-41 https://dl.acm.org/action/cookieAbsent -RedirectTemp /15-42 http://bracha.org/pluggableTypesPosition.pdf -RedirectTemp /15-43 https://www.researchgate.net/publication/213886116_Static_Typing_Where_Possible_Dynamic_Typing_When_Needed_The_End_of_the_Cold_War_Between_Programming_Languages -RedirectTemp /15-44 https://www.atomickotlin.com/atomickotlin/ -RedirectTemp /15-45 https://www.informit.com/store/effective-java-9780134685991 -RedirectTemp /15-46 https://www.manning.com/books/programming-with-types -RedirectTemp /15-47 https://www.oreilly.com/library/view/programming-typescript/9781492037644/ -RedirectTemp /15-48 https://www.informit.com/store/dart-programming-language-9780321927705 -RedirectTemp /15-49 https://www.yodaiken.com/2017/09/15/bad-ideas-in-type-theory/ -RedirectTemp /15-50 https://www.yodaiken.com/2017/11/30/types-considered-harmful-ii/ -RedirectTemp /15-51 https://web.archive.org/web/20071010002142/http://weblogs.java.net/blog/arnold/archive/2005/06/generics_consid_1.html -RedirectTemp /15-52 https://github.com/python/cpython/blob/3e7ee02327db13e4337374597cdc4458ecb9e3ad/Lib/asyncio/trsock.py#L5 -RedirectTemp /15-53 https://www.python.org/dev/peps/pep-0484/#covariance-and-contravariance -############################################################ 16 -RedirectTemp /16-1 http://www.gotw.ca/publications/c_family_interview.htm -RedirectTemp /16-2 https://docs.python.org/3/reference/expressions.html#unary-arithmetic-and-bitwise-operations -RedirectTemp /16-3 https://docs.python.org/3/reference/datamodel.html#object.__neg__ -RedirectTemp /16-4 https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#boolean-indexing -RedirectTemp /16-5 https://docs.python.org/3/library/collections.html#collections.Counter -RedirectTemp /16-6 https://docs.python.org/3/reference/datamodel.html#emulating-container-types -RedirectTemp /16-7 https://docs.python.org/3/library/numbers.html#implementing-the-arithmetic-operations -RedirectTemp /16-8 https://www.fluentpython.com/lingo/#fail-fast -RedirectTemp /16-9 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Objects/typeobject.c#L4598 -RedirectTemp /16-10 https://neopythonic.blogspot.com/2019/03/why-operators-are-useful.html -RedirectTemp /16-11 https://treyhunner.com/2019/03/python-deep-comparisons-and-code-readability/ -RedirectTemp /16-12 https://docs.python.org/3/library/numbers.html#implementing-the-arithmetic-operations -RedirectTemp /16-13 https://docs.python.org/3/library/pathlib.html -RedirectTemp /16-14 https://pypi.org/project/scapy/ -RedirectTemp /16-15 https://scapy.readthedocs.io/en/latest/usage.html#stacking-layers -RedirectTemp /16-16 https://docs.python.org/3/library/functools.html#functools.total_ordering -RedirectTemp /16-17 https://wiki.illinois.edu//wiki/download/attachments/273416327/ingalls.pdf -RedirectTemp /16-18 https://wiki.illinois.edu//wiki/download/attachments/273416327/double-dispatch.pdf -RedirectTemp /16-19 http://www.gotw.ca/publications/c_family_interview.htm -RedirectTemp /16-20 http://www.gotw.ca/publications/c_family_interview.htm -RedirectTemp /16-21 https://doc.rust-lang.org/std/ops/index.html -RedirectTemp /16-22 https://www.fluentpython.com/lingo/#lazy -############################################################ 17 -RedirectTemp /17-1 http://www.paulgraham.com/icad.html -RedirectTemp /17-2 https://en.wikipedia.org/wiki/Sentinel_value -RedirectTemp /17-3 https://docs.python.org/3.10/library/functions.html#iter -RedirectTemp /17-4 https://docs.python.org/3.10/library/functions.html#iter -RedirectTemp /17-5 https://github.com/python/cpython/blob/b1930bf75f276cd7ca08c4455298128d89adf7d1/Lib/_collections_abc.py#L271 -RedirectTemp /17-6 https://github.com/python/cpython/blob/main/Lib/types.py#L6 -RedirectTemp /17-7 https://en.wikipedia.org/wiki/CLU_(programming_language) -RedirectTemp /17-8 https://docs.python.org/3/glossary.html -RedirectTemp /17-9 https://docs.python.org/3/glossary.html#term-generator-iterator -RedirectTemp /17-10 https://docs.python.org/3/glossary.html#term-generator-expression -RedirectTemp /17-11 https://marc.info/?l=python-list&m=141826925106951&w=2 -RedirectTemp /17-12 https://docs.python.org/3/library/os.html#os.walk -RedirectTemp /17-13 https://docs.python.org/3/library/itertools.html -RedirectTemp /17-14 https://docs.python.org/3/library/exceptions.html#exception-hierarchy -RedirectTemp /17-15 https://en.wikipedia.org/wiki/Depth-first_search -RedirectTemp /17-16 https://docs.python.org/3.10/library/typing.html#typing.TypeAlias -RedirectTemp /17-17 https://docs.python.org/3/library/typing.html#typing.Generator -RedirectTemp /17-18 http://www.dabeaz.com/coroutines/Coroutines.pdf -RedirectTemp /17-19 http://www.dabeaz.com/coroutines/Coroutines.pdf -RedirectTemp /17-20 https://mail.python.org/pipermail/python-ideas/2009-April/003841.html -RedirectTemp /17-21 https://mail.python.org/pipermail/python-ideas/2009-April/003912.html -RedirectTemp /17-22 https://docs.python.org/3/library/exceptions.html#StopIteration -RedirectTemp /17-23 https://docs.python.org/3/reference/expressions.html#yield-expressions -RedirectTemp /17-24 https://docs.python.org/3/reference/index.html -RedirectTemp /17-25 https://github.com/python/cpython/blob/6f743e7a4da904f61dfa84cc7d7385e4dcc79ac5/Lib/typing.py#L2060 -RedirectTemp /17-26 http://catb.org/~esr/jargon/html/G/grok.html -RedirectTemp /17-27 https://docs.python.org/3/reference/expressions.html#yieldexpr -RedirectTemp /17-28 https://docs.python.org/3/library/itertools.html -RedirectTemp /17-29 https://docs.python.org/3/library/itertools.html#itertools-recipes -RedirectTemp /17-30 https://more-itertools.readthedocs.io/en/stable/index.html -RedirectTemp /17-31 https://rittau.org/2006/11/java-iterators-are-not-iterable/ -RedirectTemp /17-32 https://docs.python.org/3/whatsnew/3.3.html#pep-380-syntax-for-delegating-to-a-subgenerator -RedirectTemp /17-33 http://www.dabeaz.com/generators/ -RedirectTemp /17-34 http://www.dabeaz.com/coroutines/ -RedirectTemp /17-35 https://archive.org/details/pyvideo_213___pycon-2009-a-curious-course-on-coroutines-and-concurrency-part-1-of-3 -RedirectTemp /17-36 https://archive.org/details/pyvideo_215___pycon-2009-a-curious-course-on-coroutines-and-concurrency-part-2-of-3 -RedirectTemp /17-37 https://archive.org/details/pyvideo_214___pycon-2009-a-curious-course-on-coroutines-and-concurrency-part-3-of-3 -RedirectTemp /17-38 http://www.dabeaz.com/finalgenerator/ -RedirectTemp /17-39 https://web.archive.org/web/20200218150637/http://seriously.dontusethiscode.com/2013/05/01/greedy-coroutine.html -RedirectTemp /17-40 https://effectivepython.com/ -RedirectTemp /17-41 https://effectivepython.com/2015/03/10/consider-coroutines-to-run-many-functions-concurrently -RedirectTemp /17-42 https://en.wikipedia.org/wiki/Conway's_Game_of_Life -RedirectTemp /17-43 https://gist.github.com/ramalho/da5590bc38c973408839 -RedirectTemp /17-44 https://gist.github.com/ramalho/da5590bc38c973408839 -RedirectTemp /17-45 https://journal.code4lib.org/articles/4893 -RedirectTemp /17-46 https://github.com/fluentpython/isis2json -RedirectTemp /17-47 https://github.com/fluentpython/isis2json/blob/master/README.rst -############################################################ 18 -RedirectTemp /18-1 https://pyvideo.org/video/1669/keynote-3/ -RedirectTemp /18-2 https://docs.python.org/3/library/sqlite3.html#using-the-connection-as-a-context-manager -RedirectTemp /18-3 https://docs.python.org/3/library/threading.html#using-locks-conditions-and-semaphores-in-the-with-statement -RedirectTemp /18-4 https://docs.python.org/3/library/decimal.html#decimal.localcontext -RedirectTemp /18-5 https://docs.python.org/3/library/unittest.mock.html#patch -RedirectTemp /18-6 https://docs.python.org/3/library/contextlib.html#contextlib.redirect_stdout -RedirectTemp /18-7 https://docs.python.org/3/library/sys.html#sys.exc_info -RedirectTemp /18-8 https://en.wikipedia.org/wiki/LL_parser -RedirectTemp /18-9 https://docs.python.org/3/library/contextlib.html -RedirectTemp /18-10 https://github.com/python/cpython/blob/8afab2ebbc1b343cd88d058914cf622fe687a2be/Lib/contextlib.py#L123 -RedirectTemp /18-11 https://www.zopatista.com/python/2013/11/26/inplace-file-rewriting/ -RedirectTemp /18-12 https://docs.python.org/3/library/fileinput.html#fileinput.input -RedirectTemp /18-13 https://www.zopatista.com/python/2013/11/26/inplace-file-rewriting/ -RedirectTemp /18-14 https://en.wikipedia.org/wiki/Euclidean_algorithm -RedirectTemp /18-15 https://github.com/fluentpython/example-code-2e/tree/master/18-with-match/lispy/py3.10/ -RedirectTemp /18-16 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/original/lispy.py -RedirectTemp /18-17 https://github.com/fluentpython/example-code-2e/blob/6527037ae7319ba370a1ee2d9fe79214d0ed9452/18-with-match/lispy/py3.10/lis.py#L35 -RedirectTemp /18-18 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/py3.10/examples_test.py -RedirectTemp /18-19 https://github.com/python/typeshed/issues/6042 -RedirectTemp /18-20 https://github.com/fluentpython/lispy/tree/main/mylis -RedirectTemp /18-21 https://github.com/fluentpython/example-code-2e/blob/00e4741926e1b771ee7c753148b1415c0bd12e39/02-array-seq/lispy/py3.10/examples_test.py -RedirectTemp /18-22 https://mitpress.mit.edu/sites/default/files/sicp/index.html -RedirectTemp /18-23 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/py3.10/examples_test.py -RedirectTemp /18-24 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/py3.10/lis.py -RedirectTemp /18-25 https://www.python.org/dev/peps/pep-0634/#or-patterns -RedirectTemp /18-26 https://en.wikipedia.org/wiki/Lambda#Character_encodings -RedirectTemp /18-27 https://docs.python.org/3/reference/compound_stmts.html -RedirectTemp /18-28 https://docs.python.org/3/glossary.html#term-eafp -RedirectTemp /18-29 https://speakerdeck.com/pyconslides/pycon-keynote-python-is-awesome-by-raymond-hettinger?slide=21 -RedirectTemp /18-30 https://docs.python.org/3/reference/compound_stmts.html -RedirectTemp /18-31 https://stackoverflow.com/questions/16138232/is-it-a-good-practice-to-use-try-except-else-in-python -RedirectTemp /18-32 https://docs.python.org/3/library/stdtypes.html#typecontextmanager -RedirectTemp /18-33 https://docs.python.org/3/reference/datamodel.html#with-statement-context-managers -RedirectTemp /18-34 https://speakerdeck.com/pyconslides/pycon-keynote-python-is-awesome-by-raymond-hettinger?slide=21 -RedirectTemp /18-35 https://speakerdeck.com/pyconslides/transforming-code-into-beautiful-idiomatic-python-by-raymond-hettinger-1?slide=34 -RedirectTemp /18-36 https://preshing.com/20110920/the-python-with-statement-by-example/ -RedirectTemp /18-37 https://www.rath.org/on-the-beauty-of-pythons-exitstack.html -RedirectTemp /18-38 https://norvig.com/lispy.html -RedirectTemp /18-39 https://norvig.com/lispy2.html -RedirectTemp /18-40 https://github.com/norvig/pytudes -RedirectTemp /18-41 https://github.com/fluentpython/lispy -RedirectTemp /18-42 https://racket-lang.org/ -RedirectTemp /18-43 https://pyvideo.org/video/1669/keynote-3/ -RedirectTemp /18-44 https://en.wikipedia.org/wiki/Tail_call -RedirectTemp /18-45 https://2ality.com/2015/06/tail-call-optimization.html -RedirectTemp /18-46 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/original/lis.py -RedirectTemp /18-47 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/original/lispy.py -RedirectTemp /18-48 http://neopythonic.blogspot.com/2009/04/final-words-on-tail-calls.html -RedirectTemp /18-49 https://webkit.org/blog/6240/ecmascript-6-proper-tail-calls-in-webkit/ -RedirectTemp /18-50 http://kangax.github.io/compat-table/es6/ -RedirectTemp /18-51 https://world.hey.com/mgmarlow/what-happened-to-proper-tail-calls-in-javascript-5494c256 -RedirectTemp /18-52 http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html -RedirectTemp /18-53 https://github.com/fluentpython/lispy/blob/main/mylis/mylis_2/lis.py -RedirectTemp /18-54 https://github.com/fluentpython/lispy/tree/main/mylis -############################################################ 19 -RedirectTemp /19-1 https://go.dev/blog/waza-talk -RedirectTemp /19-2 https://en.wikipedia.org/wiki/Graphics_processing_unit -RedirectTemp /19-3 https://docs.python.org/3/library/sys.html#sys.getswitchinterval -RedirectTemp /19-4 https://docs.python.org/3/library/sys.html#sys.setswitchinterval -RedirectTemp /19-5 https://en.wikipedia.org/wiki/System_call -RedirectTemp /19-6 https://mail.python.org/pipermail/python-dev/2009-October/093356.html -RedirectTemp /19-7 http://www.dabeaz.com/finalgenerator/ -RedirectTemp /19-8 https://docs.python.org/3/library/threading.html#thread-objects -RedirectTemp /19-9 https://www.pypy.org/ -RedirectTemp /19-10 https://mail.python.org/pipermail/python-list/2009-February/675659.html -RedirectTemp /19-11 https://en.wikipedia.org/wiki/Braille_Patterns -RedirectTemp /19-12 https://docs.python.org/3/library/multiprocessing.shared_memory.html -RedirectTemp /19-13 https://docs.python.org/3/library/multiprocessing.shared_memory.html#multiprocessing.shared_memory.ShareableList -RedirectTemp /19-14 https://greenlet.readthedocs.io/en/latest/ -RedirectTemp /19-15 https://docs.sqlalchemy.org/en/14/changelog/migration_14.html#asynchronous-io-support-for-core-and-orm -RedirectTemp /19-16 https://docs.sqlalchemy.org/en/14/orm/extensions/asyncio.html -RedirectTemp /19-17 http://www.gevent.org/ -RedirectTemp /19-18 https://github.com/gevent/gevent/wiki/Projects -RedirectTemp /19-19 https://docs.python.org/3/library/concurrent.futures.html#processpoolexecutor-example -RedirectTemp /19-20 https://github.com/python/asyncio/issues/284 -RedirectTemp /19-21 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor -RedirectTemp /19-22 https://mail.python.org/archives/list/python-dev@python.org/message/JBYXQH3NV3YBF7P2HLHB5CD6V3GVTY55/ -RedirectTemp /19-23 https://docs.python.org/3/library/queue.html#queue.SimpleQueue.get -RedirectTemp /19-24 https://en.wikipedia.org/wiki/Race_condition -RedirectTemp /19-25 https://github.com/fluentpython/example-code-2e/commit/2c1230579db99738a5e5e6802063bda585f6476d -RedirectTemp /19-26 https://github.com/fluentpython/example-code-2e/blob/master/19-concurrency/primes/README.md -RedirectTemp /19-27 https://github.com/fluentpython/example-code-2e/blob/master/19-concurrency/primes/threads.py -RedirectTemp /19-28 https://en.wikipedia.org/wiki/Context_switch -RedirectTemp /19-29 http://www.gotw.ca/publications/concurrency-ddj.htm -RedirectTemp /19-30 https://www.ansible.com/ -RedirectTemp /19-31 https://saltproject.io/ -RedirectTemp /19-32 https://www.fabfile.org/ -RedirectTemp /19-33 https://engineering.fb.com/2016/05/27/production-engineering/python-in-production-engineering/ -RedirectTemp /19-34 https://jupyter.org/ -RedirectTemp /19-35 https://docs.bokeh.org/en/latest/index.html -RedirectTemp /19-36 https://www.tensorflow.org/ -RedirectTemp /19-37 https://pytorch.org/ -RedirectTemp /19-38 https://www.oreilly.com/radar/where-programming-ops-ai-and-the-cloud-are-headed-in-2021/ -RedirectTemp /19-39 https://www.youtube.com/watch?v=ods97a5Pzw0 -RedirectTemp /19-40 https://www.thoughtworks.com/radar/techniques/high-performance-envy-web-scale-envy -RedirectTemp /19-41 https://modwsgi.readthedocs.io/en/master/ -RedirectTemp /19-42 https://uwsgi-docs.readthedocs.io/en/latest/ -RedirectTemp /19-43 https://unit.nginx.org/ -RedirectTemp /19-44 https://www.techatbloomberg.com/blog/configuring-uwsgi-production-deployment/ -RedirectTemp /19-45 https://www.youtube.com/watch?v=p6R1h2Nn468 -RedirectTemp /19-46 https://asgi.readthedocs.io/en/latest/index.html -RedirectTemp /19-47 https://docs.celeryproject.org/en/stable/getting-started/introduction.html -RedirectTemp /19-48 https://python-rq.org/ -RedirectTemp /19-49 https://docs.celeryproject.org/en/stable/faq.html#what-kinds-of-things-should-i-use-celery-for -RedirectTemp /19-50 https://redis.io/ -RedirectTemp /19-51 https://realpython.com/intro-to-python-threading/ -RedirectTemp /19-52 https://pymotw.com/3/concurrency.html -RedirectTemp /19-53 https://www.pearson.com/us/higher-education/program/Hellmann-Python-3-Standard-Library-by-Example-The/PGM328871.html -RedirectTemp /19-54 https://docs.python.org/3/library/multiprocessing.html#programming-guidelines -RedirectTemp /19-55 https://docs.python.org/3/library/multiprocessing.html -RedirectTemp /19-56 https://www.oreilly.com/library/view/high-performance-python/9781492055013/ -RedirectTemp /19-57 https://link.springer.com/book/10.1007/978-1-4842-5793-7?error=cookies_not_supported&code=2ed5d61d-ae9f-4f3d-94ac-0f68cf45ea4f -RedirectTemp /19-58 https://www.packtpub.com/product/parallel-programming-with-python/9781783288397 -RedirectTemp /19-59 https://greenteapress.com/wp/semaphores/ -RedirectTemp /19-60 https://docs.python.org/3/c-api/init.html#thread-state-and-the-global-interpreter-lock -RedirectTemp /19-61 https://docs.python.org/3/faq/library.html#can-t-we-get-rid-of-the-global-interpreter-lock -RedirectTemp /19-62 https://www.artima.com/weblogs/viewpost.jsp?thread=214235 -RedirectTemp /19-63 http://jessenoller.com/blog/2009/02/01/python-threads-and-the-global-interpreter-lock -RedirectTemp /19-64 https://realpython.com/products/cpython-internals-book/ -RedirectTemp /19-65 http://www.dabeaz.com/GIL/ -RedirectTemp /19-66 http://www.dabeaz.com/python/UnderstandingGIL.pdf -RedirectTemp /19-67 https://bugs.python.org/issue7946#msg223110 -RedirectTemp /19-68 https://bugs.python.org/issue7946 -RedirectTemp /19-69 https://www.fullstackpython.com/ -RedirectTemp /19-70 https://www.oreilly.com/library/view/high-performance-python/9781492055013/ -RedirectTemp /19-71 https://www.packtpub.com/product/parallel-programming-with-python/9781783288397 -RedirectTemp /19-72 https://www.packtpub.com/product/distributed-computing-with-python/9781785889691 -RedirectTemp /19-73 https://towardsdatascience.com/python-performance-and-gpus-1be860ffd58d?gi=a7d537cc2fb4 -RedirectTemp /19-74 https://instagram-engineering.com/web-service-efficiency-at-instagram-with-python-4976d078e366?gi=12a441991c88 -RedirectTemp /19-75 https://www.oreilly.com/library/view/architecture-patterns-with/9781492052197/ -RedirectTemp /19-76 https://www.cosmicpython.com/ -RedirectTemp /19-77 https://pypi.org/project/lelo/ -RedirectTemp /19-78 https://github.com/npryce/python-parallelize -RedirectTemp /19-79 https://github.com/ericsnowcurrently/multi-core-python/wiki -RedirectTemp /19-80 https://gist.github.com/markshannon/79cace3656b40e21b7021504daee950c -RedirectTemp /19-81 https://mail.python.org/archives/list/python-dev@python.org/message/YOOQZCFOKEPQ24YHWWLQSJ3RCXFMS7D7/ -RedirectTemp /19-82 https://en.wikipedia.org/wiki/Communicating_sequential_processes -RedirectTemp /19-83 https://github.com/stackless-dev/stackless/wiki -RedirectTemp /19-84 https://www.eveonline.com -RedirectTemp /19-85 https://www.ccpgames.com/ -RedirectTemp /19-86 https://stackless.readthedocs.io/en/3.6-slp/stackless-python.html#history -RedirectTemp /19-87 https://doc.pypy.org/en/latest/stackless.html -RedirectTemp /19-88 https://greenlet.readthedocs.io/en/latest/ -RedirectTemp /19-89 http://www.gevent.org/ -RedirectTemp /19-90 http://thespianpy.com/doc/ -RedirectTemp /19-91 https://pykka.readthedocs.io/en/latest/ -RedirectTemp /19-92 https://www.manning.com/books/rabbitmq-in-action -RedirectTemp /19-93 https://pragprog.com/titles/pb7con/seven-concurrency-models-in-seven-weeks/ -RedirectTemp /19-94 https://en.wikipedia.org/wiki/OpenCL -RedirectTemp /19-95 https://media.pragprog.com/titles/pb7con/Bonus_Chapter.pdf -RedirectTemp /19-96 https://martinfowler.com/ -RedirectTemp /19-97 https://martinfowler.com/articles/patterns-of-distributed-systems/ -RedirectTemp /19-98 https://www.oreilly.com/library/view/designing-data-intensive-applications/9781491903063/ -RedirectTemp /19-99 https://www.oreilly.com/library/view/oscon-2016-video/9781491965153/video247021.html -RedirectTemp /19-100 https://www.oreilly.com/library/view/designing-for-scalability/9781449361556/ -RedirectTemp /19-101 https://www.thoughtworks.com/radar/techniques/high-performance-envy-web-scale-envy -RedirectTemp /19-102 https://en.wikipedia.org/wiki/KISS_principle -RedirectTemp /19-103 https://www.usenix.org/conference/hotos15/workshop-program/presentation/mcsherry -############################################################ 20 -RedirectTemp /20-1 https://www.artima.com/weblogs/viewpost.jsp?thread=299551 -RedirectTemp /20-2 https://docs.python.org/3/library/http.server.html -RedirectTemp /20-3 https://www.youtube.com/watch?v=A9e9Cy1UkME -RedirectTemp /20-4 https://www.cia.gov/the-world-factbook/ -RedirectTemp /20-5 https://docs.python-requests.org/en/latest/ -RedirectTemp /20-6 https://docs.python.org/3.10/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor -RedirectTemp /20-7 https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.as_completed -RedirectTemp /20-8 https://docs.python.org/3/library/concurrent.futures.html -RedirectTemp /20-9 https://docs.python.org/3.10/library/concurrent.futures.html#concurrent.futures.Executor -RedirectTemp /20-10 https://github.com/fluentpython/example-code-2e/blob/master/20-executors/getflags/flags2_common.py -RedirectTemp /20-11 https://github.com/noamraph/tqdm -RedirectTemp /20-12 https://www.youtube.com/watch?v=M8Z65tAl5l4 -RedirectTemp /20-13 https://github.com/noamraph/tqdm/blob/master/README.md -RedirectTemp /20-14 https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.as_completed -RedirectTemp /20-15 https://docs.python.org/3/library/asyncio-task.html#asyncio.as_completed -RedirectTemp /20-16 https://www.cloudflare.com/ -RedirectTemp /20-17 https://github.com/fluentpython/example-code-2e/tree/master/20-executors/getflags -RedirectTemp /20-18 https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/418 -RedirectTemp /20-19 https://en.wikipedia.org/wiki/Embarrassingly_parallel -RedirectTemp /20-20 https://pyvideo.org/video/480/pyconau-2010--the-future-is-soon/ -RedirectTemp /20-21 http://www.dabeaz.com/coroutines/ -RedirectTemp /20-22 https://en.wikipedia.org/wiki/POSIX_Threads -RedirectTemp /20-23 https://en.wikipedia.org/wiki/C_dynamic_memory_allocation -RedirectTemp /20-24 https://pragprog.com/titles/pb7con/seven-concurrency-models-in-seven-weeks/ -RedirectTemp /20-25 https://hexdocs.pm/ecto/getting-started.html -############################################################ 21 -RedirectTemp /21-1 https://docs.python.org/3/library/asyncio.html -RedirectTemp /21-2 https://bugs.python.org/issue43216 -RedirectTemp /21-3 https://bugs.python.org/issue36921 -RedirectTemp /21-4 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.getaddrinfo -RedirectTemp /21-5 https://docs.python.org/3/library/socket.html#socket.getaddrinfo -RedirectTemp /21-6 https://docs.python.org/3.10/library/asyncio-eventloop.html#asyncio.get_event_loop -RedirectTemp /21-7 https://www.python.org/dev/peps/pep-0492/#await-expression -RedirectTemp /21-8 https://www.fluentpython.com/extra/classic-coroutines/#yield_from_meaning_sec -RedirectTemp /21-9 https://github.com/fluentpython/example-code-2e/tree/master/20-executors/getflags -RedirectTemp /21-10 https://magicstack.github.io/asyncpg/current/ -RedirectTemp /21-11 https://magicstack.github.io/asyncpg/current/api/index.html#transactions -RedirectTemp /21-12 https://magicstack.github.io/asyncpg/current/api/index.html#transactions -RedirectTemp /21-13 https://github.com/MagicStack/asyncpg/blob/4d39a05268ce4cc01b00458223a767542da048b8/asyncpg/transaction.py#L57 -RedirectTemp /21-14 https://magicstack.github.io/asyncpg/current/usage.html#connection-pools -RedirectTemp /21-15 https://gist.github.com/jboner/2841832 -RedirectTemp /21-16 https://en.wikipedia.org/wiki/Network-attached_storage -RedirectTemp /21-17 https://en.wikipedia.org/wiki/Semaphore_(programming) -RedirectTemp /21-18 https://en.wikipedia.org/wiki/Semaphore_(programming) -RedirectTemp /21-19 https://groups.google.com/forum/#!msg/python-tulip/PdAEtwpaJHs/7fqb-Qj2zJoJ -RedirectTemp /21-20 https://web.archive.org/web/20151209151711/http://tritarget.org/blog/2012/11/28/the-pyramid-of-doom-a-javascript-style-trap -RedirectTemp /21-21 https://stackoverflow.com/questions/53701841/what-is-the-use-case-for-future-add-done-callback/53710563 -RedirectTemp /21-22 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor -RedirectTemp /21-23 https://motor.readthedocs.io/en/stable/ -RedirectTemp /21-24 https://emptysqua.re/blog/response-to-asynchronous-python-and-databases/ -RedirectTemp /21-25 https://docs.python.org/3/library/asyncio-stream.html#tcp-echo-server-using-streams -RedirectTemp /21-26 https://en.wikipedia.org/wiki/Phaistos_Disc -RedirectTemp /21-27 https://en.wikipedia.org/wiki/Inverted_index -RedirectTemp /21-28 https://fastapi.tiangolo.com/ -RedirectTemp /21-29 https://swagger.io/specification/ -RedirectTemp /21-30 https://asgi.readthedocs.io/en/latest/implementations.html -RedirectTemp /21-31 https://pydantic-docs.helpmanual.io/ -RedirectTemp /21-32 https://doc.traefik.io/traefik/ -RedirectTemp /21-33 https://fastapi.tiangolo.com/project-generation/ -RedirectTemp /21-34 https://fastapi.tiangolo.com/tutorial/response-model/ -RedirectTemp /21-35 https://docs.python.org/3/library/asyncio-stream.html#asyncio.start_server -RedirectTemp /21-36 https://github.com/python/typeshed/issues/5535 -RedirectTemp /21-37 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.Server.serve_forever -RedirectTemp /21-38 https://docs.python.org/3/library/asyncio-stream.html#asyncio.StreamWriter.close -RedirectTemp /21-39 https://docs.python.org/3/library/asyncio-stream.html#streamwriter -RedirectTemp /21-40 https://docs.python.org/3/library/asyncio-stream.html -RedirectTemp /21-41 https://docs.python.org/3/library/asyncio-protocol.html -RedirectTemp /21-42 https://docs.python.org/3/library/asyncio-protocol.html#tcp-echo-server -RedirectTemp /21-43 https://github.com/aio-libs/aiopg -RedirectTemp /21-44 https://docs.python.org/3/whatsnew/3.8.html#asyncio -RedirectTemp /21-45 https://datatracker.ietf.org/doc/html/rfc6761 -RedirectTemp /21-46 https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager -RedirectTemp /21-47 https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager -RedirectTemp /21-48 https://docs.python.org/3/library/asyncio-task.html#asyncio.gather -RedirectTemp /21-49 https://curio.readthedocs.io/en/latest/index.html -RedirectTemp /21-50 https://curio.readthedocs.io/en/latest/reference.html#task-groups -RedirectTemp /21-51 https://en.wikipedia.org/wiki/Structured_concurrency -RedirectTemp /21-52 https://mail.python.org/archives/list/python-dev@python.org/thread/2ORDAW74LGE3ZI2QETPJRT2ZL7MCCPG2/ -RedirectTemp /21-53 https://www.python.org/dev/peps/pep-0654/#motivation -RedirectTemp /21-54 https://curio.readthedocs.io/en/latest/reference.html#AWAIT -RedirectTemp /21-55 https://www.python-httpx.org/async/#curio -RedirectTemp /21-56 https://github.com/dabeaz/curio/tree/78bca8a6ad677ef51e1568ac7b3e51441ab49c42/examples -RedirectTemp /21-57 https://datatracker.ietf.org/doc/html/rfc8305 -RedirectTemp /21-58 https://trio.readthedocs.io/en/stable/ -RedirectTemp /21-59 https://www.youtube.com/watch?v=M-sc73Y-zQA -RedirectTemp /21-60 https://en.wikipedia.org/wiki/Technical_debt -RedirectTemp /21-61 https://www.youtube.com/watch?v=E-1Y4kSsAFc -RedirectTemp /21-62 https://github.com/dabeaz/curio -RedirectTemp /21-63 https://trio.readthedocs.io/en/stable/ -RedirectTemp /21-64 https://curio.readthedocs.io/en/latest/#curio-university -RedirectTemp /21-65 https://vorpus.org/blog/some-thoughts-on-asynchronous-api-design-in-a-post-asyncawait-world/ -RedirectTemp /21-66 https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/ -RedirectTemp /21-67 https://stackoverflow.com/questions/49482969/what-is-the-core-difference-between-asyncio-and-trio -RedirectTemp /21-68 https://docs.python.org/3/library/asyncio.html -RedirectTemp /21-69 https://bugs.python.org/issue33649 -RedirectTemp /21-70 https://docs.python.org/3/library/asyncio-dev.html -RedirectTemp /21-71 https://www.youtube.com/watch?v=iG6fr81xHKA -RedirectTemp /21-72 https://www.youtube.com/watch?v=F19R_M4Nay4 -RedirectTemp /21-73 https://asherman.io/projects/unsync.html -RedirectTemp /21-74 https://pyladies.com/ -RedirectTemp /21-75 https://www.youtube.com/watch?v=sW76-pRkZk8 -RedirectTemp /21-76 https://www.youtube.com/watch?v=Xbl7XjFYsN4 -RedirectTemp /21-77 https://www.youtube.com/watch?v=02CLD-42VdI -RedirectTemp /21-78 https://micropython.org/ -RedirectTemp /21-79 https://docs.micropython.org/en/latest/library/uasyncio.html -RedirectTemp /21-80 https://www.encode.io/articles/python-async-frameworks-beyond-developer-tribalism -RedirectTemp /21-81 https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/ -RedirectTemp /21-82 https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/ -RedirectTemp /21-83 https://github.com/MagicStack/uvloop -RedirectTemp /21-84 http://magic.io/blog/uvloop-blazing-fast-python-networking/ -RedirectTemp /21-85 https://github.com/MagicStack/httptools -RedirectTemp /21-86 https://docs.aiohttp.org/en/stable/ -RedirectTemp /21-87 https://github.com/wg/wrk -RedirectTemp /21-88 https://twistedmatrix.com/trac/ -############################################################ 22 -RedirectTemp /22-1 https://github.com/fluentpython/example-code-2e/blob/master/22-dyn-attr-prop/oscon/data/osconfeed.json -RedirectTemp /22-2 https://pypi.org/project/attrdict/ -RedirectTemp /22-3 https://pypi.org/project/addict/ -RedirectTemp /22-4 https://github.com/ActiveState/code/tree/master/recipes/Python/52308_simple_but_handy_collector_bunch_named_stuff -RedirectTemp /22-5 https://docs.python.org/3/library/types.html#types.SimpleNamespace -RedirectTemp /22-6 https://docs.python.org/3/library/argparse.html#argparse.Namespace -RedirectTemp /22-7 https://docs.python.org/3/library/multiprocessing.html#multiprocessing.managers.Namespace -RedirectTemp /22-8 https://github.com/fluentpython/example-code-2e/blob/master/22-dyn-attr-prop/oscon/schedule_v2.py -RedirectTemp /22-9 https://docs.python.org/3/library/functools.html#functools.cached_property -RedirectTemp /22-10 https://docs.python.org/3/library/functools.html#functools.cached_property -RedirectTemp /22-11 https://bugs.python.org/issue42781 -RedirectTemp /22-12 https://docs.python.org/3/howto/descriptor.html -RedirectTemp /22-13 https://github.com/python/cpython/blob/e6d0107e13ed957109e79b796984d3d026a8660d/Lib/functools.py#L926 -RedirectTemp /22-14 https://docs.python.org/3/library/threading.html#rlock-objects -RedirectTemp /22-15 https://docs.python.org/3.10/library/functools.html#functools.cached_property -RedirectTemp /22-16 https://www.wsj.com/articles/SB10001424052970203914304576627102996831200 -RedirectTemp /22-17 https://www.youtube.com/watch?v=s35rVw1zskA&feature=youtu.be -RedirectTemp /22-18 https://docs.python.org/3/library/functions.html#dir -RedirectTemp /22-19 https://github.com/python/cpython/blob/19903085c3ad7a17c8047e1556c700f2eb109931/Lib/cmd.py#L214 -RedirectTemp /22-20 https://docs.python.org/3/library/functions.html#hasattr -RedirectTemp /22-21 https://docs.python.org/3.10/reference/datamodel.html#special-method-lookup -RedirectTemp /22-22 https://docs.python.org/3/library/functions.html -RedirectTemp /22-23 https://docs.python.org/3/reference/datamodel.html#customizing-attribute-access -RedirectTemp /22-24 https://docs.python.org/3/reference/datamodel.html#special-method-lookup -RedirectTemp /22-25 https://docs.python.org/3/library/stdtypes.html#special-attributes -RedirectTemp /22-26 http://wiki.c2.com/?WelcomeVisitors -RedirectTemp /22-27 http://wiki.c2.com/?UniformAccessPrinciple -RedirectTemp /22-28 https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html -RedirectTemp /22-29 http://www.pingo.io/docs/ -RedirectTemp /22-30 https://www.drdobbs.com/javas-new-considered-harmful/184405016 -RedirectTemp /22-31 https://www.python.org/dev/peps/pep-0008/#class-names -############################################################ 23 -RedirectTemp /23-1 http://www.aleax.it/goo_pydp.pdf -RedirectTemp /23-2 https://docs.python.org/3.10/reference/datamodel.html#implementing-descriptors -RedirectTemp /23-3 https://docs.python.org/3/howto/descriptor.html -RedirectTemp /23-4 https://docs.python.org/3/howto/ -RedirectTemp /23-5 http://www.aleax.it/Python/nylug05_om.pdf -RedirectTemp /23-6 https://www.youtube.com/watch?v=VOzvpHoYQoo -RedirectTemp /23-7 https://www.python.org/dev/peps/pep-0487/#trait-descriptors -RedirectTemp /23-8 https://dreamsongs.com/RiseOfWorseIsBetter.html -RedirectTemp /23-9 http://web.archive.org/web/20031002184114/www.amk.ca/python/writing/warts.html -RedirectTemp /23-10 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this -RedirectTemp /23-11 http://python-history.blogspot.com/2009/02/adding-support-for-user-defined-classes.html -############################################################ 24 -RedirectTemp /24-1 https://docs.python.org/3/library/stdtypes.html#special-attributes -RedirectTemp /24-2 https://docs.djangoproject.com/en/3.2/topics/db/models/#meta-options -RedirectTemp /24-3 https://www.python.org/dev/peps/pep-3155/ -RedirectTemp /24-4 https://github.com/python/cpython/blob/3.9/Lib/collections/__init__.py -RedirectTemp /24-5 https://en.wikipedia.org/wiki/Tony_Hoare#Apologies_and_retractions -RedirectTemp /24-6 https://go.dev/tour/basics/12 -RedirectTemp /24-7 https://bugs.python.org/issue42102 -RedirectTemp /24-8 https://docs.python.org/3/reference/datamodel.html#object.__init_subclass__ -RedirectTemp /24-9 https://www.python.org/dev/peps/pep-0557/#abstract -RedirectTemp /24-10 https://github.com/python/cpython/blob/3.9/Lib/dataclasses.py -RedirectTemp /24-11 https://docs.python.org/3/reference/datamodel.html#creating-the-class-object -RedirectTemp /24-12 https://mail.python.org/pipermail/python-list/2002-December/134521.html -RedirectTemp /24-13 https://mail.python.org/pipermail/python-list/2002-July/162558.html -RedirectTemp /24-14 https://github.com/fluentpython/example-code/tree/master/21-class-metaprog/bulkfood -RedirectTemp /24-15 https://en.wikipedia.org/wiki/Principle_of_least_astonishment -RedirectTemp /24-16 https://docs.python.org/3/reference/datamodel.html#object.__class_getitem__ -RedirectTemp /24-17 https://en.wikipedia.org/wiki/Trait_(computer_programming) -RedirectTemp /24-18 https://en.wikipedia.org/wiki/Aspect-oriented_programming -RedirectTemp /24-19 https://dhh.dk/arc/000416.html -RedirectTemp /24-20 https://github.com/cjrh/autoslot -RedirectTemp /24-21 https://docs.python.org/3/reference/datamodel.html#customizing-class-creation -RedirectTemp /24-22 https://docs.python.org/3/library/functions.html#type -RedirectTemp /24-23 https://docs.python.org/3/library/stdtypes.html#special-attributes -RedirectTemp /24-24 https://docs.python.org/3/library/types.html -RedirectTemp /24-25 https://www.python.org/dev/peps/pep-3129/ -RedirectTemp /24-26 https://www.youtube.com/watch?v=cAGliEJV9_o -RedirectTemp /24-27 https://docs.python.org/3/library/functools.html#functools.total_ordering -RedirectTemp /24-28 https://www.python.org/download/releases/2.2.3/descrintro/ -RedirectTemp /24-29 https://github.com/lihaoyi/macropy -RedirectTemp /24-30 https://people.eecs.berkeley.edu/~bh/ss-toc2.html +# to update this file: +# cat custom.htaccess short.htaccess >> FPY.LI.htaccess diff --git a/links/README.md b/links/README.md index 6c9cfa8..2a3d80a 100644 --- a/links/README.md +++ b/links/README.md @@ -38,8 +38,15 @@ Exceptions: - URLs with `oreilly` in them are unchanged; - `fluentpython.com` URL (with no path) is unchanged; -The `custom.htacess` file contains the top redirects, which have custom names. -`FPY.LI.htaccess` has the same content, plus numbered URLs generated -from the links in each chapter in the book. +The `custom.htaccess` file contains redirects with custom names +plus numbered URLs generated from the links in each chapter in +the Second Edition in English. -The `FPY.LI.htaccess` is deployed at the root folder in `http://fpy.li`. +`short.htaccess` has redirects made by `short.py`, starting +with the Second Edition in Brazilian Portuguese. + +```shell +cat custom.htaccess short.htaccess > FPY.LI.htaccess +``` + +`FPY.LI.htaccess` is deployed at the root folder in `http://fpy.li`. diff --git a/links/custom.htaccess b/links/custom.htaccess index ad10802..cc779db 100644 --- a/links/custom.htaccess +++ b/links/custom.htaccess @@ -114,3 +114,959 @@ RedirectTemp /pep3141 https://www.python.org/dev/peps/pep-3141/ RedirectTemp /pep3148 https://www.python.org/dev/peps/pep-3148/ RedirectTemp /pep3155 https://www.python.org/dev/peps/pep-3155/ RedirectTemp /pep3333 https://www.python.org/dev/peps/pep-3333/ + +# Remaining URLs by chapter + +############################################################ p +RedirectTemp /p-1 https://mail.python.org/pipermail/python-list/2002-December/134521.html +RedirectTemp /p-2 https://docs.python.org/3.10/tutorial/ +RedirectTemp /p-3 https://docs.python.org/3/tutorial/ +RedirectTemp /p-4 https://www.oreilly.com/library/view/fluent-python-2nd/9781492056348/ +RedirectTemp /p-5 https://www.oreilly.com/online-learning/try-now.html +RedirectTemp /p-6 https://www.oreilly.com/library/view/fluent-python-2nd/9781492056348/ +RedirectTemp /p-7 https://stackoverflow.com/users/95810/alex-martelli +RedirectTemp /p-8 https://pythonpro.com.br +RedirectTemp /p-9 https://groups.google.com/g/python-brasil +RedirectTemp /p-10 https://www.coffeelab.com.br/ +RedirectTemp /p-11 https://garoa.net.br/wiki/P%C3%A1gina_principal +############################################################ a +RedirectTemp /a-1 https://groups.google.com/forum/#!topic/python-tulip/Y4bhLNbKs74 +RedirectTemp /a-2 https://docs.python.org/3/library/asyncio-eventloop.html#executor +RedirectTemp /a-3 https://www.youtube.com/watch?v=x-kB2o8sd5c +RedirectTemp /a-4 https://www.youtube.com/watch?v=OSGv2VnC0go +RedirectTemp /a-5 https://mail.python.org/pipermail/python-ideas/2015-March/032557.html +RedirectTemp /a-6 https://pypi.org/project/pep8/ +RedirectTemp /a-7 https://pypi.org/project/flake8/ +RedirectTemp /a-8 https://pypi.org/project/pyflakes/ +RedirectTemp /a-9 https://pypi.org/project/mccabe/ +RedirectTemp /a-10 https://google.github.io/styleguide/pyguide.html +RedirectTemp /a-11 https://flask.palletsprojects.com/en/1.1.x/styleguide/ +RedirectTemp /a-12 https://docs.python-guide.org/ +RedirectTemp /a-13 https://david.goodger.org/projects/pycon/2007/idiomatic/handout.html +RedirectTemp /a-14 https://docs.mongodb.com/manual/about/#about-the-documentation-process +RedirectTemp /a-15 https://blog.startifact.com/posts/older/what-is-pythonic.html +RedirectTemp /a-16 https://mail.python.org/pipermail/tutor/2003-October/thread.html#25930 +RedirectTemp /a-17 https://mail.python.org/pipermail/python-list/2003-April/192027.html +RedirectTemp /a-18 https://www.python.org/doc/essays/ +############################################################ 01 +RedirectTemp /1-1 http://hugunin.net/story_of_jython.html +RedirectTemp /1-2 https://www.oreilly.com/library/view/jython-essentials/9781449397364/ +RedirectTemp /1-3 https://docs.python.org/3/reference/lexical_analysis.html#reserved-classes-of-identifiers +RedirectTemp /1-4 https://docs.python.org/3.10/library/string.html#format-string-syntax +RedirectTemp /1-5 https://stackoverflow.com/questions/1436703/what-is-the-difference-between-str-and-repr +RedirectTemp /1-6 https://docs.python.org/3/library/stdtypes.html#truth +RedirectTemp /1-7 https://docs.python.org/3/tutorial/controlflow.html#unpacking-argument-lists +RedirectTemp /1-8 https://www.python.org/doc/humor/#the-zen-of-python +RedirectTemp /1-9 https://stackoverflow.com/users/95810/alex-martelli +RedirectTemp /1-10 https://en.wikipedia.org/wiki/Object_model +RedirectTemp /1-11 https://www.dourish.com/goodies/jargon.html +RedirectTemp /1-12 https://zopeinterface.readthedocs.io/en/latest/ +RedirectTemp /1-13 https://plone.org/ +############################################################ 02 +RedirectTemp /2-1 https://github.com/fluentpython/example-code-2e/blob/master/02-array-seq/listcomp_speed.py +RedirectTemp /2-2 https://www.python.org/dev/peps/pep-3132/ +RedirectTemp /2-3 https://stackoverflow.com/questions/68630/are-tuples-more-efficient-than-lists-in-python/22140115#22140115 +RedirectTemp /2-4 https://docs.python.org/3/whatsnew/3.5.html#pep-448-additional-unpacking-generalizations +RedirectTemp /2-5 https://docs.python.org/3/whatsnew/3.5.html#pep-448-additional-unpacking-generalizations +RedirectTemp /2-6 https://docs.python.org/3.10/whatsnew/3.10.html#pep-634-structural-pattern-matching +RedirectTemp /2-7 https://docs.python.org/3.10/whatsnew/3.10.html +RedirectTemp /2-8 https://en.wikipedia.org/wiki/Switch_statement#Fallthrough +RedirectTemp /2-9 https://en.wikipedia.org/wiki/Dangling_else +RedirectTemp /2-10 https://github.com/gvanrossum/patma/blob/3ece6444ef70122876fd9f0099eb9490a2d630df/EXAMPLES.md#case-6-a-very-deep-iterable-and-type-match-with-extraction +RedirectTemp /2-11 https://github.com/fluentpython/lispy/blob/main/original/norvig/lis.py +RedirectTemp /2-12 https://norvig.com/lispy.html +RedirectTemp /2-13 https://numpy.org/doc/stable/user/quickstart.html#indexing-slicing-and-iterating +RedirectTemp /2-14 https://pythontutor.com/ +RedirectTemp /2-15 https://en.wikipedia.org/wiki/Fluent_interface +RedirectTemp /2-16 https://docs.python.org/3/library/bisect.html#bisect.insort +RedirectTemp /2-17 https://stackoverflow.com/questions/4845418/when-should-a-memoryview-be-used/ +RedirectTemp /2-18 https://www.fluentpython.com/extra/parsing-binary-struct/ +RedirectTemp /2-19 http://www.netlib.org +RedirectTemp /2-20 https://pandas.pydata.org/ +RedirectTemp /2-21 https://scikit-learn.org/stable/ +RedirectTemp /2-22 https://docs.python.org/3/howto/sorting.html +RedirectTemp /2-23 https://www.python.org/dev/peps/pep-3132/ +RedirectTemp /2-24 https://bugs.python.org/issue2292 +RedirectTemp /2-25 https://docs.python.org/3.10/whatsnew/3.10.html#pep-634-structural-pattern-matching +RedirectTemp /2-26 https://docs.python.org/3.10/whatsnew/3.10.html +RedirectTemp /2-27 https://www.python.org/dev/peps/pep-0636/#appendix-a-quick-intro +RedirectTemp /2-28 https://eli.thegreenplace.net/2011/11/28/less-copies-in-python-with-the-buffer-protocol-and-memoryviews/ +RedirectTemp /2-29 https://jakevdp.github.io/PythonDataScienceHandbook/ +RedirectTemp /2-30 https://www.oreilly.com/library/view/python-for-data/9781491957653/ +RedirectTemp /2-31 https://www.labri.fr/perso/nrougier/from-python-to-numpy/ +RedirectTemp /2-32 https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html +RedirectTemp /2-33 http://www.fonts101.com/fonts/view/Uncategorized/34398/Dijkstra +RedirectTemp /2-34 https://docs.python.org/3/reference/datamodel.html#objects-values-and-types +RedirectTemp /2-35 https://en.wikipedia.org/wiki/Timsort +RedirectTemp /2-36 http://www.groklaw.net/pdf3/OraGoogle-1202.pdf +RedirectTemp /2-37 https://www.python.org/doc/humor/#id9 +############################################################ 03 +RedirectTemp /3-1 https://www.python.org/dev/peps/pep-0584/#motivation +RedirectTemp /3-2 https://docs.python.org/3.10/c-api/typeobj.html#Py_TPFLAGS_MAPPING +RedirectTemp /3-3 https://docs.python.org/3/glossary.html#term-hashable +RedirectTemp /3-4 https://docs.python.org/3/glossary.html#term-hashable +RedirectTemp /3-5 http://www.aleax.it/Python/accu04_Relearn_Python_alex.pdf +RedirectTemp /3-6 https://github.com/pingo-io/pingo-py +RedirectTemp /3-7 https://github.com/fluentpython/example-code-2e/blob/master/03-dict-set/missing.py +RedirectTemp /3-8 https://docs.python.org/3/library/collections.html#collections.ChainMap +RedirectTemp /3-9 https://docs.python.org/3/library/collections.html#collections.Counter +RedirectTemp /3-10 https://docs.python.org/3/library/shelve.html +RedirectTemp /3-11 https://docs.python.org/3/library/dbm.html +RedirectTemp /3-12 https://docs.python.org/3/library/pickle.html +RedirectTemp /3-13 https://nedbatchelder.com/blog/202006/pickles_nine_flaws.html +RedirectTemp /3-14 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Lib/_collections_abc.py#L813 +RedirectTemp /3-15 https://mail.python.org/pipermail/python-dev/2015-May/140003.html +RedirectTemp /3-16 https://bugs.python.org/issue18986 +RedirectTemp /3-17 https://github.com/fluentpython/example-code-2e/blob/master/03-dict-set/transformdict.py +RedirectTemp /3-18 http://gandenberger.org/2018/03/10/ordered-dicts-vs-ordereddict/ +RedirectTemp /3-19 https://www.pypy.org/ +RedirectTemp /3-20 https://morepypy.blogspot.com/2015/01/faster-more-memory-efficient-and-more.html +RedirectTemp /3-21 https://www.npopov.com/2014/12/22/PHPs-new-hashtable-implementation.html +RedirectTemp /3-22 https://www.youtube.com/watch?v=66P5FMkWoVU +RedirectTemp /3-23 https://pyvideo.org/video/276/the-mighty-dictionary-55/ +RedirectTemp /3-24 https://www.youtube.com/watch?v=p33CVV29OG8 +RedirectTemp /3-25 https://docs.python.org/3/whatsnew/3.6.html#new-dict-implementation +RedirectTemp /3-26 https://github.com/python/cpython/blob/cf7eaa4617295747ee5646c4e2b7e7a16d7c64ab/Objects/dictobject.c +RedirectTemp /3-27 https://github.com/python/cpython/blob/cf7eaa4617295747ee5646c4e2b7e7a16d7c64ab/Objects/dictnotes.txt +RedirectTemp /3-28 https://www.youtube.com/watch?v=tGAngdU_8D8 +RedirectTemp /3-29 https://speakerdeck.com/ramalho/python-set-practice-at-pycon +RedirectTemp /3-30 https://github.com/standupdev/uintset +RedirectTemp /3-31 https://spectrum.ieee.org/hans-peter-luhn-and-the-birth-of-the-hashing-algorithm +RedirectTemp /3-32 http://www.json.org/fatfree.html +RedirectTemp /3-33 https://twitter.com/mitsuhiko/status/1229385843585974272 +############################################################ 04 +RedirectTemp /4-1 https://www.slideshare.net/fischertrav/character-encoding-unicode-how-to-with-dignity-33352863 +RedirectTemp /4-2 https://pyvideo.org/video/2625/character-encoding-and-unicode-in-python/ +RedirectTemp /4-3 https://www.fluentpython.com/extra/parsing-binary-struct/ +RedirectTemp /4-4 https://www.fluentpython.com/extra/multi-character-emojis/ +RedirectTemp /4-5 https://w3techs.com/technologies/overview/character_encoding +RedirectTemp /4-6 https://docs.python.org/3/library/codecs.html#codecs.register_error +RedirectTemp /4-7 https://docs.python.org/3/library/stdtypes.html#str.isascii +RedirectTemp /4-8 https://pypi.org/project/chardet/ +RedirectTemp /4-9 https://docs.python.org/3/library/codecs.html#encodings-and-unicode +RedirectTemp /4-10 https://nedbatchelder.com/text/unipain/unipain.html +RedirectTemp /4-11 https://devblogs.microsoft.com/commandline/windows-command-line-unicode-and-utf-8-output-text-buffer/ +RedirectTemp /4-12 https://docs.python.org/3/using/cmdline.html#envvar-PYTHONIOENCODING +RedirectTemp /4-13 https://docs.python.org/3/using/cmdline.html#envvar-PYTHONLEGACYWINDOWSSTDIO +RedirectTemp /4-14 https://docs.python.org/3/library/locale.html#locale.getpreferredencoding +RedirectTemp /4-15 http://www.w3.org/TR/charmod-norm/ +RedirectTemp /4-16 https://docs.python.org/3/library/locale.html?highlight=strxfrm#locale.strxfrm +RedirectTemp /4-17 https://pypi.org/project/pyuca/ +RedirectTemp /4-18 https://github.com/jtauber/pyuca +RedirectTemp /4-19 http://www.unicode.org/Public/UCA/6.3.0/allkeys.txt +RedirectTemp /4-20 https://pypi.org/project/PyICU/ +RedirectTemp /4-21 https://docs.python.org/3.10/library/stdtypes.html#str.isalpha +RedirectTemp /4-22 https://en.wikipedia.org/wiki/Unicode_character_property#General_Category +RedirectTemp /4-23 https://en.wikipedia.org/wiki/Unicode_character_property +RedirectTemp /4-24 https://github.com/microsoft/terminal +RedirectTemp /4-25 https://docs.python.org/3/library/unicodedata.html +RedirectTemp /4-26 https://docs.python.org/3/reference/lexical_analysis.html#string-literal-concatenation +RedirectTemp /4-27 https://docs.python.org/3/library/re.html +RedirectTemp /4-28 https://nedbatchelder.com/text/unipain.html +RedirectTemp /4-29 https://www.slideshare.net/fischertrav/character-encoding-unicode-how-to-with-dignity-33352863 +RedirectTemp /4-30 https://pyvideo.org/video/2625/character-encoding-and-unicode-in-python/ +RedirectTemp /4-31 https://regebro.wordpress.com/2011/03/23/unconfusing-unicode-what-is-unicode/ +RedirectTemp /4-32 https://docs.python.org/3/howto/unicode.html +RedirectTemp /4-33 https://diveintopython3.net/strings.html +RedirectTemp /4-34 https://diveintopython3.net/ +RedirectTemp /4-35 https://finderiko.com/python-book +RedirectTemp /4-36 https://docs.python.org/3.0/whatsnew/3.0.html#text-vs-data-instead-of-unicode-vs-8-bit +RedirectTemp /4-37 https://lucumr.pocoo.org/2013/7/2/the-updated-guide-to-unicode/ +RedirectTemp /4-38 http://python-notes.curiousefficiency.org/en/latest/python3/binary_protocols.html +RedirectTemp /4-39 http://python-notes.curiousefficiency.org/en/latest/python3/text_file_processing.html +RedirectTemp /4-40 https://docs.python.org/3/library/codecs.html#standard-encodings +RedirectTemp /4-41 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Tools/unicode/listcodecs.py +RedirectTemp /4-42 https://www.oreilly.com/library/view/unicode-explained/059610121X/ +RedirectTemp /4-43 https://www.informit.com/store/unicode-demystified-a-practical-programmers-guide-to-9780201700527 +RedirectTemp /4-44 https://unicodebook.readthedocs.io/index.html +RedirectTemp /4-45 https://www.w3.org/International/wiki/Case_folding +RedirectTemp /4-46 http://www.w3.org/TR/charmod-norm/ +RedirectTemp /4-47 http://unicode.org/reports/tr15/ +RedirectTemp /4-48 http://www.unicode.org/faq/normalization.html +RedirectTemp /4-49 http://www.unicode.org/ +RedirectTemp /4-50 http://www.macchiato.com/unicode/nfc-faq +RedirectTemp /4-51 https://stories.moma.org/the-original-emoji-set-has-been-added-to-the-museum-of-modern-arts-collection-c6060e141f61?gi=c403f5a840a5 +RedirectTemp /4-52 https://emojipedia.org/ +RedirectTemp /4-53 https://blog.emojipedia.org/correcting-the-record-on-the-first-emoji-set/ +RedirectTemp /4-54 http://emojitracker.com/ +RedirectTemp /4-55 http://www.unicode.org/glossary/#plain_text +RedirectTemp /4-56 http://www.methods.co.nz/asciidoc/ +RedirectTemp /4-57 https://atlas.oreilly.com/ +############################################################ 05 +RedirectTemp /5-1 https://docs.python.org/3/library/typing.html#typing.TypedDict +RedirectTemp /5-2 https://docs.python.org/3.10/library/inspect.html#inspect.get_annotations +RedirectTemp /5-3 https://docs.python.org/3/library/typing.html#typing.get_type_hints +RedirectTemp /5-4 https://docs.python.org/3.8/library/collections.html#collections.somenamedtuple._asdict +RedirectTemp /5-5 https://www.jetbrains.com/pycharm/ +RedirectTemp /5-6 https://www.python.org/dev/peps/pep-0484/#acceptable-type-hints +RedirectTemp /5-7 https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass +RedirectTemp /5-8 https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass +RedirectTemp /5-9 https://docs.python.org/3/library/dataclasses.html +RedirectTemp /5-10 https://docs.python.org/3/library/dataclasses.html#inheritance +RedirectTemp /5-11 https://www.python.org/dev/peps/pep-0526/#class-and-instance-variable-annotations +RedirectTemp /5-12 https://dublincore.org/specifications/dublin-core/ +RedirectTemp /5-13 https://en.wikipedia.org/wiki/Dublin_Core +RedirectTemp /5-14 https://martinfowler.com/bliki/CodeSmell.html +RedirectTemp /5-15 https://martinfowler.com/books/refactoring.html +RedirectTemp /5-16 https://www.python.org/dev/peps/pep-0634/#class-patterns +RedirectTemp /5-17 https://docs.python.org/3/library/dataclasses.html +RedirectTemp /5-18 https://www.python.org/dev/peps/pep-0557/#id47 +RedirectTemp /5-19 https://www.python.org/dev/peps/pep-0557/#id48 +RedirectTemp /5-20 https://www.python.org/dev/peps/pep-0557/#id33 +RedirectTemp /5-21 https://realpython.com +RedirectTemp /5-22 https://realpython.com/python-data-classes/ +RedirectTemp /5-23 https://www.youtube.com/watch?v=T-TwcmT6Rcw +RedirectTemp /5-24 https://www.attrs.org/en/stable/ +RedirectTemp /5-25 https://glyph.twistedmatrix.com/2016/08/attrs.html +RedirectTemp /5-26 https://www.attrs.org/en/stable/why.html +RedirectTemp /5-27 https://github.com/dabeaz/cluegen +RedirectTemp /5-28 https://refactoring.guru/ +RedirectTemp /5-29 https://refactoring.guru/smells/data-class +RedirectTemp /5-30 https://web.archive.org/web/20190204130328/http://catb.org/esr/jargon/html/G/Guido.html +RedirectTemp /5-31 https://web.archive.org/web/20190211161610/http://catb.org/esr/jargon/html/index.html +RedirectTemp /5-32 https://www.attrs.org/en/stable/ +############################################################ 06 +RedirectTemp /6-1 https://www.olin.edu/faculty/profile/lynn-andrea-stein/ +RedirectTemp /6-2 https://docs.python.org/3/reference/datamodel.html#objects-values-and-types +RedirectTemp /6-3 https://pythontutor.com/ +RedirectTemp /6-4 https://docs.python.org/3/library/copy.html +RedirectTemp /6-5 https://en.wikipedia.org/wiki/Principle_of_least_astonishment +RedirectTemp /6-6 https://docs.python.org/3/reference/datamodel.html#object.%5C_%5C_del__ +RedirectTemp /6-7 https://emptysqua.re/blog/pypy-garbage-collection-and-a-deadlock/ +RedirectTemp /6-8 https://www.youtube.com/watch?v=HHFCFJSPWrI&feature=youtu.be +RedirectTemp /6-9 http://pymotw.com/3/copy/ +RedirectTemp /6-10 http://pymotw.com/3/weakref/ +RedirectTemp /6-11 https://docs.python.org/3/library/gc.html +RedirectTemp /6-12 https://devguide.python.org/garbage_collector/ +RedirectTemp /6-13 https://devguide.python.org/ +RedirectTemp /6-14 https://www.python.org/dev/peps/pep-0442/ +RedirectTemp /6-15 https://en.wikipedia.org/wiki/String_interning +RedirectTemp /6-16 https://en.wikipedia.org/wiki/Haddocks%27_Eyes +RedirectTemp /6-17 https://thp.io/2012/python-gc/python_gc_final_2012-01-22.pdf +############################################################ 07 +RedirectTemp /7-1 http://python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html +RedirectTemp /7-2 https://www.fluentpython.com/extra/function-introspection/ +RedirectTemp /7-3 https://docs.python.org/3/library/functions.html#map +RedirectTemp /7-4 https://en.wikipedia.org/wiki/Functional_programming +RedirectTemp /7-5 https://docs.python.org/3/howto/functional.html +RedirectTemp /7-6 https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy +RedirectTemp /7-7 https://docs.python.org/3/whatsnew/3.8.html#positional-only-parameters +RedirectTemp /7-8 https://docs.python.org/3/whatsnew/3.8.html#positional-only-parameters +RedirectTemp /7-9 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Lib/functools.py#L341 +RedirectTemp /7-10 https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy +RedirectTemp /7-11 https://docs.python.org/3/howto/functional.html +RedirectTemp /7-12 https://stackoverflow.com/questions/3252228/python-why-is-functools-partial-necessary +RedirectTemp /7-13 https://speakerdeck.com/ramalho/beyond-paradigms-berlin-edition +RedirectTemp /7-14 https://www.youtube.com/watch?v=bF3a2VYXxa0 +RedirectTemp /7-15 http://cs.brown.edu/~sk/Publications/Papers/Published/sk-teach-pl-post-linnaean/ +RedirectTemp /7-16 http://python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html +RedirectTemp /7-17 https://raw.githubusercontent.com/python/cpython/main/Misc/HISTORY +RedirectTemp /7-18 http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html +############################################################ 08 +RedirectTemp /8-1 https://www.python.org/dev/peps/pep-0484/#non-goals +RedirectTemp /8-2 https://github.com/python/typing/issues/182 +RedirectTemp /8-3 https://github.com/python/mypy/issues/731 +RedirectTemp /8-4 https://github.com/google/pytype +RedirectTemp /8-5 https://github.com/Microsoft/pyright +RedirectTemp /8-6 https://pyre-check.org/ +RedirectTemp /8-7 https://mypy.readthedocs.io/en/stable/introduction.html +RedirectTemp /8-8 https://mypy.readthedocs.io/en/stable/config_file.html +RedirectTemp /8-9 https://pypi.org/project/flake8/ +RedirectTemp /8-10 https://pypi.org/project/blue/ +RedirectTemp /8-11 https://pypi.org/project/black/ +RedirectTemp /8-12 https://wefearchange.org/2020/11/steeringcouncil.rst.html +RedirectTemp /8-13 https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes +RedirectTemp /8-14 https://en.wikipedia.org/wiki/Barbara_Liskov +RedirectTemp /8-15 https://en.wikipedia.org/wiki/Behavioral_subtyping +RedirectTemp /8-16 https://www.python.org/dev/peps/pep-0585/#implementation +RedirectTemp /8-17 https://docs.python.org/3/library/typing.html#module-contents +RedirectTemp /8-18 https://en.wikipedia.org/wiki/Geohash +RedirectTemp /8-19 https://en.wikipedia.org/wiki/Inverted_index +RedirectTemp /8-20 https://docs.python.org/3/library/typing.html#typing.List +RedirectTemp /8-21 https://docs.python.org/3/library/typing.html#typing.Dict +RedirectTemp /8-22 https://docs.python.org/3/library/typing.html#typing.Set +RedirectTemp /8-23 https://www.python.org/dev/peps/pep-0585/#implementation +RedirectTemp /8-24 https://docs.python.org/3/library/numbers.html +RedirectTemp /8-25 https://docs.python.org/3/library/typing.html#typing.List +RedirectTemp /8-26 https://github.com/python/typeshed +RedirectTemp /8-27 https://github.com/python/typeshed/blob/66cd36268a6a667714efaa27198a41d0d7f89477/stdlib/2and3/math.pyi#L45 +RedirectTemp /8-28 https://docs.python.org/3/library/statistics.html#statistics.mode +RedirectTemp /8-29 https://github.com/python/cpython/blob/822efa5695b5ba6c2316c1400e4e9ec2546f7ea5/Lib/statistics.py#L534 +RedirectTemp /8-30 https://github.com/python/typeshed/blob/e1e99245bb46223928eba68d4fc74962240ba5b4/stdlib/3/statistics.pyi +RedirectTemp /8-31 https://docs.python.org/3/library/statistics.html#statistics.mode +RedirectTemp /8-32 https://github.com/python/typeshed/blob/a8834fcd46339e17fc8add82b5803a1ce53d3d60/stdlib/3/statistics.pyi#L32 +RedirectTemp /8-33 https://mail.python.org/archives/list/python-dev@python.org/thread/CLVXXPQ2T2LQ5MP2Y53VVQFCXYWQJHKZ/ +RedirectTemp /8-34 https://docs.python.org/3/library/typing.html#typing.Callable +RedirectTemp /8-35 https://pypi.org/project/blue/ +RedirectTemp /8-36 https://www.python.org/dev/peps/pep-0484/#id38 +RedirectTemp /8-37 https://docs.google.com/document/d/1aXs1tpwzPjW9MdsG5dI7clNFyYayFBkcXwRDo-qvbIk/preview +RedirectTemp /8-38 https://www.oreilly.com/library/view/the-best-software/9781590595008/ +RedirectTemp /8-39 https://www.youtube.com/watch?v=YFexUDjHO6w +RedirectTemp /8-40 https://www.youtube.com/watch?v=YFexUDjHO6w&t=13m40s +RedirectTemp /8-41 https://bernat.tech/posts/the-state-of-type-hints-in-python/ +RedirectTemp /8-42 https://realpython.com/python-type-checking/ +RedirectTemp /8-43 https://cjolowicz.github.io/posts/hypermodern-python-04-typing/ +RedirectTemp /8-44 https://mypy.readthedocs.io/en/stable/index.html +RedirectTemp /8-45 https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html +RedirectTemp /8-46 https://mypy.readthedocs.io/en/stable/common_issues.html +RedirectTemp /8-47 https://github.com/typeddjango/awesome-python-typing +RedirectTemp /8-48 https://docs.python.org/3/library/functions.html#max +RedirectTemp /8-49 https://en.wikipedia.org/wiki/Linguistic_relativity +RedirectTemp /8-50 https://pypistats.org/top +RedirectTemp /8-51 https://github.com/psf/requests/issues/3855 +RedirectTemp /8-52 https://lwn.net/Articles/643399/ +RedirectTemp /8-53 https://docs.python-requests.org/en/master/api/#requests.request +RedirectTemp /8-54 https://queue.acm.org/detail.cfm?id=1039523 +############################################################ 09 +RedirectTemp /9-1 https://docs.python.org/3/library/dis.html +RedirectTemp /9-2 https://en.wikipedia.org/wiki/Memoization +RedirectTemp /9-3 https://numpy.org/doc/stable/user/basics.types.html +RedirectTemp /9-4 https://docs.python.org/3/library/functools.html#functools.singledispatch +RedirectTemp /9-5 https://github.com/GrahamDumpleton/wrapt/blob/develop/blog/README.md +RedirectTemp /9-6 https://github.com/GrahamDumpleton/wrapt/blob/develop/blog/01-how-you-implemented-your-python-decorator-is-wrong.md +RedirectTemp /9-7 https://wrapt.readthedocs.io/en/latest/ +RedirectTemp /9-8 https://www.oreilly.com/library/view/python-cookbook-3rd/9781449357337/ch09.html +RedirectTemp /9-9 https://pypi.org/project/decorator/ +RedirectTemp /9-10 https://wiki.python.org/moin/PythonDecoratorLibrary +RedirectTemp /9-11 http://web.archive.org/web/20201109032203/http://effbot.org/zone/closure.htm +RedirectTemp /9-12 https://www.python.org/dev/peps/pep-3104/ +RedirectTemp /9-13 https://www.python.org/dev/peps/pep-0227/ +RedirectTemp /9-14 https://www.python.org/dev/peps/pep-0443/ +RedirectTemp /9-15 https://www.artima.com/weblogs/viewpost.jsp?thread=101605 +RedirectTemp /9-16 https://reg.readthedocs.io/en/latest/ +RedirectTemp /9-17 https://morepath.readthedocs.io/en/latest/ +RedirectTemp /9-18 https://www.gnu.org/software/emacs/manual/html_node/elisp/Dynamic-Binding.html +RedirectTemp /9-19 http://www.paulgraham.com/rootsoflisp.html +RedirectTemp /9-20 http://www-formal.stanford.edu/jmc/recursive/recursive.html +RedirectTemp /9-21 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this +############################################################ 10 +RedirectTemp /10-1 https://en.wikipedia.org/wiki/Software_design_pattern +RedirectTemp /10-2 https://en.wikipedia.org/wiki/Iterator_pattern +RedirectTemp /10-3 https://github.com/python/mypy/issues/9397 +RedirectTemp /10-4 http://www.norvig.com/design-patterns/index.htm +RedirectTemp /10-5 https://pyvideo.org/video/1110/python-design-patterns/ +RedirectTemp /10-6 http://www.aleax.it/gdd_pydp.pdf +RedirectTemp /10-7 https://perl.plover.com/yak/design/ +RedirectTemp /10-8 https://en.wikipedia.org/wiki/Turtles_all_the_way_down +############################################################ 11 +RedirectTemp /11-1 https://blog.startifact.com/posts/older/what-is-pythonic.html +RedirectTemp /11-2 https://julien.danjou.info/guide-python-static-class-abstract-methods/ +RedirectTemp /11-3 https://docs.python.org/3/library/string.html#formatspec +RedirectTemp /11-4 https://docs.python.org/3/reference/lexical_analysis.html#f-strings +RedirectTemp /11-5 https://docs.python.org/3/library/string.html#format-string-syntax +RedirectTemp /11-6 https://docs.python.org/3/library/string.html#formatspec +RedirectTemp /11-7 https://docs.python.org/3/reference/datamodel.html#object.__hash__ +RedirectTemp /11-8 https://web.archive.org/web/20161025185040/http://pythonpaste.org/StyleGuide.html +RedirectTemp /11-9 https://docs.python.org/3/tutorial/modules.html#more-on-modules +RedirectTemp /11-10 https://docs.python.org/3/library/gettext.html#gettext.NullTranslations +RedirectTemp /11-11 https://github.com/fluentpython/example-code-2e/blob/master/11-pythonic-obj/mem_test.py +RedirectTemp /11-12 https://docs.python.org/3/reference/datamodel.html#basic-customization +RedirectTemp /11-13 http://esug.org/data/HistoricalDocuments/TheSmalltalkReport/ST07/04wo.pdf +RedirectTemp /11-14 https://www.artima.com/articles/the-simplest-thing-that-could-possibly-work#part3 +RedirectTemp /11-15 https://docs.oracle.com/javase/tutorial/essential/environment/security.html +RedirectTemp /11-16 https://github.com/fluentpython/example-code-2e/blob/master/11-pythonic-obj/private/Expose.java +RedirectTemp /11-17 https://docs.oracle.com/javase/tutorial/essential/environment/security.html +############################################################ 12 +RedirectTemp /12-1 https://en.wikipedia.org/wiki/Vector_space_model +RedirectTemp /12-2 https://pypi.org/project/gensim/ +RedirectTemp /12-3 https://docs.python.org/3/library/functions.html#enumerate +RedirectTemp /12-4 https://mathworld.wolfram.com/Hypersphere.html +RedirectTemp /12-5 https://en.wikipedia.org/wiki/Fold_(higher-order_function) +RedirectTemp /12-6 https://docs.python.org/2.5/whatsnew/pep-357.html +RedirectTemp /12-7 https://docs.python.org/3/reference/datamodel.html#special-method-names +RedirectTemp /12-8 https://en.wikipedia.org/wiki/KISS_principle +RedirectTemp /12-9 https://mail.python.org/pipermail/python-list/2000-July/046184.html +RedirectTemp /12-10 https://en.wikipedia.org/wiki/Duck_typing +RedirectTemp /12-11 https://mail.python.org/mailman/listinfo/python-list +RedirectTemp /12-12 https://mail.python.org/pipermail/python-list/2003-April/218568.html +############################################################ 13 +RedirectTemp /13-1 https://docs.python.org/3/c-api/index.html +RedirectTemp /13-2 https://docs.python.org/3/c-api/sequence.html +RedirectTemp /13-3 https://github.com/python/cpython/blob/31ceccb2c77854893f3a754aca04bedd74bedb10/Lib/_collections_abc.py#L870 +RedirectTemp /13-4 https://en.wikipedia.org/wiki/Monkey_patch +RedirectTemp /13-5 https://www.gevent.org/api/gevent.monkey.html +RedirectTemp /13-6 https://docs.python.org/3/library/random.html#random.shuffle +RedirectTemp /13-7 https://docs.python.org/3/reference/datamodel.html#emulating-container-types +RedirectTemp /13-8 https://docs.python.org/3/library/collections.html#collections.namedtuple +RedirectTemp /13-9 https://github.com/python/typeshed/blob/24afb531ffd07083d6a74be917342195062f7277/stdlib/collections/__init__.pyi +RedirectTemp /13-10 https://docs.python.org/3/glossary.html#term-abstract-base-class +RedirectTemp /13-11 https://en.wikipedia.org/wiki/Duck_typing#History +RedirectTemp /13-12 http://ptgmedia.pearsoncmg.com/images/020163371x/items/item33.html +RedirectTemp /13-13 https://docs.python.org/3/library/bisect.html#bisect.bisect +RedirectTemp /13-14 https://github.com/python/cpython/blob/main/Lib/_collections_abc.py +RedirectTemp /13-15 https://github.com/python/cpython/blob/main/Lib/abc.py +RedirectTemp /13-16 https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes +RedirectTemp /13-17 https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable +RedirectTemp /13-18 https://docs.python.org/3/library/abc.html +RedirectTemp /13-19 https://docs.python.org/dev/library/abc.html#abc.abstractmethod +RedirectTemp /13-20 https://docs.python.org/dev/library/abc.html +RedirectTemp /13-21 https://docs.python.org/3/library/os.html#os.urandom +RedirectTemp /13-22 https://github.com/python/mypy/issues/2922 +RedirectTemp /13-23 https://docs.python.org/3/library/stdtypes.html#truth +RedirectTemp /13-24 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Lib/_collections_abc.py +RedirectTemp /13-25 https://github.com/python/cpython/blob/0fbddb14dc03f61738af01af88e7d8aa8df07336/Lib/_collections_abc.py#L369 +RedirectTemp /13-26 https://github.com/python/cpython/blob/c0a9afe2ac1820409e6173bd1893ebee2cf50270/Lib/abc.py#L196 +RedirectTemp /13-27 https://bugs.python.org/issue31333 +RedirectTemp /13-28 https://github.com/python/cpython/blob/3635388f52b42e5280229104747962117104c453/Modules/_abc.c#L605 +RedirectTemp /13-29 https://github.com/python/cpython/blob/0fbddb14dc03f61738af01af88e7d8aa8df07336/Lib/_collections_abc.py#L881 +RedirectTemp /13-30 https://docs.python.org/3/library/typing.html#protocols +RedirectTemp /13-31 https://github.com/python/cpython/blob/3635388f52b42e5280229104747962117104c453/Lib/typing.py#L1751 +RedirectTemp /13-32 https://mail.python.org/archives/list/python-dev@python.org/thread/CLVXXPQ2T2LQ5MP2Y53VVQFCXYWQJHKZ/ +RedirectTemp /13-33 https://martinfowler.com/bliki/RoleInterface.html +RedirectTemp /13-34 https://en.wikipedia.org/wiki/Interface_segregation_principle +RedirectTemp /13-35 https://github.com/python/typeshed/blob/master/CONTRIBUTING.md +RedirectTemp /13-36 https://gist.github.com/asukakenji/ac8a05644a2e98f1d5ea8c299541fce9 +RedirectTemp /13-37 https://www.python.org/dev/peps/pep-0544/#runtime-checkable-decorator-and-narrowing-types-by-isinstance +RedirectTemp /13-38 https://www.python.org/dev/peps/pep-0544/#merging-and-extending-protocols +RedirectTemp /13-39 https://numpy.org/devdocs/user/basics.types.html +RedirectTemp /13-40 https://github.com/python/typeshed/blob/master/stdlib/statistics.pyi +RedirectTemp /13-41 https://bugs.python.org/issue41974 +RedirectTemp /13-42 https://glyph.twistedmatrix.com/2020/07/new-duck.html +RedirectTemp /13-43 https://glyph.twistedmatrix.com/2021/03/interfaces-and-protocols.html +RedirectTemp /13-44 https://plone.org/ +RedirectTemp /13-45 https://trypyramid.com/ +RedirectTemp /13-46 https://twistedmatrix.com/trac/ +RedirectTemp /13-47 https://www.artima.com/articles/contracts-in-python +RedirectTemp /13-48 https://martinfowler.com/bliki/DynamicTyping.html +RedirectTemp /13-49 https://martinfowler.com/bliki/RoleInterface.html +RedirectTemp /13-50 https://mypy.readthedocs.io/en/stable/protocols.html +RedirectTemp /13-51 https://pymotw.com/3/abc/index.html +RedirectTemp /13-52 https://www.python.org/dev/peps/pep-3119/ +RedirectTemp /13-53 https://www.python.org/dev/peps/pep-3141/ +RedirectTemp /13-54 https://docs.python.org/3/library/numbers.html +RedirectTemp /13-55 https://github.com/python/mypy/issues/3186 +RedirectTemp /13-56 https://stackoverflow.com/questions/69334475/how-to-hint-at-number-types-i-e-subclasses-of-number-not-numbers-themselv/69383462#69383462 +RedirectTemp /13-57 https://github.com/python/mypy/issues/3186 +RedirectTemp /13-58 https://martinfowler.com/articles/lean-inception/ +RedirectTemp /13-59 https://martinfowler.com +RedirectTemp /13-60 https://www.jetbrains.com/pycharm/ +RedirectTemp /13-61 https://wingware.com/ +RedirectTemp /13-62 https://code.visualstudio.com/ +############################################################ 14 +RedirectTemp /14-1 http://worrydream.com/EarlyHistoryOfSmalltalk/ +RedirectTemp /14-2 https://docs.python.org/3/tutorial/classes.html +RedirectTemp /14-3 https://docs.python.org/3/library/collections.html#ordereddict-examples-and-recipes +RedirectTemp /14-4 https://discuss.python.org/t/is-it-time-to-deprecate-unbound-super-methods/1833 +RedirectTemp /14-5 https://doc.pypy.org/en/latest/cpython_differences.html#subclasses-of-built-in-types +RedirectTemp /14-6 https://docs.python.org/3/library/collections.html +RedirectTemp /14-7 https://github.com/fluentpython/example-code-2e/blob/master/14-inheritance/strkeydict_dictsub.py +RedirectTemp /14-8 https://doc.pypy.org/en/latest/cpython_differences.html#subclasses-of-built-in-types +RedirectTemp /14-9 https://en.wikipedia.org/wiki/Breadth-first_search +RedirectTemp /14-10 https://www.python.org/download/releases/2.3/mro/ +RedirectTemp /14-11 https://github.com/fluentpython/example-code-2e/blob/master/14-inheritance/uppermixin.py +RedirectTemp /14-12 https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html +RedirectTemp /14-13 https://docs.python.org/3/library/collections.abc.html +RedirectTemp /14-14 https://github.com/python/cpython/blob/8ece98a7e418c3c68a4c61bc47a2d0931b59a889/Lib/collections/__init__.py#L1084 +RedirectTemp /14-15 https://docs.python.org/3/library/http.server.html +RedirectTemp /14-16 https://github.com/python/cpython/blob/17c23167942498296f0bdfffe52e72d53d66d693/Lib/http/server.py#L144 +RedirectTemp /14-17 https://github.com/python/cpython/blob/699ee016af5736ffc80f68359617611a22b72943/Lib/socketserver.py#L664 +RedirectTemp /14-18 https://docs.python.org/3/library/socketserver.html#socketserver.ForkingMixIn +RedirectTemp /14-19 https://docs.python.org/3/library/os.html#os.fork +RedirectTemp /14-20 https://en.wikipedia.org/wiki/POSIX +RedirectTemp /14-21 http://ccbv.co.uk/ +RedirectTemp /14-22 https://github.com/django/django/tree/main/django/views/generic +RedirectTemp /14-23 https://en.wikipedia.org/wiki/Template_method_pattern +RedirectTemp /14-24 https://docs.python.org/3/library/tkinter.html +RedirectTemp /14-25 https://docs.python.org/3/library/tkinter.ttk.html +RedirectTemp /14-26 https://docs.oracle.com/javase/10/docs/api/java/awt/package-tree.html +RedirectTemp /14-27 https://docs.oracle.com/javase/10/docs/api/javax/swing/package-tree.html +RedirectTemp /14-28 https://squeak.org/ +RedirectTemp /14-29 https://github.com/django/django/blob/b64db05b9cedd96905d637a2d824cbbf428e40e7/django/views/generic/list.py#L194 +RedirectTemp /14-30 https://github.com/python/cpython/blob/8ed183391241f0c73e7ba7f42b1d49fc02985f7b/Lib/tkinter/__init__.py#L2618 +RedirectTemp /14-31 https://docs.python.org/3/library/socketserver.html +RedirectTemp /14-32 https://docs.python.org/3/library/socketserver.html#socketserver.BaseServer +RedirectTemp /14-33 https://github.com/python/cpython/blob/699ee016af5736ffc80f68359617611a22b72943/Lib/socketserver.py#L153 +RedirectTemp /14-34 https://docs.python.org/3/library/typing.html#typing.final +RedirectTemp /14-35 https://docs.python.org/3/library/typing.html#typing.Final +RedirectTemp /14-36 https://docs.python.org/3/library/collections.abc.html +RedirectTemp /14-37 https://hynek.me/articles/python-subclassing-redux/ +RedirectTemp /14-38 https://www.oreilly.com/library/view/python-cookbook-3rd/9781449357337/ch08.html#super +RedirectTemp /14-39 https://rhettinger.wordpress.com/2011/05/26/super-considered-super/ +RedirectTemp /14-40 https://fuhm.net/super-harmful/ +RedirectTemp /14-41 https://stackoverflow.com/questions/30190185/how-to-use-super-with-one-argument/30190341#30190341 +RedirectTemp /14-42 https://www.artima.com/weblogs/viewpost.jsp?thread=246488 +RedirectTemp /14-43 https://www.artima.com/weblogs/viewpost.jsp?thread=281127 +RedirectTemp /14-44 https://www.artima.com/weblogs/viewpost.jsp?thread=246341 +RedirectTemp /14-45 https://www.artima.com/weblogs/viewpost.jsp?thread=246483 +RedirectTemp /14-46 https://www.artima.com/weblogs/viewpost.jsp?thread=236275 +RedirectTemp /14-47 https://www.artima.com/weblogs/viewpost.jsp?thread=236278 +RedirectTemp /14-48 https://www.artima.com/weblogs/viewpost.jsp?thread=237121 +RedirectTemp /14-49 https://python-patterns.guide/gang-of-four/composition-over-inheritance/ +RedirectTemp /14-50 https://python-patterns.guide/ +RedirectTemp /14-51 https://www.youtube.com/watch?v=3MNVP9-hglc +RedirectTemp /14-52 http://worrydream.com/EarlyHistoryOfSmalltalk/ +RedirectTemp /14-53 https://en.wikipedia.org/wiki/Polymorphism_(computer_science) +############################################################ 15 +RedirectTemp /15-1 https://www.youtube.com/watch?v=csL8DLXGNlU&t=92m5s +RedirectTemp /15-2 https://github.com/python/typeshed/blob/a8834fcd46339e17fc8add82b5803a1ce53d3d60/stdlib/2and3/builtins.pyi#L1434 +RedirectTemp /15-3 https://github.com/python/typeshed/blob/a8834fcd46339e17fc8add82b5803a1ce53d3d60/stdlib/2and3/builtins.pyi +RedirectTemp /15-4 https://twitter.com/gwidion/status/1265384692464967680 +RedirectTemp /15-5 https://pypi.org/project/pydantic/ +RedirectTemp /15-6 https://google.github.io/pytype/faq.html +RedirectTemp /15-7 https://google.github.io/pytype/faq.html +RedirectTemp /15-8 https://lxml.de/ +RedirectTemp /15-9 https://docs.python.org/3/library/xml.etree.elementtree.html +RedirectTemp /15-10 https://mypy.readthedocs.io/en/stable/common_issues.html +RedirectTemp /15-11 https://mypy.readthedocs.io/en/stable/common_issues.html#types-of-empty-collections +RedirectTemp /15-12 https://github.com/python/typing/issues/182 +RedirectTemp /15-13 https://pypi.org/project/pydantic/ +RedirectTemp /15-14 https://mypy.readthedocs.io/en/stable/type_narrowing.html#casts +RedirectTemp /15-15 https://github.com/python/cpython/blob/bee66d3cb98e740f9d8057eb7f503122052ca5d8/Lib/typing.py#L1340 +RedirectTemp /15-16 https://www.python.org/dev/peps/pep-0484/#casts +RedirectTemp /15-17 https://github.com/python/typeshed/issues/5535 +RedirectTemp /15-18 https://docs.python.org/3/library/asyncio-stream.html#tcp-echo-server-using-streams +RedirectTemp /15-19 https://github.com/python/cpython/blob/b798ab06937f8bb24b444a49dd42e11fff15e654/Lib/test/test_asyncio/test_server.py#L55 +RedirectTemp /15-20 https://en.wikipedia.org/wiki/Code_smell +RedirectTemp /15-21 https://mail.python.org/archives/list/typing-sig@python.org/message/5LCWMN2UY2UQNLC5Z47GHBZKSPZW4I63/ +RedirectTemp /15-22 https://mypy.readthedocs.io/en/stable/error_codes.html#error-codes +RedirectTemp /15-23 https://github.com/fluentpython/example-code-2e/blob/master/15-more-types/clip_annot.py +RedirectTemp /15-24 https://docs.python.org/3/library/typing.html#introspection-helpers +RedirectTemp /15-25 https://docs.python.org/3.10/library/inspect.html#inspect.get_annotations +RedirectTemp /15-26 https://www.python.org/dev/peps/pep-0563/#abstract +RedirectTemp /15-27 https://mail.python.org/archives/list/python-dev@python.org/message/ZBJ7MD6CSGM6LZAOTET7GXAVBZB7O77O/ +RedirectTemp /15-28 https://docs.python.org/3.10/howto/annotations.html +RedirectTemp /15-29 https://docs.python.org/3/library/typing.html#user-defined-generic-types +RedirectTemp /15-30 https://github.com/python/typeshed/blob/bfc83c365a0b26ab16586beac77ff16729d0e473/stdlib/builtins.pyi#L743 +RedirectTemp /15-31 https://docs.python.org/3.10/library/typing.html#typing.FrozenSet +RedirectTemp /15-32 https://docs.python.org/3.10/library/typing.html#typing.Generator +RedirectTemp /15-33 https://docs.python.org/3.10/library/typing.html#typing.AsyncGenerator +RedirectTemp /15-34 https://github.com/python/cpython/blob/46b16d0bdbb1722daed10389e27226a2370f1635/Lib/typing.py#L1786 +RedirectTemp /15-35 https://github.com/python/typeshed/blob/2a9f081abbf01134e4e04ced6a750107db904d70/stdlib/builtins.pyi#L239 +RedirectTemp /15-36 https://www.oreilly.com/library/view/robust-python/9781098100650/ +RedirectTemp /15-37 https://www.python.org/dev/peps/pep-0484/#covariance-and-contravariance +RedirectTemp /15-38 https://mypy.readthedocs.io/en/stable/generics.html#variance-of-generic-types +RedirectTemp /15-39 https://mypy.readthedocs.io/en/stable/common_issues.html#variance +RedirectTemp /15-40 https://www.artima.com/weblogs/viewpost.jsp?thread=85551 +RedirectTemp /15-41 https://dl.acm.org/action/cookieAbsent +RedirectTemp /15-42 http://bracha.org/pluggableTypesPosition.pdf +RedirectTemp /15-43 https://www.researchgate.net/publication/213886116_Static_Typing_Where_Possible_Dynamic_Typing_When_Needed_The_End_of_the_Cold_War_Between_Programming_Languages +RedirectTemp /15-44 https://www.atomickotlin.com/atomickotlin/ +RedirectTemp /15-45 https://www.informit.com/store/effective-java-9780134685991 +RedirectTemp /15-46 https://www.manning.com/books/programming-with-types +RedirectTemp /15-47 https://www.oreilly.com/library/view/programming-typescript/9781492037644/ +RedirectTemp /15-48 https://www.informit.com/store/dart-programming-language-9780321927705 +RedirectTemp /15-49 https://www.yodaiken.com/2017/09/15/bad-ideas-in-type-theory/ +RedirectTemp /15-50 https://www.yodaiken.com/2017/11/30/types-considered-harmful-ii/ +RedirectTemp /15-51 https://web.archive.org/web/20071010002142/http://weblogs.java.net/blog/arnold/archive/2005/06/generics_consid_1.html +RedirectTemp /15-52 https://github.com/python/cpython/blob/3e7ee02327db13e4337374597cdc4458ecb9e3ad/Lib/asyncio/trsock.py#L5 +RedirectTemp /15-53 https://www.python.org/dev/peps/pep-0484/#covariance-and-contravariance +############################################################ 16 +RedirectTemp /16-1 http://www.gotw.ca/publications/c_family_interview.htm +RedirectTemp /16-2 https://docs.python.org/3/reference/expressions.html#unary-arithmetic-and-bitwise-operations +RedirectTemp /16-3 https://docs.python.org/3/reference/datamodel.html#object.__neg__ +RedirectTemp /16-4 https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#boolean-indexing +RedirectTemp /16-5 https://docs.python.org/3/library/collections.html#collections.Counter +RedirectTemp /16-6 https://docs.python.org/3/reference/datamodel.html#emulating-container-types +RedirectTemp /16-7 https://docs.python.org/3/library/numbers.html#implementing-the-arithmetic-operations +RedirectTemp /16-8 https://www.fluentpython.com/lingo/#fail-fast +RedirectTemp /16-9 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Objects/typeobject.c#L4598 +RedirectTemp /16-10 https://neopythonic.blogspot.com/2019/03/why-operators-are-useful.html +RedirectTemp /16-11 https://treyhunner.com/2019/03/python-deep-comparisons-and-code-readability/ +RedirectTemp /16-12 https://docs.python.org/3/library/numbers.html#implementing-the-arithmetic-operations +RedirectTemp /16-13 https://docs.python.org/3/library/pathlib.html +RedirectTemp /16-14 https://pypi.org/project/scapy/ +RedirectTemp /16-15 https://scapy.readthedocs.io/en/latest/usage.html#stacking-layers +RedirectTemp /16-16 https://docs.python.org/3/library/functools.html#functools.total_ordering +RedirectTemp /16-17 https://wiki.illinois.edu//wiki/download/attachments/273416327/ingalls.pdf +RedirectTemp /16-18 https://wiki.illinois.edu//wiki/download/attachments/273416327/double-dispatch.pdf +RedirectTemp /16-19 http://www.gotw.ca/publications/c_family_interview.htm +RedirectTemp /16-20 http://www.gotw.ca/publications/c_family_interview.htm +RedirectTemp /16-21 https://doc.rust-lang.org/std/ops/index.html +RedirectTemp /16-22 https://www.fluentpython.com/lingo/#lazy +############################################################ 17 +RedirectTemp /17-1 http://www.paulgraham.com/icad.html +RedirectTemp /17-2 https://en.wikipedia.org/wiki/Sentinel_value +RedirectTemp /17-3 https://docs.python.org/3.10/library/functions.html#iter +RedirectTemp /17-4 https://docs.python.org/3.10/library/functions.html#iter +RedirectTemp /17-5 https://github.com/python/cpython/blob/b1930bf75f276cd7ca08c4455298128d89adf7d1/Lib/_collections_abc.py#L271 +RedirectTemp /17-6 https://github.com/python/cpython/blob/main/Lib/types.py#L6 +RedirectTemp /17-7 https://en.wikipedia.org/wiki/CLU_(programming_language) +RedirectTemp /17-8 https://docs.python.org/3/glossary.html +RedirectTemp /17-9 https://docs.python.org/3/glossary.html#term-generator-iterator +RedirectTemp /17-10 https://docs.python.org/3/glossary.html#term-generator-expression +RedirectTemp /17-11 https://marc.info/?l=python-list&m=141826925106951&w=2 +RedirectTemp /17-12 https://docs.python.org/3/library/os.html#os.walk +RedirectTemp /17-13 https://docs.python.org/3/library/itertools.html +RedirectTemp /17-14 https://docs.python.org/3/library/exceptions.html#exception-hierarchy +RedirectTemp /17-15 https://en.wikipedia.org/wiki/Depth-first_search +RedirectTemp /17-16 https://docs.python.org/3.10/library/typing.html#typing.TypeAlias +RedirectTemp /17-17 https://docs.python.org/3/library/typing.html#typing.Generator +RedirectTemp /17-18 http://www.dabeaz.com/coroutines/Coroutines.pdf +RedirectTemp /17-19 http://www.dabeaz.com/coroutines/Coroutines.pdf +RedirectTemp /17-20 https://mail.python.org/pipermail/python-ideas/2009-April/003841.html +RedirectTemp /17-21 https://mail.python.org/pipermail/python-ideas/2009-April/003912.html +RedirectTemp /17-22 https://docs.python.org/3/library/exceptions.html#StopIteration +RedirectTemp /17-23 https://docs.python.org/3/reference/expressions.html#yield-expressions +RedirectTemp /17-24 https://docs.python.org/3/reference/index.html +RedirectTemp /17-25 https://github.com/python/cpython/blob/6f743e7a4da904f61dfa84cc7d7385e4dcc79ac5/Lib/typing.py#L2060 +RedirectTemp /17-26 http://catb.org/~esr/jargon/html/G/grok.html +RedirectTemp /17-27 https://docs.python.org/3/reference/expressions.html#yieldexpr +RedirectTemp /17-28 https://docs.python.org/3/library/itertools.html +RedirectTemp /17-29 https://docs.python.org/3/library/itertools.html#itertools-recipes +RedirectTemp /17-30 https://more-itertools.readthedocs.io/en/stable/index.html +RedirectTemp /17-31 https://rittau.org/2006/11/java-iterators-are-not-iterable/ +RedirectTemp /17-32 https://docs.python.org/3/whatsnew/3.3.html#pep-380-syntax-for-delegating-to-a-subgenerator +RedirectTemp /17-33 http://www.dabeaz.com/generators/ +RedirectTemp /17-34 http://www.dabeaz.com/coroutines/ +RedirectTemp /17-35 https://archive.org/details/pyvideo_213___pycon-2009-a-curious-course-on-coroutines-and-concurrency-part-1-of-3 +RedirectTemp /17-36 https://archive.org/details/pyvideo_215___pycon-2009-a-curious-course-on-coroutines-and-concurrency-part-2-of-3 +RedirectTemp /17-37 https://archive.org/details/pyvideo_214___pycon-2009-a-curious-course-on-coroutines-and-concurrency-part-3-of-3 +RedirectTemp /17-38 http://www.dabeaz.com/finalgenerator/ +RedirectTemp /17-39 https://web.archive.org/web/20200218150637/http://seriously.dontusethiscode.com/2013/05/01/greedy-coroutine.html +RedirectTemp /17-40 https://effectivepython.com/ +RedirectTemp /17-41 https://effectivepython.com/2015/03/10/consider-coroutines-to-run-many-functions-concurrently +RedirectTemp /17-42 https://en.wikipedia.org/wiki/Conway's_Game_of_Life +RedirectTemp /17-43 https://gist.github.com/ramalho/da5590bc38c973408839 +RedirectTemp /17-44 https://gist.github.com/ramalho/da5590bc38c973408839 +RedirectTemp /17-45 https://journal.code4lib.org/articles/4893 +RedirectTemp /17-46 https://github.com/fluentpython/isis2json +RedirectTemp /17-47 https://github.com/fluentpython/isis2json/blob/master/README.rst +############################################################ 18 +RedirectTemp /18-1 https://pyvideo.org/video/1669/keynote-3/ +RedirectTemp /18-2 https://docs.python.org/3/library/sqlite3.html#using-the-connection-as-a-context-manager +RedirectTemp /18-3 https://docs.python.org/3/library/threading.html#using-locks-conditions-and-semaphores-in-the-with-statement +RedirectTemp /18-4 https://docs.python.org/3/library/decimal.html#decimal.localcontext +RedirectTemp /18-5 https://docs.python.org/3/library/unittest.mock.html#patch +RedirectTemp /18-6 https://docs.python.org/3/library/contextlib.html#contextlib.redirect_stdout +RedirectTemp /18-7 https://docs.python.org/3/library/sys.html#sys.exc_info +RedirectTemp /18-8 https://en.wikipedia.org/wiki/LL_parser +RedirectTemp /18-9 https://docs.python.org/3/library/contextlib.html +RedirectTemp /18-10 https://github.com/python/cpython/blob/8afab2ebbc1b343cd88d058914cf622fe687a2be/Lib/contextlib.py#L123 +RedirectTemp /18-11 https://www.zopatista.com/python/2013/11/26/inplace-file-rewriting/ +RedirectTemp /18-12 https://docs.python.org/3/library/fileinput.html#fileinput.input +RedirectTemp /18-13 https://www.zopatista.com/python/2013/11/26/inplace-file-rewriting/ +RedirectTemp /18-14 https://en.wikipedia.org/wiki/Euclidean_algorithm +RedirectTemp /18-15 https://github.com/fluentpython/example-code-2e/tree/master/18-with-match/lispy/py3.10/ +RedirectTemp /18-16 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/original/lispy.py +RedirectTemp /18-17 https://github.com/fluentpython/example-code-2e/blob/6527037ae7319ba370a1ee2d9fe79214d0ed9452/18-with-match/lispy/py3.10/lis.py#L35 +RedirectTemp /18-18 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/py3.10/examples_test.py +RedirectTemp /18-19 https://github.com/python/typeshed/issues/6042 +RedirectTemp /18-20 https://github.com/fluentpython/lispy/tree/main/mylis +RedirectTemp /18-21 https://github.com/fluentpython/example-code-2e/blob/00e4741926e1b771ee7c753148b1415c0bd12e39/02-array-seq/lispy/py3.10/examples_test.py +RedirectTemp /18-22 https://mitpress.mit.edu/sites/default/files/sicp/index.html +RedirectTemp /18-23 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/py3.10/examples_test.py +RedirectTemp /18-24 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/py3.10/lis.py +RedirectTemp /18-25 https://www.python.org/dev/peps/pep-0634/#or-patterns +RedirectTemp /18-26 https://en.wikipedia.org/wiki/Lambda#Character_encodings +RedirectTemp /18-27 https://docs.python.org/3/reference/compound_stmts.html +RedirectTemp /18-28 https://docs.python.org/3/glossary.html#term-eafp +RedirectTemp /18-29 https://speakerdeck.com/pyconslides/pycon-keynote-python-is-awesome-by-raymond-hettinger?slide=21 +RedirectTemp /18-30 https://docs.python.org/3/reference/compound_stmts.html +RedirectTemp /18-31 https://stackoverflow.com/questions/16138232/is-it-a-good-practice-to-use-try-except-else-in-python +RedirectTemp /18-32 https://docs.python.org/3/library/stdtypes.html#typecontextmanager +RedirectTemp /18-33 https://docs.python.org/3/reference/datamodel.html#with-statement-context-managers +RedirectTemp /18-34 https://speakerdeck.com/pyconslides/pycon-keynote-python-is-awesome-by-raymond-hettinger?slide=21 +RedirectTemp /18-35 https://speakerdeck.com/pyconslides/transforming-code-into-beautiful-idiomatic-python-by-raymond-hettinger-1?slide=34 +RedirectTemp /18-36 https://preshing.com/20110920/the-python-with-statement-by-example/ +RedirectTemp /18-37 https://www.rath.org/on-the-beauty-of-pythons-exitstack.html +RedirectTemp /18-38 https://norvig.com/lispy.html +RedirectTemp /18-39 https://norvig.com/lispy2.html +RedirectTemp /18-40 https://github.com/norvig/pytudes +RedirectTemp /18-41 https://github.com/fluentpython/lispy +RedirectTemp /18-42 https://racket-lang.org/ +RedirectTemp /18-43 https://pyvideo.org/video/1669/keynote-3/ +RedirectTemp /18-44 https://en.wikipedia.org/wiki/Tail_call +RedirectTemp /18-45 https://2ality.com/2015/06/tail-call-optimization.html +RedirectTemp /18-46 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/original/lis.py +RedirectTemp /18-47 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/original/lispy.py +RedirectTemp /18-48 http://neopythonic.blogspot.com/2009/04/final-words-on-tail-calls.html +RedirectTemp /18-49 https://webkit.org/blog/6240/ecmascript-6-proper-tail-calls-in-webkit/ +RedirectTemp /18-50 http://kangax.github.io/compat-table/es6/ +RedirectTemp /18-51 https://world.hey.com/mgmarlow/what-happened-to-proper-tail-calls-in-javascript-5494c256 +RedirectTemp /18-52 http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html +RedirectTemp /18-53 https://github.com/fluentpython/lispy/blob/main/mylis/mylis_2/lis.py +RedirectTemp /18-54 https://github.com/fluentpython/lispy/tree/main/mylis +############################################################ 19 +RedirectTemp /19-1 https://go.dev/blog/waza-talk +RedirectTemp /19-2 https://en.wikipedia.org/wiki/Graphics_processing_unit +RedirectTemp /19-3 https://docs.python.org/3/library/sys.html#sys.getswitchinterval +RedirectTemp /19-4 https://docs.python.org/3/library/sys.html#sys.setswitchinterval +RedirectTemp /19-5 https://en.wikipedia.org/wiki/System_call +RedirectTemp /19-6 https://mail.python.org/pipermail/python-dev/2009-October/093356.html +RedirectTemp /19-7 http://www.dabeaz.com/finalgenerator/ +RedirectTemp /19-8 https://docs.python.org/3/library/threading.html#thread-objects +RedirectTemp /19-9 https://www.pypy.org/ +RedirectTemp /19-10 https://mail.python.org/pipermail/python-list/2009-February/675659.html +RedirectTemp /19-11 https://en.wikipedia.org/wiki/Braille_Patterns +RedirectTemp /19-12 https://docs.python.org/3/library/multiprocessing.shared_memory.html +RedirectTemp /19-13 https://docs.python.org/3/library/multiprocessing.shared_memory.html#multiprocessing.shared_memory.ShareableList +RedirectTemp /19-14 https://greenlet.readthedocs.io/en/latest/ +RedirectTemp /19-15 https://docs.sqlalchemy.org/en/14/changelog/migration_14.html#asynchronous-io-support-for-core-and-orm +RedirectTemp /19-16 https://docs.sqlalchemy.org/en/14/orm/extensions/asyncio.html +RedirectTemp /19-17 http://www.gevent.org/ +RedirectTemp /19-18 https://github.com/gevent/gevent/wiki/Projects +RedirectTemp /19-19 https://docs.python.org/3/library/concurrent.futures.html#processpoolexecutor-example +RedirectTemp /19-20 https://github.com/python/asyncio/issues/284 +RedirectTemp /19-21 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor +RedirectTemp /19-22 https://mail.python.org/archives/list/python-dev@python.org/message/JBYXQH3NV3YBF7P2HLHB5CD6V3GVTY55/ +RedirectTemp /19-23 https://docs.python.org/3/library/queue.html#queue.SimpleQueue.get +RedirectTemp /19-24 https://en.wikipedia.org/wiki/Race_condition +RedirectTemp /19-25 https://github.com/fluentpython/example-code-2e/commit/2c1230579db99738a5e5e6802063bda585f6476d +RedirectTemp /19-26 https://github.com/fluentpython/example-code-2e/blob/master/19-concurrency/primes/README.md +RedirectTemp /19-27 https://github.com/fluentpython/example-code-2e/blob/master/19-concurrency/primes/threads.py +RedirectTemp /19-28 https://en.wikipedia.org/wiki/Context_switch +RedirectTemp /19-29 http://www.gotw.ca/publications/concurrency-ddj.htm +RedirectTemp /19-30 https://www.ansible.com/ +RedirectTemp /19-31 https://saltproject.io/ +RedirectTemp /19-32 https://www.fabfile.org/ +RedirectTemp /19-33 https://engineering.fb.com/2016/05/27/production-engineering/python-in-production-engineering/ +RedirectTemp /19-34 https://jupyter.org/ +RedirectTemp /19-35 https://docs.bokeh.org/en/latest/index.html +RedirectTemp /19-36 https://www.tensorflow.org/ +RedirectTemp /19-37 https://pytorch.org/ +RedirectTemp /19-38 https://www.oreilly.com/radar/where-programming-ops-ai-and-the-cloud-are-headed-in-2021/ +RedirectTemp /19-39 https://www.youtube.com/watch?v=ods97a5Pzw0 +RedirectTemp /19-40 https://www.thoughtworks.com/radar/techniques/high-performance-envy-web-scale-envy +RedirectTemp /19-41 https://modwsgi.readthedocs.io/en/master/ +RedirectTemp /19-42 https://uwsgi-docs.readthedocs.io/en/latest/ +RedirectTemp /19-43 https://unit.nginx.org/ +RedirectTemp /19-44 https://www.techatbloomberg.com/blog/configuring-uwsgi-production-deployment/ +RedirectTemp /19-45 https://www.youtube.com/watch?v=p6R1h2Nn468 +RedirectTemp /19-46 https://asgi.readthedocs.io/en/latest/index.html +RedirectTemp /19-47 https://docs.celeryproject.org/en/stable/getting-started/introduction.html +RedirectTemp /19-48 https://python-rq.org/ +RedirectTemp /19-49 https://docs.celeryproject.org/en/stable/faq.html#what-kinds-of-things-should-i-use-celery-for +RedirectTemp /19-50 https://redis.io/ +RedirectTemp /19-51 https://realpython.com/intro-to-python-threading/ +RedirectTemp /19-52 https://pymotw.com/3/concurrency.html +RedirectTemp /19-53 https://www.pearson.com/us/higher-education/program/Hellmann-Python-3-Standard-Library-by-Example-The/PGM328871.html +RedirectTemp /19-54 https://docs.python.org/3/library/multiprocessing.html#programming-guidelines +RedirectTemp /19-55 https://docs.python.org/3/library/multiprocessing.html +RedirectTemp /19-56 https://www.oreilly.com/library/view/high-performance-python/9781492055013/ +RedirectTemp /19-57 https://link.springer.com/book/10.1007/978-1-4842-5793-7?error=cookies_not_supported&code=2ed5d61d-ae9f-4f3d-94ac-0f68cf45ea4f +RedirectTemp /19-58 https://www.packtpub.com/product/parallel-programming-with-python/9781783288397 +RedirectTemp /19-59 https://greenteapress.com/wp/semaphores/ +RedirectTemp /19-60 https://docs.python.org/3/c-api/init.html#thread-state-and-the-global-interpreter-lock +RedirectTemp /19-61 https://docs.python.org/3/faq/library.html#can-t-we-get-rid-of-the-global-interpreter-lock +RedirectTemp /19-62 https://www.artima.com/weblogs/viewpost.jsp?thread=214235 +RedirectTemp /19-63 http://jessenoller.com/blog/2009/02/01/python-threads-and-the-global-interpreter-lock +RedirectTemp /19-64 https://realpython.com/products/cpython-internals-book/ +RedirectTemp /19-65 http://www.dabeaz.com/GIL/ +RedirectTemp /19-66 http://www.dabeaz.com/python/UnderstandingGIL.pdf +RedirectTemp /19-67 https://bugs.python.org/issue7946#msg223110 +RedirectTemp /19-68 https://bugs.python.org/issue7946 +RedirectTemp /19-69 https://www.fullstackpython.com/ +RedirectTemp /19-70 https://www.oreilly.com/library/view/high-performance-python/9781492055013/ +RedirectTemp /19-71 https://www.packtpub.com/product/parallel-programming-with-python/9781783288397 +RedirectTemp /19-72 https://www.packtpub.com/product/distributed-computing-with-python/9781785889691 +RedirectTemp /19-73 https://towardsdatascience.com/python-performance-and-gpus-1be860ffd58d?gi=a7d537cc2fb4 +RedirectTemp /19-74 https://instagram-engineering.com/web-service-efficiency-at-instagram-with-python-4976d078e366?gi=12a441991c88 +RedirectTemp /19-75 https://www.oreilly.com/library/view/architecture-patterns-with/9781492052197/ +RedirectTemp /19-76 https://www.cosmicpython.com/ +RedirectTemp /19-77 https://pypi.org/project/lelo/ +RedirectTemp /19-78 https://github.com/npryce/python-parallelize +RedirectTemp /19-79 https://github.com/ericsnowcurrently/multi-core-python/wiki +RedirectTemp /19-80 https://gist.github.com/markshannon/79cace3656b40e21b7021504daee950c +RedirectTemp /19-81 https://mail.python.org/archives/list/python-dev@python.org/message/YOOQZCFOKEPQ24YHWWLQSJ3RCXFMS7D7/ +RedirectTemp /19-82 https://en.wikipedia.org/wiki/Communicating_sequential_processes +RedirectTemp /19-83 https://github.com/stackless-dev/stackless/wiki +RedirectTemp /19-84 https://www.eveonline.com +RedirectTemp /19-85 https://www.ccpgames.com/ +RedirectTemp /19-86 https://stackless.readthedocs.io/en/3.6-slp/stackless-python.html#history +RedirectTemp /19-87 https://doc.pypy.org/en/latest/stackless.html +RedirectTemp /19-88 https://greenlet.readthedocs.io/en/latest/ +RedirectTemp /19-89 http://www.gevent.org/ +RedirectTemp /19-90 http://thespianpy.com/doc/ +RedirectTemp /19-91 https://pykka.readthedocs.io/en/latest/ +RedirectTemp /19-92 https://www.manning.com/books/rabbitmq-in-action +RedirectTemp /19-93 https://pragprog.com/titles/pb7con/seven-concurrency-models-in-seven-weeks/ +RedirectTemp /19-94 https://en.wikipedia.org/wiki/OpenCL +RedirectTemp /19-95 https://media.pragprog.com/titles/pb7con/Bonus_Chapter.pdf +RedirectTemp /19-96 https://martinfowler.com/ +RedirectTemp /19-97 https://martinfowler.com/articles/patterns-of-distributed-systems/ +RedirectTemp /19-98 https://www.oreilly.com/library/view/designing-data-intensive-applications/9781491903063/ +RedirectTemp /19-99 https://www.oreilly.com/library/view/oscon-2016-video/9781491965153/video247021.html +RedirectTemp /19-100 https://www.oreilly.com/library/view/designing-for-scalability/9781449361556/ +RedirectTemp /19-101 https://www.thoughtworks.com/radar/techniques/high-performance-envy-web-scale-envy +RedirectTemp /19-102 https://en.wikipedia.org/wiki/KISS_principle +RedirectTemp /19-103 https://www.usenix.org/conference/hotos15/workshop-program/presentation/mcsherry +############################################################ 20 +RedirectTemp /20-1 https://www.artima.com/weblogs/viewpost.jsp?thread=299551 +RedirectTemp /20-2 https://docs.python.org/3/library/http.server.html +RedirectTemp /20-3 https://www.youtube.com/watch?v=A9e9Cy1UkME +RedirectTemp /20-4 https://www.cia.gov/the-world-factbook/ +RedirectTemp /20-5 https://docs.python-requests.org/en/latest/ +RedirectTemp /20-6 https://docs.python.org/3.10/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor +RedirectTemp /20-7 https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.as_completed +RedirectTemp /20-8 https://docs.python.org/3/library/concurrent.futures.html +RedirectTemp /20-9 https://docs.python.org/3.10/library/concurrent.futures.html#concurrent.futures.Executor +RedirectTemp /20-10 https://github.com/fluentpython/example-code-2e/blob/master/20-executors/getflags/flags2_common.py +RedirectTemp /20-11 https://github.com/noamraph/tqdm +RedirectTemp /20-12 https://www.youtube.com/watch?v=M8Z65tAl5l4 +RedirectTemp /20-13 https://github.com/noamraph/tqdm/blob/master/README.md +RedirectTemp /20-14 https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.as_completed +RedirectTemp /20-15 https://docs.python.org/3/library/asyncio-task.html#asyncio.as_completed +RedirectTemp /20-16 https://www.cloudflare.com/ +RedirectTemp /20-17 https://github.com/fluentpython/example-code-2e/tree/master/20-executors/getflags +RedirectTemp /20-18 https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/418 +RedirectTemp /20-19 https://en.wikipedia.org/wiki/Embarrassingly_parallel +RedirectTemp /20-20 https://pyvideo.org/video/480/pyconau-2010--the-future-is-soon/ +RedirectTemp /20-21 http://www.dabeaz.com/coroutines/ +RedirectTemp /20-22 https://en.wikipedia.org/wiki/POSIX_Threads +RedirectTemp /20-23 https://en.wikipedia.org/wiki/C_dynamic_memory_allocation +RedirectTemp /20-24 https://pragprog.com/titles/pb7con/seven-concurrency-models-in-seven-weeks/ +RedirectTemp /20-25 https://hexdocs.pm/ecto/getting-started.html +############################################################ 21 +RedirectTemp /21-1 https://docs.python.org/3/library/asyncio.html +RedirectTemp /21-2 https://bugs.python.org/issue43216 +RedirectTemp /21-3 https://bugs.python.org/issue36921 +RedirectTemp /21-4 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.getaddrinfo +RedirectTemp /21-5 https://docs.python.org/3/library/socket.html#socket.getaddrinfo +RedirectTemp /21-6 https://docs.python.org/3.10/library/asyncio-eventloop.html#asyncio.get_event_loop +RedirectTemp /21-7 https://www.python.org/dev/peps/pep-0492/#await-expression +RedirectTemp /21-8 https://www.fluentpython.com/extra/classic-coroutines/#yield_from_meaning_sec +RedirectTemp /21-9 https://github.com/fluentpython/example-code-2e/tree/master/20-executors/getflags +RedirectTemp /21-10 https://magicstack.github.io/asyncpg/current/ +RedirectTemp /21-11 https://magicstack.github.io/asyncpg/current/api/index.html#transactions +RedirectTemp /21-12 https://magicstack.github.io/asyncpg/current/api/index.html#transactions +RedirectTemp /21-13 https://github.com/MagicStack/asyncpg/blob/4d39a05268ce4cc01b00458223a767542da048b8/asyncpg/transaction.py#L57 +RedirectTemp /21-14 https://magicstack.github.io/asyncpg/current/usage.html#connection-pools +RedirectTemp /21-15 https://gist.github.com/jboner/2841832 +RedirectTemp /21-16 https://en.wikipedia.org/wiki/Network-attached_storage +RedirectTemp /21-17 https://en.wikipedia.org/wiki/Semaphore_(programming) +RedirectTemp /21-18 https://en.wikipedia.org/wiki/Semaphore_(programming) +RedirectTemp /21-19 https://groups.google.com/forum/#!msg/python-tulip/PdAEtwpaJHs/7fqb-Qj2zJoJ +RedirectTemp /21-20 https://web.archive.org/web/20151209151711/http://tritarget.org/blog/2012/11/28/the-pyramid-of-doom-a-javascript-style-trap +RedirectTemp /21-21 https://stackoverflow.com/questions/53701841/what-is-the-use-case-for-future-add-done-callback/53710563 +RedirectTemp /21-22 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor +RedirectTemp /21-23 https://motor.readthedocs.io/en/stable/ +RedirectTemp /21-24 https://emptysqua.re/blog/response-to-asynchronous-python-and-databases/ +RedirectTemp /21-25 https://docs.python.org/3/library/asyncio-stream.html#tcp-echo-server-using-streams +RedirectTemp /21-26 https://en.wikipedia.org/wiki/Phaistos_Disc +RedirectTemp /21-27 https://en.wikipedia.org/wiki/Inverted_index +RedirectTemp /21-28 https://fastapi.tiangolo.com/ +RedirectTemp /21-29 https://swagger.io/specification/ +RedirectTemp /21-30 https://asgi.readthedocs.io/en/latest/implementations.html +RedirectTemp /21-31 https://pydantic-docs.helpmanual.io/ +RedirectTemp /21-32 https://doc.traefik.io/traefik/ +RedirectTemp /21-33 https://fastapi.tiangolo.com/project-generation/ +RedirectTemp /21-34 https://fastapi.tiangolo.com/tutorial/response-model/ +RedirectTemp /21-35 https://docs.python.org/3/library/asyncio-stream.html#asyncio.start_server +RedirectTemp /21-36 https://github.com/python/typeshed/issues/5535 +RedirectTemp /21-37 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.Server.serve_forever +RedirectTemp /21-38 https://docs.python.org/3/library/asyncio-stream.html#asyncio.StreamWriter.close +RedirectTemp /21-39 https://docs.python.org/3/library/asyncio-stream.html#streamwriter +RedirectTemp /21-40 https://docs.python.org/3/library/asyncio-stream.html +RedirectTemp /21-41 https://docs.python.org/3/library/asyncio-protocol.html +RedirectTemp /21-42 https://docs.python.org/3/library/asyncio-protocol.html#tcp-echo-server +RedirectTemp /21-43 https://github.com/aio-libs/aiopg +RedirectTemp /21-44 https://docs.python.org/3/whatsnew/3.8.html#asyncio +RedirectTemp /21-45 https://datatracker.ietf.org/doc/html/rfc6761 +RedirectTemp /21-46 https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager +RedirectTemp /21-47 https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager +RedirectTemp /21-48 https://docs.python.org/3/library/asyncio-task.html#asyncio.gather +RedirectTemp /21-49 https://curio.readthedocs.io/en/latest/index.html +RedirectTemp /21-50 https://curio.readthedocs.io/en/latest/reference.html#task-groups +RedirectTemp /21-51 https://en.wikipedia.org/wiki/Structured_concurrency +RedirectTemp /21-52 https://mail.python.org/archives/list/python-dev@python.org/thread/2ORDAW74LGE3ZI2QETPJRT2ZL7MCCPG2/ +RedirectTemp /21-53 https://www.python.org/dev/peps/pep-0654/#motivation +RedirectTemp /21-54 https://curio.readthedocs.io/en/latest/reference.html#AWAIT +RedirectTemp /21-55 https://www.python-httpx.org/async/#curio +RedirectTemp /21-56 https://github.com/dabeaz/curio/tree/78bca8a6ad677ef51e1568ac7b3e51441ab49c42/examples +RedirectTemp /21-57 https://datatracker.ietf.org/doc/html/rfc8305 +RedirectTemp /21-58 https://trio.readthedocs.io/en/stable/ +RedirectTemp /21-59 https://www.youtube.com/watch?v=M-sc73Y-zQA +RedirectTemp /21-60 https://en.wikipedia.org/wiki/Technical_debt +RedirectTemp /21-61 https://www.youtube.com/watch?v=E-1Y4kSsAFc +RedirectTemp /21-62 https://github.com/dabeaz/curio +RedirectTemp /21-63 https://trio.readthedocs.io/en/stable/ +RedirectTemp /21-64 https://curio.readthedocs.io/en/latest/#curio-university +RedirectTemp /21-65 https://vorpus.org/blog/some-thoughts-on-asynchronous-api-design-in-a-post-asyncawait-world/ +RedirectTemp /21-66 https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/ +RedirectTemp /21-67 https://stackoverflow.com/questions/49482969/what-is-the-core-difference-between-asyncio-and-trio +RedirectTemp /21-68 https://docs.python.org/3/library/asyncio.html +RedirectTemp /21-69 https://bugs.python.org/issue33649 +RedirectTemp /21-70 https://docs.python.org/3/library/asyncio-dev.html +RedirectTemp /21-71 https://www.youtube.com/watch?v=iG6fr81xHKA +RedirectTemp /21-72 https://www.youtube.com/watch?v=F19R_M4Nay4 +RedirectTemp /21-73 https://asherman.io/projects/unsync.html +RedirectTemp /21-74 https://pyladies.com/ +RedirectTemp /21-75 https://www.youtube.com/watch?v=sW76-pRkZk8 +RedirectTemp /21-76 https://www.youtube.com/watch?v=Xbl7XjFYsN4 +RedirectTemp /21-77 https://www.youtube.com/watch?v=02CLD-42VdI +RedirectTemp /21-78 https://micropython.org/ +RedirectTemp /21-79 https://docs.micropython.org/en/latest/library/uasyncio.html +RedirectTemp /21-80 https://www.encode.io/articles/python-async-frameworks-beyond-developer-tribalism +RedirectTemp /21-81 https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/ +RedirectTemp /21-82 https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/ +RedirectTemp /21-83 https://github.com/MagicStack/uvloop +RedirectTemp /21-84 http://magic.io/blog/uvloop-blazing-fast-python-networking/ +RedirectTemp /21-85 https://github.com/MagicStack/httptools +RedirectTemp /21-86 https://docs.aiohttp.org/en/stable/ +RedirectTemp /21-87 https://github.com/wg/wrk +RedirectTemp /21-88 https://twistedmatrix.com/trac/ +############################################################ 22 +RedirectTemp /22-1 https://github.com/fluentpython/example-code-2e/blob/master/22-dyn-attr-prop/oscon/data/osconfeed.json +RedirectTemp /22-2 https://pypi.org/project/attrdict/ +RedirectTemp /22-3 https://pypi.org/project/addict/ +RedirectTemp /22-4 https://github.com/ActiveState/code/tree/master/recipes/Python/52308_simple_but_handy_collector_bunch_named_stuff +RedirectTemp /22-5 https://docs.python.org/3/library/types.html#types.SimpleNamespace +RedirectTemp /22-6 https://docs.python.org/3/library/argparse.html#argparse.Namespace +RedirectTemp /22-7 https://docs.python.org/3/library/multiprocessing.html#multiprocessing.managers.Namespace +RedirectTemp /22-8 https://github.com/fluentpython/example-code-2e/blob/master/22-dyn-attr-prop/oscon/schedule_v2.py +RedirectTemp /22-9 https://docs.python.org/3/library/functools.html#functools.cached_property +RedirectTemp /22-10 https://docs.python.org/3/library/functools.html#functools.cached_property +RedirectTemp /22-11 https://bugs.python.org/issue42781 +RedirectTemp /22-12 https://docs.python.org/3/howto/descriptor.html +RedirectTemp /22-13 https://github.com/python/cpython/blob/e6d0107e13ed957109e79b796984d3d026a8660d/Lib/functools.py#L926 +RedirectTemp /22-14 https://docs.python.org/3/library/threading.html#rlock-objects +RedirectTemp /22-15 https://docs.python.org/3.10/library/functools.html#functools.cached_property +RedirectTemp /22-16 https://www.wsj.com/articles/SB10001424052970203914304576627102996831200 +RedirectTemp /22-17 https://www.youtube.com/watch?v=s35rVw1zskA&feature=youtu.be +RedirectTemp /22-18 https://docs.python.org/3/library/functions.html#dir +RedirectTemp /22-19 https://github.com/python/cpython/blob/19903085c3ad7a17c8047e1556c700f2eb109931/Lib/cmd.py#L214 +RedirectTemp /22-20 https://docs.python.org/3/library/functions.html#hasattr +RedirectTemp /22-21 https://docs.python.org/3.10/reference/datamodel.html#special-method-lookup +RedirectTemp /22-22 https://docs.python.org/3/library/functions.html +RedirectTemp /22-23 https://docs.python.org/3/reference/datamodel.html#customizing-attribute-access +RedirectTemp /22-24 https://docs.python.org/3/reference/datamodel.html#special-method-lookup +RedirectTemp /22-25 https://docs.python.org/3/library/stdtypes.html#special-attributes +RedirectTemp /22-26 http://wiki.c2.com/?WelcomeVisitors +RedirectTemp /22-27 http://wiki.c2.com/?UniformAccessPrinciple +RedirectTemp /22-28 https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html +RedirectTemp /22-29 http://www.pingo.io/docs/ +RedirectTemp /22-30 https://www.drdobbs.com/javas-new-considered-harmful/184405016 +RedirectTemp /22-31 https://www.python.org/dev/peps/pep-0008/#class-names +############################################################ 23 +RedirectTemp /23-1 http://www.aleax.it/goo_pydp.pdf +RedirectTemp /23-2 https://docs.python.org/3.10/reference/datamodel.html#implementing-descriptors +RedirectTemp /23-3 https://docs.python.org/3/howto/descriptor.html +RedirectTemp /23-4 https://docs.python.org/3/howto/ +RedirectTemp /23-5 http://www.aleax.it/Python/nylug05_om.pdf +RedirectTemp /23-6 https://www.youtube.com/watch?v=VOzvpHoYQoo +RedirectTemp /23-7 https://www.python.org/dev/peps/pep-0487/#trait-descriptors +RedirectTemp /23-8 https://dreamsongs.com/RiseOfWorseIsBetter.html +RedirectTemp /23-9 http://web.archive.org/web/20031002184114/www.amk.ca/python/writing/warts.html +RedirectTemp /23-10 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this +RedirectTemp /23-11 http://python-history.blogspot.com/2009/02/adding-support-for-user-defined-classes.html +############################################################ 24 +RedirectTemp /24-1 https://docs.python.org/3/library/stdtypes.html#special-attributes +RedirectTemp /24-2 https://docs.djangoproject.com/en/3.2/topics/db/models/#meta-options +RedirectTemp /24-3 https://www.python.org/dev/peps/pep-3155/ +RedirectTemp /24-4 https://github.com/python/cpython/blob/3.9/Lib/collections/__init__.py +RedirectTemp /24-5 https://en.wikipedia.org/wiki/Tony_Hoare#Apologies_and_retractions +RedirectTemp /24-6 https://go.dev/tour/basics/12 +RedirectTemp /24-7 https://bugs.python.org/issue42102 +RedirectTemp /24-8 https://docs.python.org/3/reference/datamodel.html#object.__init_subclass__ +RedirectTemp /24-9 https://www.python.org/dev/peps/pep-0557/#abstract +RedirectTemp /24-10 https://github.com/python/cpython/blob/3.9/Lib/dataclasses.py +RedirectTemp /24-11 https://docs.python.org/3/reference/datamodel.html#creating-the-class-object +RedirectTemp /24-12 https://mail.python.org/pipermail/python-list/2002-December/134521.html +RedirectTemp /24-13 https://mail.python.org/pipermail/python-list/2002-July/162558.html +RedirectTemp /24-14 https://github.com/fluentpython/example-code/tree/master/21-class-metaprog/bulkfood +RedirectTemp /24-15 https://en.wikipedia.org/wiki/Principle_of_least_astonishment +RedirectTemp /24-16 https://docs.python.org/3/reference/datamodel.html#object.__class_getitem__ +RedirectTemp /24-17 https://en.wikipedia.org/wiki/Trait_(computer_programming) +RedirectTemp /24-18 https://en.wikipedia.org/wiki/Aspect-oriented_programming +RedirectTemp /24-19 https://dhh.dk/arc/000416.html +RedirectTemp /24-20 https://github.com/cjrh/autoslot +RedirectTemp /24-21 https://docs.python.org/3/reference/datamodel.html#customizing-class-creation +RedirectTemp /24-22 https://docs.python.org/3/library/functions.html#type +RedirectTemp /24-23 https://docs.python.org/3/library/stdtypes.html#special-attributes +RedirectTemp /24-24 https://docs.python.org/3/library/types.html +RedirectTemp /24-25 https://www.python.org/dev/peps/pep-3129/ +RedirectTemp /24-26 https://www.youtube.com/watch?v=cAGliEJV9_o +RedirectTemp /24-27 https://docs.python.org/3/library/functools.html#functools.total_ordering +RedirectTemp /24-28 https://www.python.org/download/releases/2.2.3/descrintro/ +RedirectTemp /24-29 https://github.com/lihaoyi/macropy +RedirectTemp /24-30 https://people.eecs.berkeley.edu/~bh/ss-toc2.html diff --git a/links/short.htaccess b/links/short.htaccess new file mode 100644 index 0000000..fbe7ddf --- /dev/null +++ b/links/short.htaccess @@ -0,0 +1 @@ +# file created and managed by short.py diff --git a/links/short.py b/links/short.py new file mode 100755 index 0000000..a9ae96c --- /dev/null +++ b/links/short.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 + +import itertools +from collections.abc import Iterator + + +def load_redirects(): + redirects = {} + targets = {} + for filename in ('custom.htaccess', 'short.htaccess'): + with open(filename) as fp: + for line in fp: + if line.startswith('RedirectTemp'): + _, short, long = line.split() + short = short[1:] # Remove leading slash + assert short not in redirects, f"{filename}: duplicate redirect from {short}" + # custom is live since 2022, we cannot change it remove duplicate targets + if not filename.startswith('custom'): + assert long not in targets, f"{filename}: Duplicate redirect to {long}" + redirects[short] = long + targets[long] = short + return redirects, targets + + +SDIGITS = '23456789abcdefghjkmnpqrstvwxyz' + + +def gen_short() -> Iterator[str]: + """ + Generate every possible sequence of SDIGITS. + """ + length = 1 + while True: + for short in itertools.product(SDIGITS, repeat=length): + yield ''.join(short) + length += 1 + + +def shorten(n: int) -> str: + """ + Get Nth short URL made from SDIGITS, where 0 is the first. + """ + iter_short = gen_short() + for i in range(n+1): + short = next(iter_short) + if i == n: + return short + + +def gen_free_short(redirects: dict) -> Iterator[str]: + """ + Generate next available short URL. + """ + for short in gen_short(): + if short not in redirects: + yield short + + +def new_urls(urls: list[str], redirects: dict, targets: dict) -> None: + iter_short = gen_free_short(redirects) + with open('short.htaccess', 'a') as fp: + for url in urls: + assert 'fpy.li' not in url, f"{url} is a fpy.li URL" + if url in targets: + continue + short = next(iter_short) + redirects[short] = url + targets[url] = short + fp.write(f"RedirectTemp /{short} {url}\n") + + +def main(): + from random import randrange + urls = [f'https://example.com/{randrange(100000)}.html' for n in range(7)] + + redirects, targets = load_redirects() + new_urls(urls, redirects, targets) + + +if __name__ == '__main__': + main() From c5490b1569c9d4d4d52f0834a5f29b81bf657529 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 22 May 2025 04:13:41 +0000 Subject: [PATCH 59/66] build(deps): bump h11 from 0.12.0 to 0.16.0 in /21-async/mojifinder Bumps [h11](https://github.com/python-hyper/h11) from 0.12.0 to 0.16.0. - [Commits](https://github.com/python-hyper/h11/compare/v0.12.0...v0.16.0) --- updated-dependencies: - dependency-name: h11 dependency-version: 0.16.0 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- 21-async/mojifinder/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/21-async/mojifinder/requirements.txt b/21-async/mojifinder/requirements.txt index f7de911..6831fee 100644 --- a/21-async/mojifinder/requirements.txt +++ b/21-async/mojifinder/requirements.txt @@ -1,6 +1,6 @@ click==7.1.2 fastapi==0.65.2 -h11==0.12.0 +h11==0.16.0 pydantic==1.10.13 starlette==0.40.0 typing-extensions==3.7.4.3 From cc4e26c67a4fbe7a84094b7d1c6fffe3fddc1f45 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Thu, 22 May 2025 02:18:34 -0300 Subject: [PATCH 60/66] Remove redundant if from short.py --- links/short.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/links/short.py b/links/short.py index a9ae96c..0e95b55 100755 --- a/links/short.py +++ b/links/short.py @@ -41,10 +41,9 @@ def shorten(n: int) -> str: Get Nth short URL made from SDIGITS, where 0 is the first. """ iter_short = gen_short() - for i in range(n+1): + for _ in range(n+1): short = next(iter_short) - if i == n: - return short + return short def gen_free_short(redirects: dict) -> Iterator[str]: From 648e9f6394c753730f48587ce70e0c5d0cffdf92 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Thu, 22 May 2025 10:05:54 -0300 Subject: [PATCH 61/66] Update short.py to return list of URL substitutions --- links/short.py | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/links/short.py b/links/short.py index 0e95b55..89464a3 100755 --- a/links/short.py +++ b/links/short.py @@ -36,16 +36,6 @@ def gen_short() -> Iterator[str]: length += 1 -def shorten(n: int) -> str: - """ - Get Nth short URL made from SDIGITS, where 0 is the first. - """ - iter_short = gen_short() - for _ in range(n+1): - short = next(iter_short) - return short - - def gen_free_short(redirects: dict) -> Iterator[str]: """ Generate next available short URL. @@ -55,17 +45,23 @@ def gen_free_short(redirects: dict) -> Iterator[str]: yield short -def new_urls(urls: list[str], redirects: dict, targets: dict) -> None: +def shorten(urls: list[str], redirects: dict, targets: dict) -> list[tuple[str,str]]: + """return (short, long) pairs, updating short.htaccess as needed""' iter_short = gen_free_short(redirects) + pairs = [] with open('short.htaccess', 'a') as fp: - for url in urls: - assert 'fpy.li' not in url, f"{url} is a fpy.li URL" - if url in targets: - continue - short = next(iter_short) - redirects[short] = url - targets[url] = short - fp.write(f"RedirectTemp /{short} {url}\n") + for long in urls: + assert 'fpy.li' not in long, f"{long} is a fpy.li URL" + if long in targets: + short = targets[long] + else: + short = next(iter_short) + redirects[short] = url + targets[url] = short + fp.write(f"RedirectTemp /{short} {url}\n") + pairs.append((short, long)) + + return pairs def main(): @@ -73,7 +69,8 @@ def main(): urls = [f'https://example.com/{randrange(100000)}.html' for n in range(7)] redirects, targets = load_redirects() - new_urls(urls, redirects, targets) + for short, long in shorten(urls, redirects, targets): + print(f'fpy.li/{short}\t{long}') if __name__ == '__main__': From 5b743b5bd7040cd5c29bf2fa4804dc734ba010bd Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Thu, 22 May 2025 13:24:50 -0300 Subject: [PATCH 62/66] short.py now reads files and stdin --- links/sample-urls.txt | 47 ++++++++++++++++++++++++++++++++++++++++ links/short.htaccess | 2 +- links/short.py | 50 +++++++++++++++++++++++++++++-------------- 3 files changed, 82 insertions(+), 17 deletions(-) create mode 100644 links/sample-urls.txt diff --git a/links/sample-urls.txt b/links/sample-urls.txt new file mode 100644 index 0000000..9eac47c --- /dev/null +++ b/links/sample-urls.txt @@ -0,0 +1,47 @@ +https://www.oreilly.com/library/view/fluent-python-2nd/9781492056348/ +https://dask.org/ +http://example.com/1572039572038573208 +http://www.unicode.org/ +https://www.techcrunch.com/2024/startup-funding-trends +https://blog.medium.com/writing-tips-for-beginners +https://github.com/microsoft/typescript +https://stackoverflow.com/questions/javascript-async-await +https://www.reddit.com/r/programming/hot +https://docs.google.com/spreadsheets/create +https://www.youtube.com/watch?v=dQw4w9WgXcQ +https://www.amazon.com/dp/B08N5WRWNW +https://support.apple.com/iphone-setup-guide +https://www.wikipedia.org/wiki/Machine_Learning +https://www.linkedin.com/in/johndoe123 +https://www.instagram.com/p/CxYz123AbC/ +https://twitter.com/elonmusk/status/1234567890 +https://www.facebook.com/events/987654321 +https://drive.google.com/file/d/1AbCdEfGhIjKlMnOp/view +https://www.dropbox.com/s/qwerty123/document.pdf +https://zoom.us/j/1234567890?pwd=abcdef +https://calendly.com/janedoe/30min-meeting +https://www.shopify.com/admin/products/new +https://stripe.com/docs/api/charges/create +https://www.paypal.com/invoice/create +https://mailchimp.com/campaigns/dashboard +https://analytics.google.com/analytics/web/ +https://console.aws.amazon.com/s3/buckets +https://portal.azure.com/dashboard +https://www.figma.com/file/AbCdEf123456/design-system +https://www.notion.so/workspace/project-notes +https://trello.com/b/AbCdEfGh/marketing-board +https://slack.com/app_redirect?channel=general +https://discord.gg/AbCdEfGh123 +https://www.twitch.tv/streamername/videos +https://www.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M +https://www.netflix.com/browse/genre/83 +https://www.hulu.com/series/breaking-bad-2008 +https://www.airbnb.com/rooms/12345678 +https://www.booking.com/hotel/us/grand-plaza.html +https://www.expedia.com/flights/search?trip=roundtrip +https://www.uber.com/ride/request +https://www.doordash.com/store/pizza-palace-123 +https://www.grubhub.com/restaurant/tacos-el-rey-456 +https://www.zillow.com/homes/for_sale/San-Francisco-CA +https://www.craigslist.org/about/sites +https://www.python.org/dev/peps/pep-0484/ \ No newline at end of file diff --git a/links/short.htaccess b/links/short.htaccess index fbe7ddf..6b09a50 100644 --- a/links/short.htaccess +++ b/links/short.htaccess @@ -1 +1 @@ -# file created and managed by short.py +# content of short.htaccess file created and managed by short.py diff --git a/links/short.py b/links/short.py index 89464a3..a1b6664 100755 --- a/links/short.py +++ b/links/short.py @@ -1,8 +1,23 @@ #!/usr/bin/env python3 +""" +short.py generates unique short URLs. + +This script reads lines from stdin or files named as arguments, then: + +1. retrieves or creates new short URLs, taking into account existing RedirectTemp + directives in custom.htacess or short.htacess; +2. appends RedirectTemp directives for newly created short URLs to short.htacess; +3. outputs the list of (short, long) URLs retrieved or created. + +""" + +import fileinput import itertools from collections.abc import Iterator +from time import strftime +BASE_DOMAIN = 'fpy.li' def load_redirects(): redirects = {} @@ -25,52 +40,55 @@ def load_redirects(): SDIGITS = '23456789abcdefghjkmnpqrstvwxyz' -def gen_short() -> Iterator[str]: +def gen_short(start_len=1) -> Iterator[str]: """ - Generate every possible sequence of SDIGITS. + Generate every possible sequence of SDIGITS, starting with start_len """ - length = 1 + length = start_len while True: for short in itertools.product(SDIGITS, repeat=length): yield ''.join(short) length += 1 -def gen_free_short(redirects: dict) -> Iterator[str]: +def gen_unused_short(redirects: dict) -> Iterator[str]: """ - Generate next available short URL. + Generate next available short URL of len >= 2. """ - for short in gen_short(): + for short in gen_short(2): if short not in redirects: yield short def shorten(urls: list[str], redirects: dict, targets: dict) -> list[tuple[str,str]]: - """return (short, long) pairs, updating short.htaccess as needed""' - iter_short = gen_free_short(redirects) + """return (short, long) pairs, appending directives to short.htaccess as needed""" + iter_short = gen_unused_short(redirects) pairs = [] + timestamp = strftime('%Y-%m-%d %H:%M:%S') with open('short.htaccess', 'a') as fp: for long in urls: - assert 'fpy.li' not in long, f"{long} is a fpy.li URL" + assert BASE_DOMAIN not in long, f"{long} is a {BASE_DOMAIN} URL" if long in targets: short = targets[long] else: short = next(iter_short) - redirects[short] = url - targets[url] = short - fp.write(f"RedirectTemp /{short} {url}\n") + redirects[short] = long + targets[long] = short + if timestamp: + fp.write(f'\n# appended: {timestamp}\n') + timestamp = None + fp.write(f'RedirectTemp /{short} {long}\n') pairs.append((short, long)) return pairs def main(): - from random import randrange - urls = [f'https://example.com/{randrange(100000)}.html' for n in range(7)] - + """read URLS from filename arguments or stdin""" + urls = [line.strip() for line in fileinput.input(encoding="utf-8")] redirects, targets = load_redirects() for short, long in shorten(urls, redirects, targets): - print(f'fpy.li/{short}\t{long}') + print(f'{BASE_DOMAIN}/{short}\t{long}') if __name__ == '__main__': From ec03da74cac0899c1f6572a8d9ed880b358494af Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Thu, 22 May 2025 13:44:46 -0300 Subject: [PATCH 63/66] short.py appends timestamps to short.htaccesss --- links/short.py | 44 ++++++++++++++++++++++---------------------- ruff.toml | 4 ++++ 2 files changed, 26 insertions(+), 22 deletions(-) create mode 100644 ruff.toml diff --git a/links/short.py b/links/short.py index a1b6664..1ebd0bd 100755 --- a/links/short.py +++ b/links/short.py @@ -6,8 +6,8 @@ This script reads lines from stdin or files named as arguments, then: 1. retrieves or creates new short URLs, taking into account existing RedirectTemp - directives in custom.htacess or short.htacess; -2. appends RedirectTemp directives for newly created short URLs to short.htacess; + directives in custom.htaccess or short.htaccess; +2. appends RedirectTemp directives for newly created short URLs to short.htaccess; 3. outputs the list of (short, long) URLs retrieved or created. """ @@ -17,21 +17,25 @@ from collections.abc import Iterator from time import strftime +HTACCESS_CUSTOM = 'custom.htaccess' +HTACCESS_SHORT = 'short.htaccess' +HTACCESS_FILES = (HTACCESS_CUSTOM, HTACCESS_SHORT) BASE_DOMAIN = 'fpy.li' -def load_redirects(): + +def load_redirects() -> tuple[dict, dict]: redirects = {} targets = {} - for filename in ('custom.htaccess', 'short.htaccess'): + for filename in HTACCESS_FILES: with open(filename) as fp: for line in fp: if line.startswith('RedirectTemp'): _, short, long = line.split() short = short[1:] # Remove leading slash - assert short not in redirects, f"{filename}: duplicate redirect from {short}" - # custom is live since 2022, we cannot change it remove duplicate targets - if not filename.startswith('custom'): - assert long not in targets, f"{filename}: Duplicate redirect to {long}" + assert short not in redirects, f'{filename}: duplicate redirect from {short}' + # htaccess.custom is live since 2022, we can't change it remove duplicate targets + if filename != HTACCESS_CUSTOM: + assert long not in targets, f'{filename}: duplicate redirect to {long}' redirects[short] = long targets[long] = short return redirects, targets @@ -41,9 +45,7 @@ def load_redirects(): def gen_short(start_len=1) -> Iterator[str]: - """ - Generate every possible sequence of SDIGITS, starting with start_len - """ + """Generate every possible sequence of SDIGITS, starting with start_len""" length = start_len while True: for short in itertools.product(SDIGITS, repeat=length): @@ -52,22 +54,20 @@ def gen_short(start_len=1) -> Iterator[str]: def gen_unused_short(redirects: dict) -> Iterator[str]: - """ - Generate next available short URL of len >= 2. - """ + """Generate next available short URL of len >= 2.""" for short in gen_short(2): if short not in redirects: yield short -def shorten(urls: list[str], redirects: dict, targets: dict) -> list[tuple[str,str]]: - """return (short, long) pairs, appending directives to short.htaccess as needed""" +def shorten(urls: list[str], redirects: dict, targets: dict) -> list[tuple[str, str]]: + """Return (short, long) pairs, appending directives to HTACCESS_SHORT as needed.""" iter_short = gen_unused_short(redirects) pairs = [] timestamp = strftime('%Y-%m-%d %H:%M:%S') - with open('short.htaccess', 'a') as fp: + with open(HTACCESS_SHORT, 'a') as fp: for long in urls: - assert BASE_DOMAIN not in long, f"{long} is a {BASE_DOMAIN} URL" + assert BASE_DOMAIN not in long, f'{long} is a {BASE_DOMAIN} URL' if long in targets: short = targets[long] else: @@ -79,16 +79,16 @@ def shorten(urls: list[str], redirects: dict, targets: dict) -> list[tuple[str,s timestamp = None fp.write(f'RedirectTemp /{short} {long}\n') pairs.append((short, long)) - + return pairs -def main(): +def main() -> None: """read URLS from filename arguments or stdin""" - urls = [line.strip() for line in fileinput.input(encoding="utf-8")] + urls = [line.strip() for line in fileinput.input(encoding='utf-8')] redirects, targets = load_redirects() for short, long in shorten(urls, redirects, targets): - print(f'{BASE_DOMAIN}/{short}\t{long}') + print(f'{BASE_DOMAIN}/{short}\t{long}') if __name__ == '__main__': diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 0000000..f7b07e2 --- /dev/null +++ b/ruff.toml @@ -0,0 +1,4 @@ +line-length = 100 +[format] +# Like Python's repr(), use single quotes for strings. +quote-style = "single" \ No newline at end of file From cf996500070e0d712a3b088d29428f74ddc9fa1f Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Thu, 22 May 2025 14:28:42 -0300 Subject: [PATCH 64/66] minor refactoring to make it easier to call shorten() --- links/short.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/links/short.py b/links/short.py index 1ebd0bd..d67c71d 100755 --- a/links/short.py +++ b/links/short.py @@ -60,8 +60,9 @@ def gen_unused_short(redirects: dict) -> Iterator[str]: yield short -def shorten(urls: list[str], redirects: dict, targets: dict) -> list[tuple[str, str]]: +def shorten(urls: list[str]) -> list[tuple[str, str]]: """Return (short, long) pairs, appending directives to HTACCESS_SHORT as needed.""" + redirects, targets = load_redirects() iter_short = gen_unused_short(redirects) pairs = [] timestamp = strftime('%Y-%m-%d %H:%M:%S') @@ -86,8 +87,7 @@ def shorten(urls: list[str], redirects: dict, targets: dict) -> list[tuple[str, def main() -> None: """read URLS from filename arguments or stdin""" urls = [line.strip() for line in fileinput.input(encoding='utf-8')] - redirects, targets = load_redirects() - for short, long in shorten(urls, redirects, targets): + for short, long in shorten(urls): print(f'{BASE_DOMAIN}/{short}\t{long}') From 162dbadbe5cabdfc737c85446a8d788398dfe8b8 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Fri, 23 May 2025 16:35:01 -0300 Subject: [PATCH 65/66] links from vol1 to pythonfluente.com --- links/FPY.LI.htaccess | 1091 ++++++++++++++++++++++++++++++++++++++++- links/short.htaccess | 13 + 2 files changed, 1102 insertions(+), 2 deletions(-) diff --git a/links/FPY.LI.htaccess b/links/FPY.LI.htaccess index 7338157..5607fa4 100644 --- a/links/FPY.LI.htaccess +++ b/links/FPY.LI.htaccess @@ -1,2 +1,1089 @@ -# to update this file: -# cat custom.htaccess short.htaccess >> FPY.LI.htaccess +# to recreate or update this file: +# $ cat custom.htaccess short.htaccess > FPY.LI.htaccess + +ErrorDocument 404 /404.html + +# main resources +RedirectTemp /book https://www.oreilly.com/library/view/fluent-python-2nd/9781492056348/ +RedirectTemp /code https://github.com/fluentpython/example-code-2e +RedirectTemp /home https://www.fluentpython.com/ + +# URLs mentioned at least three times +RedirectTemp /bisect https://www.fluentpython.com/extra/ordered-sequences-with-bisect/ +RedirectTemp /cardxvi https://www.python.org/dev/peps/pep-0484/#the-numeric-tower +RedirectTemp /collec https://docs.python.org/3/library/collections.html +RedirectTemp /dask https://dask.org/ +RedirectTemp /dtmodel https://docs.python.org/3/reference/datamodel.html +RedirectTemp /descr101 https://www.python.org/download/releases/2.2.3/descrintro/ +RedirectTemp /descrhow https://docs.python.org/3/howto/descriptor.html +RedirectTemp /doctest https://docs.python.org/3/library/doctest.html +RedirectTemp /effectpy https://effectivepython.com/ +RedirectTemp /fmtspec https://docs.python.org/3/library/string.html#formatspec +RedirectTemp /gunicorn https://gunicorn.org/ +RedirectTemp /hashint https://www.fluentpython.com/extra/internals-of-sets-and-dicts/ +RedirectTemp /hattingh https://www.oreilly.com/library/view/using-asyncio-in/9781492075325/ +RedirectTemp /httpx https://www.python-httpx.org/ +RedirectTemp /initvar https://docs.python.org/3/library/dataclasses.html#init-only-variables +RedirectTemp /mypy https://mypy.readthedocs.io/en/stable/ +RedirectTemp /norvigdp http://norvig.com/design-patterns/ +RedirectTemp /nsphere https://en.wikipedia.org/wiki/N-sphere +RedirectTemp /oldcoro https://www.fluentpython.com/extra/classic-coroutines/ +RedirectTemp /pandas https://pandas.pydata.org/ +RedirectTemp /pycook3 https://www.oreilly.com/library/view/python-cookbook-3rd/9781449357337/ +RedirectTemp /pynut3 https://www.oreilly.com/library/view/python-in-a/9781491913833/ +RedirectTemp /pypydif https://doc.pypy.org/en/latest/cpython_differences.html#subclasses-of-built-in-types +RedirectTemp /shed4051 https://github.com/python/typeshed/issues/4051 +RedirectTemp /specattr https://docs.python.org/3/library/stdtypes.html#special-attributes +RedirectTemp /typecoro https://docs.python.org/3.10/library/typing.html#typing.Coroutine +RedirectTemp /typing https://docs.python.org/3/library/typing.html +RedirectTemp /weakref https://www.fluentpython.com/extra/weak-references/ + +# URL added during QA of the Second Edition +RedirectTemp /bdfl https://www.artima.com/weblogs/viewpost.jsp?thread=235725 + +# Python Enhancement Proposals +RedirectTemp /pep218 https://www.python.org/dev/peps/pep-0218/ +RedirectTemp /pep227 https://www.python.org/dev/peps/pep-0227/ +RedirectTemp /pep255 https://www.python.org/dev/peps/pep-0255/ +RedirectTemp /pep342 https://www.python.org/dev/peps/pep-0342/ +RedirectTemp /pep343 https://www.python.org/dev/peps/pep-0343/ +RedirectTemp /pep357 https://www.python.org/dev/peps/pep-0357/ +RedirectTemp /pep362 https://www.python.org/dev/peps/pep-0362/ +RedirectTemp /pep371 https://www.python.org/dev/peps/pep-0371/ +RedirectTemp /pep380 https://www.python.org/dev/peps/pep-0380/ +RedirectTemp /pep393 https://www.python.org/dev/peps/pep-0393/ +RedirectTemp /pep412 https://www.python.org/dev/peps/pep-0412/ +RedirectTemp /pep442 https://www.python.org/dev/peps/pep-0442/ +RedirectTemp /pep443 https://www.python.org/dev/peps/pep-0443/ +RedirectTemp /pep448 https://www.python.org/dev/peps/pep-0448/ +RedirectTemp /pep455 https://www.python.org/dev/peps/pep-0455/ +RedirectTemp /pep456 https://www.python.org/dev/peps/pep-0456/ +RedirectTemp /pep461 https://www.python.org/dev/peps/pep-0461/ +RedirectTemp /pep465 https://www.python.org/dev/peps/pep-0465/ +RedirectTemp /pep467 https://www.python.org/dev/peps/pep-0467/ +RedirectTemp /pep482 https://www.python.org/dev/peps/pep-0482/ +RedirectTemp /pep483 https://www.python.org/dev/peps/pep-0483/ +RedirectTemp /pep484 https://www.python.org/dev/peps/pep-0484/ +RedirectTemp /pep487 https://www.python.org/dev/peps/pep-0487/ +RedirectTemp /pep492 https://www.python.org/dev/peps/pep-0492/ +RedirectTemp /pep519 https://www.python.org/dev/peps/pep-0519/ +RedirectTemp /pep525 https://www.python.org/dev/peps/pep-0525/ +RedirectTemp /pep526 https://www.python.org/dev/peps/pep-0526/ +RedirectTemp /pep528 https://www.python.org/dev/peps/pep-0528/ +RedirectTemp /pep529 https://www.python.org/dev/peps/pep-0529/ +RedirectTemp /pep530 https://www.python.org/dev/peps/pep-0530/ +RedirectTemp /pep544 https://www.python.org/dev/peps/pep-0544/ +RedirectTemp /pep554 https://www.python.org/dev/peps/pep-0554/ +RedirectTemp /pep557 https://www.python.org/dev/peps/pep-0557/ +RedirectTemp /pep560 https://www.python.org/dev/peps/pep-0560/ +RedirectTemp /pep561 https://www.python.org/dev/peps/pep-0561/ +RedirectTemp /pep563 https://www.python.org/dev/peps/pep-0563/ +RedirectTemp /pep570 https://www.python.org/dev/peps/pep-0570/ +RedirectTemp /pep572 https://www.python.org/dev/peps/pep-0572/ +RedirectTemp /pep584 https://www.python.org/dev/peps/pep-0584/ +RedirectTemp /pep585 https://www.python.org/dev/peps/pep-0585/ +RedirectTemp /pep586 https://www.python.org/dev/peps/pep-0586/ +RedirectTemp /pep589 https://www.python.org/dev/peps/pep-0589/ +RedirectTemp /pep591 https://www.python.org/dev/peps/pep-0591/ +RedirectTemp /pep593 https://www.python.org/dev/peps/pep-0593/ +RedirectTemp /pep604 https://www.python.org/dev/peps/pep-0604/ +RedirectTemp /pep612 https://www.python.org/dev/peps/pep-0612/ +RedirectTemp /pep613 https://www.python.org/dev/peps/pep-0613/ +RedirectTemp /pep616 https://www.python.org/dev/peps/pep-0616/ +RedirectTemp /pep617 https://www.python.org/dev/peps/pep-0617/ +RedirectTemp /pep618 https://www.python.org/dev/peps/pep-0618/ +RedirectTemp /pep634 https://www.python.org/dev/peps/pep-0634/ +RedirectTemp /pep635 https://www.python.org/dev/peps/pep-0635/ +RedirectTemp /pep636 https://www.python.org/dev/peps/pep-0636/ +RedirectTemp /pep638 https://www.python.org/dev/peps/pep-0638/ +RedirectTemp /pep645 https://www.python.org/dev/peps/pep-0645/ +RedirectTemp /pep646 https://www.python.org/dev/peps/pep-0646/ +RedirectTemp /pep647 https://www.python.org/dev/peps/pep-0647/ +RedirectTemp /pep649 https://www.python.org/dev/peps/pep-0649/ +RedirectTemp /pep654 https://www.python.org/dev/peps/pep-0654/ +RedirectTemp /pep655 https://www.python.org/dev/peps/pep-0655/ +RedirectTemp /pep661 https://www.python.org/dev/peps/pep-0661/ +RedirectTemp /pep3099 https://www.python.org/dev/peps/pep-3099/ +RedirectTemp /pep3102 https://www.python.org/dev/peps/pep-3102/ +RedirectTemp /pep3104 https://www.python.org/dev/peps/pep-3104/ +RedirectTemp /pep3106 https://www.python.org/dev/peps/pep-3106/ +RedirectTemp /pep3107 https://www.python.org/dev/peps/pep-3107/ +RedirectTemp /pep3115 https://www.python.org/dev/peps/pep-3115/ +RedirectTemp /pep3118 https://www.python.org/dev/peps/pep-3118/ +RedirectTemp /pep3119 https://www.python.org/dev/peps/pep-3119/ +RedirectTemp /pep3129 https://www.python.org/dev/peps/pep-3129/ +RedirectTemp /pep3132 https://www.python.org/dev/peps/pep-3132/ +RedirectTemp /pep3141 https://www.python.org/dev/peps/pep-3141/ +RedirectTemp /pep3148 https://www.python.org/dev/peps/pep-3148/ +RedirectTemp /pep3155 https://www.python.org/dev/peps/pep-3155/ +RedirectTemp /pep3333 https://www.python.org/dev/peps/pep-3333/ + +# Remaining URLs by chapter + +############################################################ p +RedirectTemp /p-1 https://mail.python.org/pipermail/python-list/2002-December/134521.html +RedirectTemp /p-2 https://docs.python.org/3.10/tutorial/ +RedirectTemp /p-3 https://docs.python.org/3/tutorial/ +RedirectTemp /p-4 https://www.oreilly.com/library/view/fluent-python-2nd/9781492056348/ +RedirectTemp /p-5 https://www.oreilly.com/online-learning/try-now.html +RedirectTemp /p-6 https://www.oreilly.com/library/view/fluent-python-2nd/9781492056348/ +RedirectTemp /p-7 https://stackoverflow.com/users/95810/alex-martelli +RedirectTemp /p-8 https://pythonpro.com.br +RedirectTemp /p-9 https://groups.google.com/g/python-brasil +RedirectTemp /p-10 https://www.coffeelab.com.br/ +RedirectTemp /p-11 https://garoa.net.br/wiki/P%C3%A1gina_principal +############################################################ a +RedirectTemp /a-1 https://groups.google.com/forum/#!topic/python-tulip/Y4bhLNbKs74 +RedirectTemp /a-2 https://docs.python.org/3/library/asyncio-eventloop.html#executor +RedirectTemp /a-3 https://www.youtube.com/watch?v=x-kB2o8sd5c +RedirectTemp /a-4 https://www.youtube.com/watch?v=OSGv2VnC0go +RedirectTemp /a-5 https://mail.python.org/pipermail/python-ideas/2015-March/032557.html +RedirectTemp /a-6 https://pypi.org/project/pep8/ +RedirectTemp /a-7 https://pypi.org/project/flake8/ +RedirectTemp /a-8 https://pypi.org/project/pyflakes/ +RedirectTemp /a-9 https://pypi.org/project/mccabe/ +RedirectTemp /a-10 https://google.github.io/styleguide/pyguide.html +RedirectTemp /a-11 https://flask.palletsprojects.com/en/1.1.x/styleguide/ +RedirectTemp /a-12 https://docs.python-guide.org/ +RedirectTemp /a-13 https://david.goodger.org/projects/pycon/2007/idiomatic/handout.html +RedirectTemp /a-14 https://docs.mongodb.com/manual/about/#about-the-documentation-process +RedirectTemp /a-15 https://blog.startifact.com/posts/older/what-is-pythonic.html +RedirectTemp /a-16 https://mail.python.org/pipermail/tutor/2003-October/thread.html#25930 +RedirectTemp /a-17 https://mail.python.org/pipermail/python-list/2003-April/192027.html +RedirectTemp /a-18 https://www.python.org/doc/essays/ +############################################################ 01 +RedirectTemp /1-1 http://hugunin.net/story_of_jython.html +RedirectTemp /1-2 https://www.oreilly.com/library/view/jython-essentials/9781449397364/ +RedirectTemp /1-3 https://docs.python.org/3/reference/lexical_analysis.html#reserved-classes-of-identifiers +RedirectTemp /1-4 https://docs.python.org/3.10/library/string.html#format-string-syntax +RedirectTemp /1-5 https://stackoverflow.com/questions/1436703/what-is-the-difference-between-str-and-repr +RedirectTemp /1-6 https://docs.python.org/3/library/stdtypes.html#truth +RedirectTemp /1-7 https://docs.python.org/3/tutorial/controlflow.html#unpacking-argument-lists +RedirectTemp /1-8 https://www.python.org/doc/humor/#the-zen-of-python +RedirectTemp /1-9 https://stackoverflow.com/users/95810/alex-martelli +RedirectTemp /1-10 https://en.wikipedia.org/wiki/Object_model +RedirectTemp /1-11 https://www.dourish.com/goodies/jargon.html +RedirectTemp /1-12 https://zopeinterface.readthedocs.io/en/latest/ +RedirectTemp /1-13 https://plone.org/ +############################################################ 02 +RedirectTemp /2-1 https://github.com/fluentpython/example-code-2e/blob/master/02-array-seq/listcomp_speed.py +RedirectTemp /2-2 https://www.python.org/dev/peps/pep-3132/ +RedirectTemp /2-3 https://stackoverflow.com/questions/68630/are-tuples-more-efficient-than-lists-in-python/22140115#22140115 +RedirectTemp /2-4 https://docs.python.org/3/whatsnew/3.5.html#pep-448-additional-unpacking-generalizations +RedirectTemp /2-5 https://docs.python.org/3/whatsnew/3.5.html#pep-448-additional-unpacking-generalizations +RedirectTemp /2-6 https://docs.python.org/3.10/whatsnew/3.10.html#pep-634-structural-pattern-matching +RedirectTemp /2-7 https://docs.python.org/3.10/whatsnew/3.10.html +RedirectTemp /2-8 https://en.wikipedia.org/wiki/Switch_statement#Fallthrough +RedirectTemp /2-9 https://en.wikipedia.org/wiki/Dangling_else +RedirectTemp /2-10 https://github.com/gvanrossum/patma/blob/3ece6444ef70122876fd9f0099eb9490a2d630df/EXAMPLES.md#case-6-a-very-deep-iterable-and-type-match-with-extraction +RedirectTemp /2-11 https://github.com/fluentpython/lispy/blob/main/original/norvig/lis.py +RedirectTemp /2-12 https://norvig.com/lispy.html +RedirectTemp /2-13 https://numpy.org/doc/stable/user/quickstart.html#indexing-slicing-and-iterating +RedirectTemp /2-14 https://pythontutor.com/ +RedirectTemp /2-15 https://en.wikipedia.org/wiki/Fluent_interface +RedirectTemp /2-16 https://docs.python.org/3/library/bisect.html#bisect.insort +RedirectTemp /2-17 https://stackoverflow.com/questions/4845418/when-should-a-memoryview-be-used/ +RedirectTemp /2-18 https://www.fluentpython.com/extra/parsing-binary-struct/ +RedirectTemp /2-19 http://www.netlib.org +RedirectTemp /2-20 https://pandas.pydata.org/ +RedirectTemp /2-21 https://scikit-learn.org/stable/ +RedirectTemp /2-22 https://docs.python.org/3/howto/sorting.html +RedirectTemp /2-23 https://www.python.org/dev/peps/pep-3132/ +RedirectTemp /2-24 https://bugs.python.org/issue2292 +RedirectTemp /2-25 https://docs.python.org/3.10/whatsnew/3.10.html#pep-634-structural-pattern-matching +RedirectTemp /2-26 https://docs.python.org/3.10/whatsnew/3.10.html +RedirectTemp /2-27 https://www.python.org/dev/peps/pep-0636/#appendix-a-quick-intro +RedirectTemp /2-28 https://eli.thegreenplace.net/2011/11/28/less-copies-in-python-with-the-buffer-protocol-and-memoryviews/ +RedirectTemp /2-29 https://jakevdp.github.io/PythonDataScienceHandbook/ +RedirectTemp /2-30 https://www.oreilly.com/library/view/python-for-data/9781491957653/ +RedirectTemp /2-31 https://www.labri.fr/perso/nrougier/from-python-to-numpy/ +RedirectTemp /2-32 https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html +RedirectTemp /2-33 http://www.fonts101.com/fonts/view/Uncategorized/34398/Dijkstra +RedirectTemp /2-34 https://docs.python.org/3/reference/datamodel.html#objects-values-and-types +RedirectTemp /2-35 https://en.wikipedia.org/wiki/Timsort +RedirectTemp /2-36 http://www.groklaw.net/pdf3/OraGoogle-1202.pdf +RedirectTemp /2-37 https://www.python.org/doc/humor/#id9 +############################################################ 03 +RedirectTemp /3-1 https://www.python.org/dev/peps/pep-0584/#motivation +RedirectTemp /3-2 https://docs.python.org/3.10/c-api/typeobj.html#Py_TPFLAGS_MAPPING +RedirectTemp /3-3 https://docs.python.org/3/glossary.html#term-hashable +RedirectTemp /3-4 https://docs.python.org/3/glossary.html#term-hashable +RedirectTemp /3-5 http://www.aleax.it/Python/accu04_Relearn_Python_alex.pdf +RedirectTemp /3-6 https://github.com/pingo-io/pingo-py +RedirectTemp /3-7 https://github.com/fluentpython/example-code-2e/blob/master/03-dict-set/missing.py +RedirectTemp /3-8 https://docs.python.org/3/library/collections.html#collections.ChainMap +RedirectTemp /3-9 https://docs.python.org/3/library/collections.html#collections.Counter +RedirectTemp /3-10 https://docs.python.org/3/library/shelve.html +RedirectTemp /3-11 https://docs.python.org/3/library/dbm.html +RedirectTemp /3-12 https://docs.python.org/3/library/pickle.html +RedirectTemp /3-13 https://nedbatchelder.com/blog/202006/pickles_nine_flaws.html +RedirectTemp /3-14 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Lib/_collections_abc.py#L813 +RedirectTemp /3-15 https://mail.python.org/pipermail/python-dev/2015-May/140003.html +RedirectTemp /3-16 https://bugs.python.org/issue18986 +RedirectTemp /3-17 https://github.com/fluentpython/example-code-2e/blob/master/03-dict-set/transformdict.py +RedirectTemp /3-18 http://gandenberger.org/2018/03/10/ordered-dicts-vs-ordereddict/ +RedirectTemp /3-19 https://www.pypy.org/ +RedirectTemp /3-20 https://morepypy.blogspot.com/2015/01/faster-more-memory-efficient-and-more.html +RedirectTemp /3-21 https://www.npopov.com/2014/12/22/PHPs-new-hashtable-implementation.html +RedirectTemp /3-22 https://www.youtube.com/watch?v=66P5FMkWoVU +RedirectTemp /3-23 https://pyvideo.org/video/276/the-mighty-dictionary-55/ +RedirectTemp /3-24 https://www.youtube.com/watch?v=p33CVV29OG8 +RedirectTemp /3-25 https://docs.python.org/3/whatsnew/3.6.html#new-dict-implementation +RedirectTemp /3-26 https://github.com/python/cpython/blob/cf7eaa4617295747ee5646c4e2b7e7a16d7c64ab/Objects/dictobject.c +RedirectTemp /3-27 https://github.com/python/cpython/blob/cf7eaa4617295747ee5646c4e2b7e7a16d7c64ab/Objects/dictnotes.txt +RedirectTemp /3-28 https://www.youtube.com/watch?v=tGAngdU_8D8 +RedirectTemp /3-29 https://speakerdeck.com/ramalho/python-set-practice-at-pycon +RedirectTemp /3-30 https://github.com/standupdev/uintset +RedirectTemp /3-31 https://spectrum.ieee.org/hans-peter-luhn-and-the-birth-of-the-hashing-algorithm +RedirectTemp /3-32 http://www.json.org/fatfree.html +RedirectTemp /3-33 https://twitter.com/mitsuhiko/status/1229385843585974272 +############################################################ 04 +RedirectTemp /4-1 https://www.slideshare.net/fischertrav/character-encoding-unicode-how-to-with-dignity-33352863 +RedirectTemp /4-2 https://pyvideo.org/video/2625/character-encoding-and-unicode-in-python/ +RedirectTemp /4-3 https://www.fluentpython.com/extra/parsing-binary-struct/ +RedirectTemp /4-4 https://www.fluentpython.com/extra/multi-character-emojis/ +RedirectTemp /4-5 https://w3techs.com/technologies/overview/character_encoding +RedirectTemp /4-6 https://docs.python.org/3/library/codecs.html#codecs.register_error +RedirectTemp /4-7 https://docs.python.org/3/library/stdtypes.html#str.isascii +RedirectTemp /4-8 https://pypi.org/project/chardet/ +RedirectTemp /4-9 https://docs.python.org/3/library/codecs.html#encodings-and-unicode +RedirectTemp /4-10 https://nedbatchelder.com/text/unipain/unipain.html +RedirectTemp /4-11 https://devblogs.microsoft.com/commandline/windows-command-line-unicode-and-utf-8-output-text-buffer/ +RedirectTemp /4-12 https://docs.python.org/3/using/cmdline.html#envvar-PYTHONIOENCODING +RedirectTemp /4-13 https://docs.python.org/3/using/cmdline.html#envvar-PYTHONLEGACYWINDOWSSTDIO +RedirectTemp /4-14 https://docs.python.org/3/library/locale.html#locale.getpreferredencoding +RedirectTemp /4-15 http://www.w3.org/TR/charmod-norm/ +RedirectTemp /4-16 https://docs.python.org/3/library/locale.html?highlight=strxfrm#locale.strxfrm +RedirectTemp /4-17 https://pypi.org/project/pyuca/ +RedirectTemp /4-18 https://github.com/jtauber/pyuca +RedirectTemp /4-19 http://www.unicode.org/Public/UCA/6.3.0/allkeys.txt +RedirectTemp /4-20 https://pypi.org/project/PyICU/ +RedirectTemp /4-21 https://docs.python.org/3.10/library/stdtypes.html#str.isalpha +RedirectTemp /4-22 https://en.wikipedia.org/wiki/Unicode_character_property#General_Category +RedirectTemp /4-23 https://en.wikipedia.org/wiki/Unicode_character_property +RedirectTemp /4-24 https://github.com/microsoft/terminal +RedirectTemp /4-25 https://docs.python.org/3/library/unicodedata.html +RedirectTemp /4-26 https://docs.python.org/3/reference/lexical_analysis.html#string-literal-concatenation +RedirectTemp /4-27 https://docs.python.org/3/library/re.html +RedirectTemp /4-28 https://nedbatchelder.com/text/unipain.html +RedirectTemp /4-29 https://www.slideshare.net/fischertrav/character-encoding-unicode-how-to-with-dignity-33352863 +RedirectTemp /4-30 https://pyvideo.org/video/2625/character-encoding-and-unicode-in-python/ +RedirectTemp /4-31 https://regebro.wordpress.com/2011/03/23/unconfusing-unicode-what-is-unicode/ +RedirectTemp /4-32 https://docs.python.org/3/howto/unicode.html +RedirectTemp /4-33 https://diveintopython3.net/strings.html +RedirectTemp /4-34 https://diveintopython3.net/ +RedirectTemp /4-35 https://finderiko.com/python-book +RedirectTemp /4-36 https://docs.python.org/3.0/whatsnew/3.0.html#text-vs-data-instead-of-unicode-vs-8-bit +RedirectTemp /4-37 https://lucumr.pocoo.org/2013/7/2/the-updated-guide-to-unicode/ +RedirectTemp /4-38 http://python-notes.curiousefficiency.org/en/latest/python3/binary_protocols.html +RedirectTemp /4-39 http://python-notes.curiousefficiency.org/en/latest/python3/text_file_processing.html +RedirectTemp /4-40 https://docs.python.org/3/library/codecs.html#standard-encodings +RedirectTemp /4-41 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Tools/unicode/listcodecs.py +RedirectTemp /4-42 https://www.oreilly.com/library/view/unicode-explained/059610121X/ +RedirectTemp /4-43 https://www.informit.com/store/unicode-demystified-a-practical-programmers-guide-to-9780201700527 +RedirectTemp /4-44 https://unicodebook.readthedocs.io/index.html +RedirectTemp /4-45 https://www.w3.org/International/wiki/Case_folding +RedirectTemp /4-46 http://www.w3.org/TR/charmod-norm/ +RedirectTemp /4-47 http://unicode.org/reports/tr15/ +RedirectTemp /4-48 http://www.unicode.org/faq/normalization.html +RedirectTemp /4-49 http://www.unicode.org/ +RedirectTemp /4-50 http://www.macchiato.com/unicode/nfc-faq +RedirectTemp /4-51 https://stories.moma.org/the-original-emoji-set-has-been-added-to-the-museum-of-modern-arts-collection-c6060e141f61?gi=c403f5a840a5 +RedirectTemp /4-52 https://emojipedia.org/ +RedirectTemp /4-53 https://blog.emojipedia.org/correcting-the-record-on-the-first-emoji-set/ +RedirectTemp /4-54 http://emojitracker.com/ +RedirectTemp /4-55 http://www.unicode.org/glossary/#plain_text +RedirectTemp /4-56 http://www.methods.co.nz/asciidoc/ +RedirectTemp /4-57 https://atlas.oreilly.com/ +############################################################ 05 +RedirectTemp /5-1 https://docs.python.org/3/library/typing.html#typing.TypedDict +RedirectTemp /5-2 https://docs.python.org/3.10/library/inspect.html#inspect.get_annotations +RedirectTemp /5-3 https://docs.python.org/3/library/typing.html#typing.get_type_hints +RedirectTemp /5-4 https://docs.python.org/3.8/library/collections.html#collections.somenamedtuple._asdict +RedirectTemp /5-5 https://www.jetbrains.com/pycharm/ +RedirectTemp /5-6 https://www.python.org/dev/peps/pep-0484/#acceptable-type-hints +RedirectTemp /5-7 https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass +RedirectTemp /5-8 https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass +RedirectTemp /5-9 https://docs.python.org/3/library/dataclasses.html +RedirectTemp /5-10 https://docs.python.org/3/library/dataclasses.html#inheritance +RedirectTemp /5-11 https://www.python.org/dev/peps/pep-0526/#class-and-instance-variable-annotations +RedirectTemp /5-12 https://dublincore.org/specifications/dublin-core/ +RedirectTemp /5-13 https://en.wikipedia.org/wiki/Dublin_Core +RedirectTemp /5-14 https://martinfowler.com/bliki/CodeSmell.html +RedirectTemp /5-15 https://martinfowler.com/books/refactoring.html +RedirectTemp /5-16 https://www.python.org/dev/peps/pep-0634/#class-patterns +RedirectTemp /5-17 https://docs.python.org/3/library/dataclasses.html +RedirectTemp /5-18 https://www.python.org/dev/peps/pep-0557/#id47 +RedirectTemp /5-19 https://www.python.org/dev/peps/pep-0557/#id48 +RedirectTemp /5-20 https://www.python.org/dev/peps/pep-0557/#id33 +RedirectTemp /5-21 https://realpython.com +RedirectTemp /5-22 https://realpython.com/python-data-classes/ +RedirectTemp /5-23 https://www.youtube.com/watch?v=T-TwcmT6Rcw +RedirectTemp /5-24 https://www.attrs.org/en/stable/ +RedirectTemp /5-25 https://glyph.twistedmatrix.com/2016/08/attrs.html +RedirectTemp /5-26 https://www.attrs.org/en/stable/why.html +RedirectTemp /5-27 https://github.com/dabeaz/cluegen +RedirectTemp /5-28 https://refactoring.guru/ +RedirectTemp /5-29 https://refactoring.guru/smells/data-class +RedirectTemp /5-30 https://web.archive.org/web/20190204130328/http://catb.org/esr/jargon/html/G/Guido.html +RedirectTemp /5-31 https://web.archive.org/web/20190211161610/http://catb.org/esr/jargon/html/index.html +RedirectTemp /5-32 https://www.attrs.org/en/stable/ +############################################################ 06 +RedirectTemp /6-1 https://www.olin.edu/faculty/profile/lynn-andrea-stein/ +RedirectTemp /6-2 https://docs.python.org/3/reference/datamodel.html#objects-values-and-types +RedirectTemp /6-3 https://pythontutor.com/ +RedirectTemp /6-4 https://docs.python.org/3/library/copy.html +RedirectTemp /6-5 https://en.wikipedia.org/wiki/Principle_of_least_astonishment +RedirectTemp /6-6 https://docs.python.org/3/reference/datamodel.html#object.%5C_%5C_del__ +RedirectTemp /6-7 https://emptysqua.re/blog/pypy-garbage-collection-and-a-deadlock/ +RedirectTemp /6-8 https://www.youtube.com/watch?v=HHFCFJSPWrI&feature=youtu.be +RedirectTemp /6-9 http://pymotw.com/3/copy/ +RedirectTemp /6-10 http://pymotw.com/3/weakref/ +RedirectTemp /6-11 https://docs.python.org/3/library/gc.html +RedirectTemp /6-12 https://devguide.python.org/garbage_collector/ +RedirectTemp /6-13 https://devguide.python.org/ +RedirectTemp /6-14 https://www.python.org/dev/peps/pep-0442/ +RedirectTemp /6-15 https://en.wikipedia.org/wiki/String_interning +RedirectTemp /6-16 https://en.wikipedia.org/wiki/Haddocks%27_Eyes +RedirectTemp /6-17 https://thp.io/2012/python-gc/python_gc_final_2012-01-22.pdf +############################################################ 07 +RedirectTemp /7-1 http://python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html +RedirectTemp /7-2 https://www.fluentpython.com/extra/function-introspection/ +RedirectTemp /7-3 https://docs.python.org/3/library/functions.html#map +RedirectTemp /7-4 https://en.wikipedia.org/wiki/Functional_programming +RedirectTemp /7-5 https://docs.python.org/3/howto/functional.html +RedirectTemp /7-6 https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy +RedirectTemp /7-7 https://docs.python.org/3/whatsnew/3.8.html#positional-only-parameters +RedirectTemp /7-8 https://docs.python.org/3/whatsnew/3.8.html#positional-only-parameters +RedirectTemp /7-9 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Lib/functools.py#L341 +RedirectTemp /7-10 https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy +RedirectTemp /7-11 https://docs.python.org/3/howto/functional.html +RedirectTemp /7-12 https://stackoverflow.com/questions/3252228/python-why-is-functools-partial-necessary +RedirectTemp /7-13 https://speakerdeck.com/ramalho/beyond-paradigms-berlin-edition +RedirectTemp /7-14 https://www.youtube.com/watch?v=bF3a2VYXxa0 +RedirectTemp /7-15 http://cs.brown.edu/~sk/Publications/Papers/Published/sk-teach-pl-post-linnaean/ +RedirectTemp /7-16 http://python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html +RedirectTemp /7-17 https://raw.githubusercontent.com/python/cpython/main/Misc/HISTORY +RedirectTemp /7-18 http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html +############################################################ 08 +RedirectTemp /8-1 https://www.python.org/dev/peps/pep-0484/#non-goals +RedirectTemp /8-2 https://github.com/python/typing/issues/182 +RedirectTemp /8-3 https://github.com/python/mypy/issues/731 +RedirectTemp /8-4 https://github.com/google/pytype +RedirectTemp /8-5 https://github.com/Microsoft/pyright +RedirectTemp /8-6 https://pyre-check.org/ +RedirectTemp /8-7 https://mypy.readthedocs.io/en/stable/introduction.html +RedirectTemp /8-8 https://mypy.readthedocs.io/en/stable/config_file.html +RedirectTemp /8-9 https://pypi.org/project/flake8/ +RedirectTemp /8-10 https://pypi.org/project/blue/ +RedirectTemp /8-11 https://pypi.org/project/black/ +RedirectTemp /8-12 https://wefearchange.org/2020/11/steeringcouncil.rst.html +RedirectTemp /8-13 https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes +RedirectTemp /8-14 https://en.wikipedia.org/wiki/Barbara_Liskov +RedirectTemp /8-15 https://en.wikipedia.org/wiki/Behavioral_subtyping +RedirectTemp /8-16 https://www.python.org/dev/peps/pep-0585/#implementation +RedirectTemp /8-17 https://docs.python.org/3/library/typing.html#module-contents +RedirectTemp /8-18 https://en.wikipedia.org/wiki/Geohash +RedirectTemp /8-19 https://en.wikipedia.org/wiki/Inverted_index +RedirectTemp /8-20 https://docs.python.org/3/library/typing.html#typing.List +RedirectTemp /8-21 https://docs.python.org/3/library/typing.html#typing.Dict +RedirectTemp /8-22 https://docs.python.org/3/library/typing.html#typing.Set +RedirectTemp /8-23 https://www.python.org/dev/peps/pep-0585/#implementation +RedirectTemp /8-24 https://docs.python.org/3/library/numbers.html +RedirectTemp /8-25 https://docs.python.org/3/library/typing.html#typing.List +RedirectTemp /8-26 https://github.com/python/typeshed +RedirectTemp /8-27 https://github.com/python/typeshed/blob/66cd36268a6a667714efaa27198a41d0d7f89477/stdlib/2and3/math.pyi#L45 +RedirectTemp /8-28 https://docs.python.org/3/library/statistics.html#statistics.mode +RedirectTemp /8-29 https://github.com/python/cpython/blob/822efa5695b5ba6c2316c1400e4e9ec2546f7ea5/Lib/statistics.py#L534 +RedirectTemp /8-30 https://github.com/python/typeshed/blob/e1e99245bb46223928eba68d4fc74962240ba5b4/stdlib/3/statistics.pyi +RedirectTemp /8-31 https://docs.python.org/3/library/statistics.html#statistics.mode +RedirectTemp /8-32 https://github.com/python/typeshed/blob/a8834fcd46339e17fc8add82b5803a1ce53d3d60/stdlib/3/statistics.pyi#L32 +RedirectTemp /8-33 https://mail.python.org/archives/list/python-dev@python.org/thread/CLVXXPQ2T2LQ5MP2Y53VVQFCXYWQJHKZ/ +RedirectTemp /8-34 https://docs.python.org/3/library/typing.html#typing.Callable +RedirectTemp /8-35 https://pypi.org/project/blue/ +RedirectTemp /8-36 https://www.python.org/dev/peps/pep-0484/#id38 +RedirectTemp /8-37 https://docs.google.com/document/d/1aXs1tpwzPjW9MdsG5dI7clNFyYayFBkcXwRDo-qvbIk/preview +RedirectTemp /8-38 https://www.oreilly.com/library/view/the-best-software/9781590595008/ +RedirectTemp /8-39 https://www.youtube.com/watch?v=YFexUDjHO6w +RedirectTemp /8-40 https://www.youtube.com/watch?v=YFexUDjHO6w&t=13m40s +RedirectTemp /8-41 https://bernat.tech/posts/the-state-of-type-hints-in-python/ +RedirectTemp /8-42 https://realpython.com/python-type-checking/ +RedirectTemp /8-43 https://cjolowicz.github.io/posts/hypermodern-python-04-typing/ +RedirectTemp /8-44 https://mypy.readthedocs.io/en/stable/index.html +RedirectTemp /8-45 https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html +RedirectTemp /8-46 https://mypy.readthedocs.io/en/stable/common_issues.html +RedirectTemp /8-47 https://github.com/typeddjango/awesome-python-typing +RedirectTemp /8-48 https://docs.python.org/3/library/functions.html#max +RedirectTemp /8-49 https://en.wikipedia.org/wiki/Linguistic_relativity +RedirectTemp /8-50 https://pypistats.org/top +RedirectTemp /8-51 https://github.com/psf/requests/issues/3855 +RedirectTemp /8-52 https://lwn.net/Articles/643399/ +RedirectTemp /8-53 https://docs.python-requests.org/en/master/api/#requests.request +RedirectTemp /8-54 https://queue.acm.org/detail.cfm?id=1039523 +############################################################ 09 +RedirectTemp /9-1 https://docs.python.org/3/library/dis.html +RedirectTemp /9-2 https://en.wikipedia.org/wiki/Memoization +RedirectTemp /9-3 https://numpy.org/doc/stable/user/basics.types.html +RedirectTemp /9-4 https://docs.python.org/3/library/functools.html#functools.singledispatch +RedirectTemp /9-5 https://github.com/GrahamDumpleton/wrapt/blob/develop/blog/README.md +RedirectTemp /9-6 https://github.com/GrahamDumpleton/wrapt/blob/develop/blog/01-how-you-implemented-your-python-decorator-is-wrong.md +RedirectTemp /9-7 https://wrapt.readthedocs.io/en/latest/ +RedirectTemp /9-8 https://www.oreilly.com/library/view/python-cookbook-3rd/9781449357337/ch09.html +RedirectTemp /9-9 https://pypi.org/project/decorator/ +RedirectTemp /9-10 https://wiki.python.org/moin/PythonDecoratorLibrary +RedirectTemp /9-11 http://web.archive.org/web/20201109032203/http://effbot.org/zone/closure.htm +RedirectTemp /9-12 https://www.python.org/dev/peps/pep-3104/ +RedirectTemp /9-13 https://www.python.org/dev/peps/pep-0227/ +RedirectTemp /9-14 https://www.python.org/dev/peps/pep-0443/ +RedirectTemp /9-15 https://www.artima.com/weblogs/viewpost.jsp?thread=101605 +RedirectTemp /9-16 https://reg.readthedocs.io/en/latest/ +RedirectTemp /9-17 https://morepath.readthedocs.io/en/latest/ +RedirectTemp /9-18 https://www.gnu.org/software/emacs/manual/html_node/elisp/Dynamic-Binding.html +RedirectTemp /9-19 http://www.paulgraham.com/rootsoflisp.html +RedirectTemp /9-20 http://www-formal.stanford.edu/jmc/recursive/recursive.html +RedirectTemp /9-21 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this +############################################################ 10 +RedirectTemp /10-1 https://en.wikipedia.org/wiki/Software_design_pattern +RedirectTemp /10-2 https://en.wikipedia.org/wiki/Iterator_pattern +RedirectTemp /10-3 https://github.com/python/mypy/issues/9397 +RedirectTemp /10-4 http://www.norvig.com/design-patterns/index.htm +RedirectTemp /10-5 https://pyvideo.org/video/1110/python-design-patterns/ +RedirectTemp /10-6 http://www.aleax.it/gdd_pydp.pdf +RedirectTemp /10-7 https://perl.plover.com/yak/design/ +RedirectTemp /10-8 https://en.wikipedia.org/wiki/Turtles_all_the_way_down +############################################################ 11 +RedirectTemp /11-1 https://blog.startifact.com/posts/older/what-is-pythonic.html +RedirectTemp /11-2 https://julien.danjou.info/guide-python-static-class-abstract-methods/ +RedirectTemp /11-3 https://docs.python.org/3/library/string.html#formatspec +RedirectTemp /11-4 https://docs.python.org/3/reference/lexical_analysis.html#f-strings +RedirectTemp /11-5 https://docs.python.org/3/library/string.html#format-string-syntax +RedirectTemp /11-6 https://docs.python.org/3/library/string.html#formatspec +RedirectTemp /11-7 https://docs.python.org/3/reference/datamodel.html#object.__hash__ +RedirectTemp /11-8 https://web.archive.org/web/20161025185040/http://pythonpaste.org/StyleGuide.html +RedirectTemp /11-9 https://docs.python.org/3/tutorial/modules.html#more-on-modules +RedirectTemp /11-10 https://docs.python.org/3/library/gettext.html#gettext.NullTranslations +RedirectTemp /11-11 https://github.com/fluentpython/example-code-2e/blob/master/11-pythonic-obj/mem_test.py +RedirectTemp /11-12 https://docs.python.org/3/reference/datamodel.html#basic-customization +RedirectTemp /11-13 http://esug.org/data/HistoricalDocuments/TheSmalltalkReport/ST07/04wo.pdf +RedirectTemp /11-14 https://www.artima.com/articles/the-simplest-thing-that-could-possibly-work#part3 +RedirectTemp /11-15 https://docs.oracle.com/javase/tutorial/essential/environment/security.html +RedirectTemp /11-16 https://github.com/fluentpython/example-code-2e/blob/master/11-pythonic-obj/private/Expose.java +RedirectTemp /11-17 https://docs.oracle.com/javase/tutorial/essential/environment/security.html +############################################################ 12 +RedirectTemp /12-1 https://en.wikipedia.org/wiki/Vector_space_model +RedirectTemp /12-2 https://pypi.org/project/gensim/ +RedirectTemp /12-3 https://docs.python.org/3/library/functions.html#enumerate +RedirectTemp /12-4 https://mathworld.wolfram.com/Hypersphere.html +RedirectTemp /12-5 https://en.wikipedia.org/wiki/Fold_(higher-order_function) +RedirectTemp /12-6 https://docs.python.org/2.5/whatsnew/pep-357.html +RedirectTemp /12-7 https://docs.python.org/3/reference/datamodel.html#special-method-names +RedirectTemp /12-8 https://en.wikipedia.org/wiki/KISS_principle +RedirectTemp /12-9 https://mail.python.org/pipermail/python-list/2000-July/046184.html +RedirectTemp /12-10 https://en.wikipedia.org/wiki/Duck_typing +RedirectTemp /12-11 https://mail.python.org/mailman/listinfo/python-list +RedirectTemp /12-12 https://mail.python.org/pipermail/python-list/2003-April/218568.html +############################################################ 13 +RedirectTemp /13-1 https://docs.python.org/3/c-api/index.html +RedirectTemp /13-2 https://docs.python.org/3/c-api/sequence.html +RedirectTemp /13-3 https://github.com/python/cpython/blob/31ceccb2c77854893f3a754aca04bedd74bedb10/Lib/_collections_abc.py#L870 +RedirectTemp /13-4 https://en.wikipedia.org/wiki/Monkey_patch +RedirectTemp /13-5 https://www.gevent.org/api/gevent.monkey.html +RedirectTemp /13-6 https://docs.python.org/3/library/random.html#random.shuffle +RedirectTemp /13-7 https://docs.python.org/3/reference/datamodel.html#emulating-container-types +RedirectTemp /13-8 https://docs.python.org/3/library/collections.html#collections.namedtuple +RedirectTemp /13-9 https://github.com/python/typeshed/blob/24afb531ffd07083d6a74be917342195062f7277/stdlib/collections/__init__.pyi +RedirectTemp /13-10 https://docs.python.org/3/glossary.html#term-abstract-base-class +RedirectTemp /13-11 https://en.wikipedia.org/wiki/Duck_typing#History +RedirectTemp /13-12 http://ptgmedia.pearsoncmg.com/images/020163371x/items/item33.html +RedirectTemp /13-13 https://docs.python.org/3/library/bisect.html#bisect.bisect +RedirectTemp /13-14 https://github.com/python/cpython/blob/main/Lib/_collections_abc.py +RedirectTemp /13-15 https://github.com/python/cpython/blob/main/Lib/abc.py +RedirectTemp /13-16 https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes +RedirectTemp /13-17 https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable +RedirectTemp /13-18 https://docs.python.org/3/library/abc.html +RedirectTemp /13-19 https://docs.python.org/dev/library/abc.html#abc.abstractmethod +RedirectTemp /13-20 https://docs.python.org/dev/library/abc.html +RedirectTemp /13-21 https://docs.python.org/3/library/os.html#os.urandom +RedirectTemp /13-22 https://github.com/python/mypy/issues/2922 +RedirectTemp /13-23 https://docs.python.org/3/library/stdtypes.html#truth +RedirectTemp /13-24 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Lib/_collections_abc.py +RedirectTemp /13-25 https://github.com/python/cpython/blob/0fbddb14dc03f61738af01af88e7d8aa8df07336/Lib/_collections_abc.py#L369 +RedirectTemp /13-26 https://github.com/python/cpython/blob/c0a9afe2ac1820409e6173bd1893ebee2cf50270/Lib/abc.py#L196 +RedirectTemp /13-27 https://bugs.python.org/issue31333 +RedirectTemp /13-28 https://github.com/python/cpython/blob/3635388f52b42e5280229104747962117104c453/Modules/_abc.c#L605 +RedirectTemp /13-29 https://github.com/python/cpython/blob/0fbddb14dc03f61738af01af88e7d8aa8df07336/Lib/_collections_abc.py#L881 +RedirectTemp /13-30 https://docs.python.org/3/library/typing.html#protocols +RedirectTemp /13-31 https://github.com/python/cpython/blob/3635388f52b42e5280229104747962117104c453/Lib/typing.py#L1751 +RedirectTemp /13-32 https://mail.python.org/archives/list/python-dev@python.org/thread/CLVXXPQ2T2LQ5MP2Y53VVQFCXYWQJHKZ/ +RedirectTemp /13-33 https://martinfowler.com/bliki/RoleInterface.html +RedirectTemp /13-34 https://en.wikipedia.org/wiki/Interface_segregation_principle +RedirectTemp /13-35 https://github.com/python/typeshed/blob/master/CONTRIBUTING.md +RedirectTemp /13-36 https://gist.github.com/asukakenji/ac8a05644a2e98f1d5ea8c299541fce9 +RedirectTemp /13-37 https://www.python.org/dev/peps/pep-0544/#runtime-checkable-decorator-and-narrowing-types-by-isinstance +RedirectTemp /13-38 https://www.python.org/dev/peps/pep-0544/#merging-and-extending-protocols +RedirectTemp /13-39 https://numpy.org/devdocs/user/basics.types.html +RedirectTemp /13-40 https://github.com/python/typeshed/blob/master/stdlib/statistics.pyi +RedirectTemp /13-41 https://bugs.python.org/issue41974 +RedirectTemp /13-42 https://glyph.twistedmatrix.com/2020/07/new-duck.html +RedirectTemp /13-43 https://glyph.twistedmatrix.com/2021/03/interfaces-and-protocols.html +RedirectTemp /13-44 https://plone.org/ +RedirectTemp /13-45 https://trypyramid.com/ +RedirectTemp /13-46 https://twistedmatrix.com/trac/ +RedirectTemp /13-47 https://www.artima.com/articles/contracts-in-python +RedirectTemp /13-48 https://martinfowler.com/bliki/DynamicTyping.html +RedirectTemp /13-49 https://martinfowler.com/bliki/RoleInterface.html +RedirectTemp /13-50 https://mypy.readthedocs.io/en/stable/protocols.html +RedirectTemp /13-51 https://pymotw.com/3/abc/index.html +RedirectTemp /13-52 https://www.python.org/dev/peps/pep-3119/ +RedirectTemp /13-53 https://www.python.org/dev/peps/pep-3141/ +RedirectTemp /13-54 https://docs.python.org/3/library/numbers.html +RedirectTemp /13-55 https://github.com/python/mypy/issues/3186 +RedirectTemp /13-56 https://stackoverflow.com/questions/69334475/how-to-hint-at-number-types-i-e-subclasses-of-number-not-numbers-themselv/69383462#69383462 +RedirectTemp /13-57 https://github.com/python/mypy/issues/3186 +RedirectTemp /13-58 https://martinfowler.com/articles/lean-inception/ +RedirectTemp /13-59 https://martinfowler.com +RedirectTemp /13-60 https://www.jetbrains.com/pycharm/ +RedirectTemp /13-61 https://wingware.com/ +RedirectTemp /13-62 https://code.visualstudio.com/ +############################################################ 14 +RedirectTemp /14-1 http://worrydream.com/EarlyHistoryOfSmalltalk/ +RedirectTemp /14-2 https://docs.python.org/3/tutorial/classes.html +RedirectTemp /14-3 https://docs.python.org/3/library/collections.html#ordereddict-examples-and-recipes +RedirectTemp /14-4 https://discuss.python.org/t/is-it-time-to-deprecate-unbound-super-methods/1833 +RedirectTemp /14-5 https://doc.pypy.org/en/latest/cpython_differences.html#subclasses-of-built-in-types +RedirectTemp /14-6 https://docs.python.org/3/library/collections.html +RedirectTemp /14-7 https://github.com/fluentpython/example-code-2e/blob/master/14-inheritance/strkeydict_dictsub.py +RedirectTemp /14-8 https://doc.pypy.org/en/latest/cpython_differences.html#subclasses-of-built-in-types +RedirectTemp /14-9 https://en.wikipedia.org/wiki/Breadth-first_search +RedirectTemp /14-10 https://www.python.org/download/releases/2.3/mro/ +RedirectTemp /14-11 https://github.com/fluentpython/example-code-2e/blob/master/14-inheritance/uppermixin.py +RedirectTemp /14-12 https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html +RedirectTemp /14-13 https://docs.python.org/3/library/collections.abc.html +RedirectTemp /14-14 https://github.com/python/cpython/blob/8ece98a7e418c3c68a4c61bc47a2d0931b59a889/Lib/collections/__init__.py#L1084 +RedirectTemp /14-15 https://docs.python.org/3/library/http.server.html +RedirectTemp /14-16 https://github.com/python/cpython/blob/17c23167942498296f0bdfffe52e72d53d66d693/Lib/http/server.py#L144 +RedirectTemp /14-17 https://github.com/python/cpython/blob/699ee016af5736ffc80f68359617611a22b72943/Lib/socketserver.py#L664 +RedirectTemp /14-18 https://docs.python.org/3/library/socketserver.html#socketserver.ForkingMixIn +RedirectTemp /14-19 https://docs.python.org/3/library/os.html#os.fork +RedirectTemp /14-20 https://en.wikipedia.org/wiki/POSIX +RedirectTemp /14-21 http://ccbv.co.uk/ +RedirectTemp /14-22 https://github.com/django/django/tree/main/django/views/generic +RedirectTemp /14-23 https://en.wikipedia.org/wiki/Template_method_pattern +RedirectTemp /14-24 https://docs.python.org/3/library/tkinter.html +RedirectTemp /14-25 https://docs.python.org/3/library/tkinter.ttk.html +RedirectTemp /14-26 https://docs.oracle.com/javase/10/docs/api/java/awt/package-tree.html +RedirectTemp /14-27 https://docs.oracle.com/javase/10/docs/api/javax/swing/package-tree.html +RedirectTemp /14-28 https://squeak.org/ +RedirectTemp /14-29 https://github.com/django/django/blob/b64db05b9cedd96905d637a2d824cbbf428e40e7/django/views/generic/list.py#L194 +RedirectTemp /14-30 https://github.com/python/cpython/blob/8ed183391241f0c73e7ba7f42b1d49fc02985f7b/Lib/tkinter/__init__.py#L2618 +RedirectTemp /14-31 https://docs.python.org/3/library/socketserver.html +RedirectTemp /14-32 https://docs.python.org/3/library/socketserver.html#socketserver.BaseServer +RedirectTemp /14-33 https://github.com/python/cpython/blob/699ee016af5736ffc80f68359617611a22b72943/Lib/socketserver.py#L153 +RedirectTemp /14-34 https://docs.python.org/3/library/typing.html#typing.final +RedirectTemp /14-35 https://docs.python.org/3/library/typing.html#typing.Final +RedirectTemp /14-36 https://docs.python.org/3/library/collections.abc.html +RedirectTemp /14-37 https://hynek.me/articles/python-subclassing-redux/ +RedirectTemp /14-38 https://www.oreilly.com/library/view/python-cookbook-3rd/9781449357337/ch08.html#super +RedirectTemp /14-39 https://rhettinger.wordpress.com/2011/05/26/super-considered-super/ +RedirectTemp /14-40 https://fuhm.net/super-harmful/ +RedirectTemp /14-41 https://stackoverflow.com/questions/30190185/how-to-use-super-with-one-argument/30190341#30190341 +RedirectTemp /14-42 https://www.artima.com/weblogs/viewpost.jsp?thread=246488 +RedirectTemp /14-43 https://www.artima.com/weblogs/viewpost.jsp?thread=281127 +RedirectTemp /14-44 https://www.artima.com/weblogs/viewpost.jsp?thread=246341 +RedirectTemp /14-45 https://www.artima.com/weblogs/viewpost.jsp?thread=246483 +RedirectTemp /14-46 https://www.artima.com/weblogs/viewpost.jsp?thread=236275 +RedirectTemp /14-47 https://www.artima.com/weblogs/viewpost.jsp?thread=236278 +RedirectTemp /14-48 https://www.artima.com/weblogs/viewpost.jsp?thread=237121 +RedirectTemp /14-49 https://python-patterns.guide/gang-of-four/composition-over-inheritance/ +RedirectTemp /14-50 https://python-patterns.guide/ +RedirectTemp /14-51 https://www.youtube.com/watch?v=3MNVP9-hglc +RedirectTemp /14-52 http://worrydream.com/EarlyHistoryOfSmalltalk/ +RedirectTemp /14-53 https://en.wikipedia.org/wiki/Polymorphism_(computer_science) +############################################################ 15 +RedirectTemp /15-1 https://www.youtube.com/watch?v=csL8DLXGNlU&t=92m5s +RedirectTemp /15-2 https://github.com/python/typeshed/blob/a8834fcd46339e17fc8add82b5803a1ce53d3d60/stdlib/2and3/builtins.pyi#L1434 +RedirectTemp /15-3 https://github.com/python/typeshed/blob/a8834fcd46339e17fc8add82b5803a1ce53d3d60/stdlib/2and3/builtins.pyi +RedirectTemp /15-4 https://twitter.com/gwidion/status/1265384692464967680 +RedirectTemp /15-5 https://pypi.org/project/pydantic/ +RedirectTemp /15-6 https://google.github.io/pytype/faq.html +RedirectTemp /15-7 https://google.github.io/pytype/faq.html +RedirectTemp /15-8 https://lxml.de/ +RedirectTemp /15-9 https://docs.python.org/3/library/xml.etree.elementtree.html +RedirectTemp /15-10 https://mypy.readthedocs.io/en/stable/common_issues.html +RedirectTemp /15-11 https://mypy.readthedocs.io/en/stable/common_issues.html#types-of-empty-collections +RedirectTemp /15-12 https://github.com/python/typing/issues/182 +RedirectTemp /15-13 https://pypi.org/project/pydantic/ +RedirectTemp /15-14 https://mypy.readthedocs.io/en/stable/type_narrowing.html#casts +RedirectTemp /15-15 https://github.com/python/cpython/blob/bee66d3cb98e740f9d8057eb7f503122052ca5d8/Lib/typing.py#L1340 +RedirectTemp /15-16 https://www.python.org/dev/peps/pep-0484/#casts +RedirectTemp /15-17 https://github.com/python/typeshed/issues/5535 +RedirectTemp /15-18 https://docs.python.org/3/library/asyncio-stream.html#tcp-echo-server-using-streams +RedirectTemp /15-19 https://github.com/python/cpython/blob/b798ab06937f8bb24b444a49dd42e11fff15e654/Lib/test/test_asyncio/test_server.py#L55 +RedirectTemp /15-20 https://en.wikipedia.org/wiki/Code_smell +RedirectTemp /15-21 https://mail.python.org/archives/list/typing-sig@python.org/message/5LCWMN2UY2UQNLC5Z47GHBZKSPZW4I63/ +RedirectTemp /15-22 https://mypy.readthedocs.io/en/stable/error_codes.html#error-codes +RedirectTemp /15-23 https://github.com/fluentpython/example-code-2e/blob/master/15-more-types/clip_annot.py +RedirectTemp /15-24 https://docs.python.org/3/library/typing.html#introspection-helpers +RedirectTemp /15-25 https://docs.python.org/3.10/library/inspect.html#inspect.get_annotations +RedirectTemp /15-26 https://www.python.org/dev/peps/pep-0563/#abstract +RedirectTemp /15-27 https://mail.python.org/archives/list/python-dev@python.org/message/ZBJ7MD6CSGM6LZAOTET7GXAVBZB7O77O/ +RedirectTemp /15-28 https://docs.python.org/3.10/howto/annotations.html +RedirectTemp /15-29 https://docs.python.org/3/library/typing.html#user-defined-generic-types +RedirectTemp /15-30 https://github.com/python/typeshed/blob/bfc83c365a0b26ab16586beac77ff16729d0e473/stdlib/builtins.pyi#L743 +RedirectTemp /15-31 https://docs.python.org/3.10/library/typing.html#typing.FrozenSet +RedirectTemp /15-32 https://docs.python.org/3.10/library/typing.html#typing.Generator +RedirectTemp /15-33 https://docs.python.org/3.10/library/typing.html#typing.AsyncGenerator +RedirectTemp /15-34 https://github.com/python/cpython/blob/46b16d0bdbb1722daed10389e27226a2370f1635/Lib/typing.py#L1786 +RedirectTemp /15-35 https://github.com/python/typeshed/blob/2a9f081abbf01134e4e04ced6a750107db904d70/stdlib/builtins.pyi#L239 +RedirectTemp /15-36 https://www.oreilly.com/library/view/robust-python/9781098100650/ +RedirectTemp /15-37 https://www.python.org/dev/peps/pep-0484/#covariance-and-contravariance +RedirectTemp /15-38 https://mypy.readthedocs.io/en/stable/generics.html#variance-of-generic-types +RedirectTemp /15-39 https://mypy.readthedocs.io/en/stable/common_issues.html#variance +RedirectTemp /15-40 https://www.artima.com/weblogs/viewpost.jsp?thread=85551 +RedirectTemp /15-41 https://dl.acm.org/action/cookieAbsent +RedirectTemp /15-42 http://bracha.org/pluggableTypesPosition.pdf +RedirectTemp /15-43 https://www.researchgate.net/publication/213886116_Static_Typing_Where_Possible_Dynamic_Typing_When_Needed_The_End_of_the_Cold_War_Between_Programming_Languages +RedirectTemp /15-44 https://www.atomickotlin.com/atomickotlin/ +RedirectTemp /15-45 https://www.informit.com/store/effective-java-9780134685991 +RedirectTemp /15-46 https://www.manning.com/books/programming-with-types +RedirectTemp /15-47 https://www.oreilly.com/library/view/programming-typescript/9781492037644/ +RedirectTemp /15-48 https://www.informit.com/store/dart-programming-language-9780321927705 +RedirectTemp /15-49 https://www.yodaiken.com/2017/09/15/bad-ideas-in-type-theory/ +RedirectTemp /15-50 https://www.yodaiken.com/2017/11/30/types-considered-harmful-ii/ +RedirectTemp /15-51 https://web.archive.org/web/20071010002142/http://weblogs.java.net/blog/arnold/archive/2005/06/generics_consid_1.html +RedirectTemp /15-52 https://github.com/python/cpython/blob/3e7ee02327db13e4337374597cdc4458ecb9e3ad/Lib/asyncio/trsock.py#L5 +RedirectTemp /15-53 https://www.python.org/dev/peps/pep-0484/#covariance-and-contravariance +############################################################ 16 +RedirectTemp /16-1 http://www.gotw.ca/publications/c_family_interview.htm +RedirectTemp /16-2 https://docs.python.org/3/reference/expressions.html#unary-arithmetic-and-bitwise-operations +RedirectTemp /16-3 https://docs.python.org/3/reference/datamodel.html#object.__neg__ +RedirectTemp /16-4 https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#boolean-indexing +RedirectTemp /16-5 https://docs.python.org/3/library/collections.html#collections.Counter +RedirectTemp /16-6 https://docs.python.org/3/reference/datamodel.html#emulating-container-types +RedirectTemp /16-7 https://docs.python.org/3/library/numbers.html#implementing-the-arithmetic-operations +RedirectTemp /16-8 https://www.fluentpython.com/lingo/#fail-fast +RedirectTemp /16-9 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Objects/typeobject.c#L4598 +RedirectTemp /16-10 https://neopythonic.blogspot.com/2019/03/why-operators-are-useful.html +RedirectTemp /16-11 https://treyhunner.com/2019/03/python-deep-comparisons-and-code-readability/ +RedirectTemp /16-12 https://docs.python.org/3/library/numbers.html#implementing-the-arithmetic-operations +RedirectTemp /16-13 https://docs.python.org/3/library/pathlib.html +RedirectTemp /16-14 https://pypi.org/project/scapy/ +RedirectTemp /16-15 https://scapy.readthedocs.io/en/latest/usage.html#stacking-layers +RedirectTemp /16-16 https://docs.python.org/3/library/functools.html#functools.total_ordering +RedirectTemp /16-17 https://wiki.illinois.edu//wiki/download/attachments/273416327/ingalls.pdf +RedirectTemp /16-18 https://wiki.illinois.edu//wiki/download/attachments/273416327/double-dispatch.pdf +RedirectTemp /16-19 http://www.gotw.ca/publications/c_family_interview.htm +RedirectTemp /16-20 http://www.gotw.ca/publications/c_family_interview.htm +RedirectTemp /16-21 https://doc.rust-lang.org/std/ops/index.html +RedirectTemp /16-22 https://www.fluentpython.com/lingo/#lazy +############################################################ 17 +RedirectTemp /17-1 http://www.paulgraham.com/icad.html +RedirectTemp /17-2 https://en.wikipedia.org/wiki/Sentinel_value +RedirectTemp /17-3 https://docs.python.org/3.10/library/functions.html#iter +RedirectTemp /17-4 https://docs.python.org/3.10/library/functions.html#iter +RedirectTemp /17-5 https://github.com/python/cpython/blob/b1930bf75f276cd7ca08c4455298128d89adf7d1/Lib/_collections_abc.py#L271 +RedirectTemp /17-6 https://github.com/python/cpython/blob/main/Lib/types.py#L6 +RedirectTemp /17-7 https://en.wikipedia.org/wiki/CLU_(programming_language) +RedirectTemp /17-8 https://docs.python.org/3/glossary.html +RedirectTemp /17-9 https://docs.python.org/3/glossary.html#term-generator-iterator +RedirectTemp /17-10 https://docs.python.org/3/glossary.html#term-generator-expression +RedirectTemp /17-11 https://marc.info/?l=python-list&m=141826925106951&w=2 +RedirectTemp /17-12 https://docs.python.org/3/library/os.html#os.walk +RedirectTemp /17-13 https://docs.python.org/3/library/itertools.html +RedirectTemp /17-14 https://docs.python.org/3/library/exceptions.html#exception-hierarchy +RedirectTemp /17-15 https://en.wikipedia.org/wiki/Depth-first_search +RedirectTemp /17-16 https://docs.python.org/3.10/library/typing.html#typing.TypeAlias +RedirectTemp /17-17 https://docs.python.org/3/library/typing.html#typing.Generator +RedirectTemp /17-18 http://www.dabeaz.com/coroutines/Coroutines.pdf +RedirectTemp /17-19 http://www.dabeaz.com/coroutines/Coroutines.pdf +RedirectTemp /17-20 https://mail.python.org/pipermail/python-ideas/2009-April/003841.html +RedirectTemp /17-21 https://mail.python.org/pipermail/python-ideas/2009-April/003912.html +RedirectTemp /17-22 https://docs.python.org/3/library/exceptions.html#StopIteration +RedirectTemp /17-23 https://docs.python.org/3/reference/expressions.html#yield-expressions +RedirectTemp /17-24 https://docs.python.org/3/reference/index.html +RedirectTemp /17-25 https://github.com/python/cpython/blob/6f743e7a4da904f61dfa84cc7d7385e4dcc79ac5/Lib/typing.py#L2060 +RedirectTemp /17-26 http://catb.org/~esr/jargon/html/G/grok.html +RedirectTemp /17-27 https://docs.python.org/3/reference/expressions.html#yieldexpr +RedirectTemp /17-28 https://docs.python.org/3/library/itertools.html +RedirectTemp /17-29 https://docs.python.org/3/library/itertools.html#itertools-recipes +RedirectTemp /17-30 https://more-itertools.readthedocs.io/en/stable/index.html +RedirectTemp /17-31 https://rittau.org/2006/11/java-iterators-are-not-iterable/ +RedirectTemp /17-32 https://docs.python.org/3/whatsnew/3.3.html#pep-380-syntax-for-delegating-to-a-subgenerator +RedirectTemp /17-33 http://www.dabeaz.com/generators/ +RedirectTemp /17-34 http://www.dabeaz.com/coroutines/ +RedirectTemp /17-35 https://archive.org/details/pyvideo_213___pycon-2009-a-curious-course-on-coroutines-and-concurrency-part-1-of-3 +RedirectTemp /17-36 https://archive.org/details/pyvideo_215___pycon-2009-a-curious-course-on-coroutines-and-concurrency-part-2-of-3 +RedirectTemp /17-37 https://archive.org/details/pyvideo_214___pycon-2009-a-curious-course-on-coroutines-and-concurrency-part-3-of-3 +RedirectTemp /17-38 http://www.dabeaz.com/finalgenerator/ +RedirectTemp /17-39 https://web.archive.org/web/20200218150637/http://seriously.dontusethiscode.com/2013/05/01/greedy-coroutine.html +RedirectTemp /17-40 https://effectivepython.com/ +RedirectTemp /17-41 https://effectivepython.com/2015/03/10/consider-coroutines-to-run-many-functions-concurrently +RedirectTemp /17-42 https://en.wikipedia.org/wiki/Conway's_Game_of_Life +RedirectTemp /17-43 https://gist.github.com/ramalho/da5590bc38c973408839 +RedirectTemp /17-44 https://gist.github.com/ramalho/da5590bc38c973408839 +RedirectTemp /17-45 https://journal.code4lib.org/articles/4893 +RedirectTemp /17-46 https://github.com/fluentpython/isis2json +RedirectTemp /17-47 https://github.com/fluentpython/isis2json/blob/master/README.rst +############################################################ 18 +RedirectTemp /18-1 https://pyvideo.org/video/1669/keynote-3/ +RedirectTemp /18-2 https://docs.python.org/3/library/sqlite3.html#using-the-connection-as-a-context-manager +RedirectTemp /18-3 https://docs.python.org/3/library/threading.html#using-locks-conditions-and-semaphores-in-the-with-statement +RedirectTemp /18-4 https://docs.python.org/3/library/decimal.html#decimal.localcontext +RedirectTemp /18-5 https://docs.python.org/3/library/unittest.mock.html#patch +RedirectTemp /18-6 https://docs.python.org/3/library/contextlib.html#contextlib.redirect_stdout +RedirectTemp /18-7 https://docs.python.org/3/library/sys.html#sys.exc_info +RedirectTemp /18-8 https://en.wikipedia.org/wiki/LL_parser +RedirectTemp /18-9 https://docs.python.org/3/library/contextlib.html +RedirectTemp /18-10 https://github.com/python/cpython/blob/8afab2ebbc1b343cd88d058914cf622fe687a2be/Lib/contextlib.py#L123 +RedirectTemp /18-11 https://www.zopatista.com/python/2013/11/26/inplace-file-rewriting/ +RedirectTemp /18-12 https://docs.python.org/3/library/fileinput.html#fileinput.input +RedirectTemp /18-13 https://www.zopatista.com/python/2013/11/26/inplace-file-rewriting/ +RedirectTemp /18-14 https://en.wikipedia.org/wiki/Euclidean_algorithm +RedirectTemp /18-15 https://github.com/fluentpython/example-code-2e/tree/master/18-with-match/lispy/py3.10/ +RedirectTemp /18-16 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/original/lispy.py +RedirectTemp /18-17 https://github.com/fluentpython/example-code-2e/blob/6527037ae7319ba370a1ee2d9fe79214d0ed9452/18-with-match/lispy/py3.10/lis.py#L35 +RedirectTemp /18-18 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/py3.10/examples_test.py +RedirectTemp /18-19 https://github.com/python/typeshed/issues/6042 +RedirectTemp /18-20 https://github.com/fluentpython/lispy/tree/main/mylis +RedirectTemp /18-21 https://github.com/fluentpython/example-code-2e/blob/00e4741926e1b771ee7c753148b1415c0bd12e39/02-array-seq/lispy/py3.10/examples_test.py +RedirectTemp /18-22 https://mitpress.mit.edu/sites/default/files/sicp/index.html +RedirectTemp /18-23 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/py3.10/examples_test.py +RedirectTemp /18-24 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/py3.10/lis.py +RedirectTemp /18-25 https://www.python.org/dev/peps/pep-0634/#or-patterns +RedirectTemp /18-26 https://en.wikipedia.org/wiki/Lambda#Character_encodings +RedirectTemp /18-27 https://docs.python.org/3/reference/compound_stmts.html +RedirectTemp /18-28 https://docs.python.org/3/glossary.html#term-eafp +RedirectTemp /18-29 https://speakerdeck.com/pyconslides/pycon-keynote-python-is-awesome-by-raymond-hettinger?slide=21 +RedirectTemp /18-30 https://docs.python.org/3/reference/compound_stmts.html +RedirectTemp /18-31 https://stackoverflow.com/questions/16138232/is-it-a-good-practice-to-use-try-except-else-in-python +RedirectTemp /18-32 https://docs.python.org/3/library/stdtypes.html#typecontextmanager +RedirectTemp /18-33 https://docs.python.org/3/reference/datamodel.html#with-statement-context-managers +RedirectTemp /18-34 https://speakerdeck.com/pyconslides/pycon-keynote-python-is-awesome-by-raymond-hettinger?slide=21 +RedirectTemp /18-35 https://speakerdeck.com/pyconslides/transforming-code-into-beautiful-idiomatic-python-by-raymond-hettinger-1?slide=34 +RedirectTemp /18-36 https://preshing.com/20110920/the-python-with-statement-by-example/ +RedirectTemp /18-37 https://www.rath.org/on-the-beauty-of-pythons-exitstack.html +RedirectTemp /18-38 https://norvig.com/lispy.html +RedirectTemp /18-39 https://norvig.com/lispy2.html +RedirectTemp /18-40 https://github.com/norvig/pytudes +RedirectTemp /18-41 https://github.com/fluentpython/lispy +RedirectTemp /18-42 https://racket-lang.org/ +RedirectTemp /18-43 https://pyvideo.org/video/1669/keynote-3/ +RedirectTemp /18-44 https://en.wikipedia.org/wiki/Tail_call +RedirectTemp /18-45 https://2ality.com/2015/06/tail-call-optimization.html +RedirectTemp /18-46 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/original/lis.py +RedirectTemp /18-47 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/original/lispy.py +RedirectTemp /18-48 http://neopythonic.blogspot.com/2009/04/final-words-on-tail-calls.html +RedirectTemp /18-49 https://webkit.org/blog/6240/ecmascript-6-proper-tail-calls-in-webkit/ +RedirectTemp /18-50 http://kangax.github.io/compat-table/es6/ +RedirectTemp /18-51 https://world.hey.com/mgmarlow/what-happened-to-proper-tail-calls-in-javascript-5494c256 +RedirectTemp /18-52 http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html +RedirectTemp /18-53 https://github.com/fluentpython/lispy/blob/main/mylis/mylis_2/lis.py +RedirectTemp /18-54 https://github.com/fluentpython/lispy/tree/main/mylis +############################################################ 19 +RedirectTemp /19-1 https://go.dev/blog/waza-talk +RedirectTemp /19-2 https://en.wikipedia.org/wiki/Graphics_processing_unit +RedirectTemp /19-3 https://docs.python.org/3/library/sys.html#sys.getswitchinterval +RedirectTemp /19-4 https://docs.python.org/3/library/sys.html#sys.setswitchinterval +RedirectTemp /19-5 https://en.wikipedia.org/wiki/System_call +RedirectTemp /19-6 https://mail.python.org/pipermail/python-dev/2009-October/093356.html +RedirectTemp /19-7 http://www.dabeaz.com/finalgenerator/ +RedirectTemp /19-8 https://docs.python.org/3/library/threading.html#thread-objects +RedirectTemp /19-9 https://www.pypy.org/ +RedirectTemp /19-10 https://mail.python.org/pipermail/python-list/2009-February/675659.html +RedirectTemp /19-11 https://en.wikipedia.org/wiki/Braille_Patterns +RedirectTemp /19-12 https://docs.python.org/3/library/multiprocessing.shared_memory.html +RedirectTemp /19-13 https://docs.python.org/3/library/multiprocessing.shared_memory.html#multiprocessing.shared_memory.ShareableList +RedirectTemp /19-14 https://greenlet.readthedocs.io/en/latest/ +RedirectTemp /19-15 https://docs.sqlalchemy.org/en/14/changelog/migration_14.html#asynchronous-io-support-for-core-and-orm +RedirectTemp /19-16 https://docs.sqlalchemy.org/en/14/orm/extensions/asyncio.html +RedirectTemp /19-17 http://www.gevent.org/ +RedirectTemp /19-18 https://github.com/gevent/gevent/wiki/Projects +RedirectTemp /19-19 https://docs.python.org/3/library/concurrent.futures.html#processpoolexecutor-example +RedirectTemp /19-20 https://github.com/python/asyncio/issues/284 +RedirectTemp /19-21 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor +RedirectTemp /19-22 https://mail.python.org/archives/list/python-dev@python.org/message/JBYXQH3NV3YBF7P2HLHB5CD6V3GVTY55/ +RedirectTemp /19-23 https://docs.python.org/3/library/queue.html#queue.SimpleQueue.get +RedirectTemp /19-24 https://en.wikipedia.org/wiki/Race_condition +RedirectTemp /19-25 https://github.com/fluentpython/example-code-2e/commit/2c1230579db99738a5e5e6802063bda585f6476d +RedirectTemp /19-26 https://github.com/fluentpython/example-code-2e/blob/master/19-concurrency/primes/README.md +RedirectTemp /19-27 https://github.com/fluentpython/example-code-2e/blob/master/19-concurrency/primes/threads.py +RedirectTemp /19-28 https://en.wikipedia.org/wiki/Context_switch +RedirectTemp /19-29 http://www.gotw.ca/publications/concurrency-ddj.htm +RedirectTemp /19-30 https://www.ansible.com/ +RedirectTemp /19-31 https://saltproject.io/ +RedirectTemp /19-32 https://www.fabfile.org/ +RedirectTemp /19-33 https://engineering.fb.com/2016/05/27/production-engineering/python-in-production-engineering/ +RedirectTemp /19-34 https://jupyter.org/ +RedirectTemp /19-35 https://docs.bokeh.org/en/latest/index.html +RedirectTemp /19-36 https://www.tensorflow.org/ +RedirectTemp /19-37 https://pytorch.org/ +RedirectTemp /19-38 https://www.oreilly.com/radar/where-programming-ops-ai-and-the-cloud-are-headed-in-2021/ +RedirectTemp /19-39 https://www.youtube.com/watch?v=ods97a5Pzw0 +RedirectTemp /19-40 https://www.thoughtworks.com/radar/techniques/high-performance-envy-web-scale-envy +RedirectTemp /19-41 https://modwsgi.readthedocs.io/en/master/ +RedirectTemp /19-42 https://uwsgi-docs.readthedocs.io/en/latest/ +RedirectTemp /19-43 https://unit.nginx.org/ +RedirectTemp /19-44 https://www.techatbloomberg.com/blog/configuring-uwsgi-production-deployment/ +RedirectTemp /19-45 https://www.youtube.com/watch?v=p6R1h2Nn468 +RedirectTemp /19-46 https://asgi.readthedocs.io/en/latest/index.html +RedirectTemp /19-47 https://docs.celeryproject.org/en/stable/getting-started/introduction.html +RedirectTemp /19-48 https://python-rq.org/ +RedirectTemp /19-49 https://docs.celeryproject.org/en/stable/faq.html#what-kinds-of-things-should-i-use-celery-for +RedirectTemp /19-50 https://redis.io/ +RedirectTemp /19-51 https://realpython.com/intro-to-python-threading/ +RedirectTemp /19-52 https://pymotw.com/3/concurrency.html +RedirectTemp /19-53 https://www.pearson.com/us/higher-education/program/Hellmann-Python-3-Standard-Library-by-Example-The/PGM328871.html +RedirectTemp /19-54 https://docs.python.org/3/library/multiprocessing.html#programming-guidelines +RedirectTemp /19-55 https://docs.python.org/3/library/multiprocessing.html +RedirectTemp /19-56 https://www.oreilly.com/library/view/high-performance-python/9781492055013/ +RedirectTemp /19-57 https://link.springer.com/book/10.1007/978-1-4842-5793-7?error=cookies_not_supported&code=2ed5d61d-ae9f-4f3d-94ac-0f68cf45ea4f +RedirectTemp /19-58 https://www.packtpub.com/product/parallel-programming-with-python/9781783288397 +RedirectTemp /19-59 https://greenteapress.com/wp/semaphores/ +RedirectTemp /19-60 https://docs.python.org/3/c-api/init.html#thread-state-and-the-global-interpreter-lock +RedirectTemp /19-61 https://docs.python.org/3/faq/library.html#can-t-we-get-rid-of-the-global-interpreter-lock +RedirectTemp /19-62 https://www.artima.com/weblogs/viewpost.jsp?thread=214235 +RedirectTemp /19-63 http://jessenoller.com/blog/2009/02/01/python-threads-and-the-global-interpreter-lock +RedirectTemp /19-64 https://realpython.com/products/cpython-internals-book/ +RedirectTemp /19-65 http://www.dabeaz.com/GIL/ +RedirectTemp /19-66 http://www.dabeaz.com/python/UnderstandingGIL.pdf +RedirectTemp /19-67 https://bugs.python.org/issue7946#msg223110 +RedirectTemp /19-68 https://bugs.python.org/issue7946 +RedirectTemp /19-69 https://www.fullstackpython.com/ +RedirectTemp /19-70 https://www.oreilly.com/library/view/high-performance-python/9781492055013/ +RedirectTemp /19-71 https://www.packtpub.com/product/parallel-programming-with-python/9781783288397 +RedirectTemp /19-72 https://www.packtpub.com/product/distributed-computing-with-python/9781785889691 +RedirectTemp /19-73 https://towardsdatascience.com/python-performance-and-gpus-1be860ffd58d?gi=a7d537cc2fb4 +RedirectTemp /19-74 https://instagram-engineering.com/web-service-efficiency-at-instagram-with-python-4976d078e366?gi=12a441991c88 +RedirectTemp /19-75 https://www.oreilly.com/library/view/architecture-patterns-with/9781492052197/ +RedirectTemp /19-76 https://www.cosmicpython.com/ +RedirectTemp /19-77 https://pypi.org/project/lelo/ +RedirectTemp /19-78 https://github.com/npryce/python-parallelize +RedirectTemp /19-79 https://github.com/ericsnowcurrently/multi-core-python/wiki +RedirectTemp /19-80 https://gist.github.com/markshannon/79cace3656b40e21b7021504daee950c +RedirectTemp /19-81 https://mail.python.org/archives/list/python-dev@python.org/message/YOOQZCFOKEPQ24YHWWLQSJ3RCXFMS7D7/ +RedirectTemp /19-82 https://en.wikipedia.org/wiki/Communicating_sequential_processes +RedirectTemp /19-83 https://github.com/stackless-dev/stackless/wiki +RedirectTemp /19-84 https://www.eveonline.com +RedirectTemp /19-85 https://www.ccpgames.com/ +RedirectTemp /19-86 https://stackless.readthedocs.io/en/3.6-slp/stackless-python.html#history +RedirectTemp /19-87 https://doc.pypy.org/en/latest/stackless.html +RedirectTemp /19-88 https://greenlet.readthedocs.io/en/latest/ +RedirectTemp /19-89 http://www.gevent.org/ +RedirectTemp /19-90 http://thespianpy.com/doc/ +RedirectTemp /19-91 https://pykka.readthedocs.io/en/latest/ +RedirectTemp /19-92 https://www.manning.com/books/rabbitmq-in-action +RedirectTemp /19-93 https://pragprog.com/titles/pb7con/seven-concurrency-models-in-seven-weeks/ +RedirectTemp /19-94 https://en.wikipedia.org/wiki/OpenCL +RedirectTemp /19-95 https://media.pragprog.com/titles/pb7con/Bonus_Chapter.pdf +RedirectTemp /19-96 https://martinfowler.com/ +RedirectTemp /19-97 https://martinfowler.com/articles/patterns-of-distributed-systems/ +RedirectTemp /19-98 https://www.oreilly.com/library/view/designing-data-intensive-applications/9781491903063/ +RedirectTemp /19-99 https://www.oreilly.com/library/view/oscon-2016-video/9781491965153/video247021.html +RedirectTemp /19-100 https://www.oreilly.com/library/view/designing-for-scalability/9781449361556/ +RedirectTemp /19-101 https://www.thoughtworks.com/radar/techniques/high-performance-envy-web-scale-envy +RedirectTemp /19-102 https://en.wikipedia.org/wiki/KISS_principle +RedirectTemp /19-103 https://www.usenix.org/conference/hotos15/workshop-program/presentation/mcsherry +############################################################ 20 +RedirectTemp /20-1 https://www.artima.com/weblogs/viewpost.jsp?thread=299551 +RedirectTemp /20-2 https://docs.python.org/3/library/http.server.html +RedirectTemp /20-3 https://www.youtube.com/watch?v=A9e9Cy1UkME +RedirectTemp /20-4 https://www.cia.gov/the-world-factbook/ +RedirectTemp /20-5 https://docs.python-requests.org/en/latest/ +RedirectTemp /20-6 https://docs.python.org/3.10/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor +RedirectTemp /20-7 https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.as_completed +RedirectTemp /20-8 https://docs.python.org/3/library/concurrent.futures.html +RedirectTemp /20-9 https://docs.python.org/3.10/library/concurrent.futures.html#concurrent.futures.Executor +RedirectTemp /20-10 https://github.com/fluentpython/example-code-2e/blob/master/20-executors/getflags/flags2_common.py +RedirectTemp /20-11 https://github.com/noamraph/tqdm +RedirectTemp /20-12 https://www.youtube.com/watch?v=M8Z65tAl5l4 +RedirectTemp /20-13 https://github.com/noamraph/tqdm/blob/master/README.md +RedirectTemp /20-14 https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.as_completed +RedirectTemp /20-15 https://docs.python.org/3/library/asyncio-task.html#asyncio.as_completed +RedirectTemp /20-16 https://www.cloudflare.com/ +RedirectTemp /20-17 https://github.com/fluentpython/example-code-2e/tree/master/20-executors/getflags +RedirectTemp /20-18 https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/418 +RedirectTemp /20-19 https://en.wikipedia.org/wiki/Embarrassingly_parallel +RedirectTemp /20-20 https://pyvideo.org/video/480/pyconau-2010--the-future-is-soon/ +RedirectTemp /20-21 http://www.dabeaz.com/coroutines/ +RedirectTemp /20-22 https://en.wikipedia.org/wiki/POSIX_Threads +RedirectTemp /20-23 https://en.wikipedia.org/wiki/C_dynamic_memory_allocation +RedirectTemp /20-24 https://pragprog.com/titles/pb7con/seven-concurrency-models-in-seven-weeks/ +RedirectTemp /20-25 https://hexdocs.pm/ecto/getting-started.html +############################################################ 21 +RedirectTemp /21-1 https://docs.python.org/3/library/asyncio.html +RedirectTemp /21-2 https://bugs.python.org/issue43216 +RedirectTemp /21-3 https://bugs.python.org/issue36921 +RedirectTemp /21-4 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.getaddrinfo +RedirectTemp /21-5 https://docs.python.org/3/library/socket.html#socket.getaddrinfo +RedirectTemp /21-6 https://docs.python.org/3.10/library/asyncio-eventloop.html#asyncio.get_event_loop +RedirectTemp /21-7 https://www.python.org/dev/peps/pep-0492/#await-expression +RedirectTemp /21-8 https://www.fluentpython.com/extra/classic-coroutines/#yield_from_meaning_sec +RedirectTemp /21-9 https://github.com/fluentpython/example-code-2e/tree/master/20-executors/getflags +RedirectTemp /21-10 https://magicstack.github.io/asyncpg/current/ +RedirectTemp /21-11 https://magicstack.github.io/asyncpg/current/api/index.html#transactions +RedirectTemp /21-12 https://magicstack.github.io/asyncpg/current/api/index.html#transactions +RedirectTemp /21-13 https://github.com/MagicStack/asyncpg/blob/4d39a05268ce4cc01b00458223a767542da048b8/asyncpg/transaction.py#L57 +RedirectTemp /21-14 https://magicstack.github.io/asyncpg/current/usage.html#connection-pools +RedirectTemp /21-15 https://gist.github.com/jboner/2841832 +RedirectTemp /21-16 https://en.wikipedia.org/wiki/Network-attached_storage +RedirectTemp /21-17 https://en.wikipedia.org/wiki/Semaphore_(programming) +RedirectTemp /21-18 https://en.wikipedia.org/wiki/Semaphore_(programming) +RedirectTemp /21-19 https://groups.google.com/forum/#!msg/python-tulip/PdAEtwpaJHs/7fqb-Qj2zJoJ +RedirectTemp /21-20 https://web.archive.org/web/20151209151711/http://tritarget.org/blog/2012/11/28/the-pyramid-of-doom-a-javascript-style-trap +RedirectTemp /21-21 https://stackoverflow.com/questions/53701841/what-is-the-use-case-for-future-add-done-callback/53710563 +RedirectTemp /21-22 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor +RedirectTemp /21-23 https://motor.readthedocs.io/en/stable/ +RedirectTemp /21-24 https://emptysqua.re/blog/response-to-asynchronous-python-and-databases/ +RedirectTemp /21-25 https://docs.python.org/3/library/asyncio-stream.html#tcp-echo-server-using-streams +RedirectTemp /21-26 https://en.wikipedia.org/wiki/Phaistos_Disc +RedirectTemp /21-27 https://en.wikipedia.org/wiki/Inverted_index +RedirectTemp /21-28 https://fastapi.tiangolo.com/ +RedirectTemp /21-29 https://swagger.io/specification/ +RedirectTemp /21-30 https://asgi.readthedocs.io/en/latest/implementations.html +RedirectTemp /21-31 https://pydantic-docs.helpmanual.io/ +RedirectTemp /21-32 https://doc.traefik.io/traefik/ +RedirectTemp /21-33 https://fastapi.tiangolo.com/project-generation/ +RedirectTemp /21-34 https://fastapi.tiangolo.com/tutorial/response-model/ +RedirectTemp /21-35 https://docs.python.org/3/library/asyncio-stream.html#asyncio.start_server +RedirectTemp /21-36 https://github.com/python/typeshed/issues/5535 +RedirectTemp /21-37 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.Server.serve_forever +RedirectTemp /21-38 https://docs.python.org/3/library/asyncio-stream.html#asyncio.StreamWriter.close +RedirectTemp /21-39 https://docs.python.org/3/library/asyncio-stream.html#streamwriter +RedirectTemp /21-40 https://docs.python.org/3/library/asyncio-stream.html +RedirectTemp /21-41 https://docs.python.org/3/library/asyncio-protocol.html +RedirectTemp /21-42 https://docs.python.org/3/library/asyncio-protocol.html#tcp-echo-server +RedirectTemp /21-43 https://github.com/aio-libs/aiopg +RedirectTemp /21-44 https://docs.python.org/3/whatsnew/3.8.html#asyncio +RedirectTemp /21-45 https://datatracker.ietf.org/doc/html/rfc6761 +RedirectTemp /21-46 https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager +RedirectTemp /21-47 https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager +RedirectTemp /21-48 https://docs.python.org/3/library/asyncio-task.html#asyncio.gather +RedirectTemp /21-49 https://curio.readthedocs.io/en/latest/index.html +RedirectTemp /21-50 https://curio.readthedocs.io/en/latest/reference.html#task-groups +RedirectTemp /21-51 https://en.wikipedia.org/wiki/Structured_concurrency +RedirectTemp /21-52 https://mail.python.org/archives/list/python-dev@python.org/thread/2ORDAW74LGE3ZI2QETPJRT2ZL7MCCPG2/ +RedirectTemp /21-53 https://www.python.org/dev/peps/pep-0654/#motivation +RedirectTemp /21-54 https://curio.readthedocs.io/en/latest/reference.html#AWAIT +RedirectTemp /21-55 https://www.python-httpx.org/async/#curio +RedirectTemp /21-56 https://github.com/dabeaz/curio/tree/78bca8a6ad677ef51e1568ac7b3e51441ab49c42/examples +RedirectTemp /21-57 https://datatracker.ietf.org/doc/html/rfc8305 +RedirectTemp /21-58 https://trio.readthedocs.io/en/stable/ +RedirectTemp /21-59 https://www.youtube.com/watch?v=M-sc73Y-zQA +RedirectTemp /21-60 https://en.wikipedia.org/wiki/Technical_debt +RedirectTemp /21-61 https://www.youtube.com/watch?v=E-1Y4kSsAFc +RedirectTemp /21-62 https://github.com/dabeaz/curio +RedirectTemp /21-63 https://trio.readthedocs.io/en/stable/ +RedirectTemp /21-64 https://curio.readthedocs.io/en/latest/#curio-university +RedirectTemp /21-65 https://vorpus.org/blog/some-thoughts-on-asynchronous-api-design-in-a-post-asyncawait-world/ +RedirectTemp /21-66 https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/ +RedirectTemp /21-67 https://stackoverflow.com/questions/49482969/what-is-the-core-difference-between-asyncio-and-trio +RedirectTemp /21-68 https://docs.python.org/3/library/asyncio.html +RedirectTemp /21-69 https://bugs.python.org/issue33649 +RedirectTemp /21-70 https://docs.python.org/3/library/asyncio-dev.html +RedirectTemp /21-71 https://www.youtube.com/watch?v=iG6fr81xHKA +RedirectTemp /21-72 https://www.youtube.com/watch?v=F19R_M4Nay4 +RedirectTemp /21-73 https://asherman.io/projects/unsync.html +RedirectTemp /21-74 https://pyladies.com/ +RedirectTemp /21-75 https://www.youtube.com/watch?v=sW76-pRkZk8 +RedirectTemp /21-76 https://www.youtube.com/watch?v=Xbl7XjFYsN4 +RedirectTemp /21-77 https://www.youtube.com/watch?v=02CLD-42VdI +RedirectTemp /21-78 https://micropython.org/ +RedirectTemp /21-79 https://docs.micropython.org/en/latest/library/uasyncio.html +RedirectTemp /21-80 https://www.encode.io/articles/python-async-frameworks-beyond-developer-tribalism +RedirectTemp /21-81 https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/ +RedirectTemp /21-82 https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/ +RedirectTemp /21-83 https://github.com/MagicStack/uvloop +RedirectTemp /21-84 http://magic.io/blog/uvloop-blazing-fast-python-networking/ +RedirectTemp /21-85 https://github.com/MagicStack/httptools +RedirectTemp /21-86 https://docs.aiohttp.org/en/stable/ +RedirectTemp /21-87 https://github.com/wg/wrk +RedirectTemp /21-88 https://twistedmatrix.com/trac/ +############################################################ 22 +RedirectTemp /22-1 https://github.com/fluentpython/example-code-2e/blob/master/22-dyn-attr-prop/oscon/data/osconfeed.json +RedirectTemp /22-2 https://pypi.org/project/attrdict/ +RedirectTemp /22-3 https://pypi.org/project/addict/ +RedirectTemp /22-4 https://github.com/ActiveState/code/tree/master/recipes/Python/52308_simple_but_handy_collector_bunch_named_stuff +RedirectTemp /22-5 https://docs.python.org/3/library/types.html#types.SimpleNamespace +RedirectTemp /22-6 https://docs.python.org/3/library/argparse.html#argparse.Namespace +RedirectTemp /22-7 https://docs.python.org/3/library/multiprocessing.html#multiprocessing.managers.Namespace +RedirectTemp /22-8 https://github.com/fluentpython/example-code-2e/blob/master/22-dyn-attr-prop/oscon/schedule_v2.py +RedirectTemp /22-9 https://docs.python.org/3/library/functools.html#functools.cached_property +RedirectTemp /22-10 https://docs.python.org/3/library/functools.html#functools.cached_property +RedirectTemp /22-11 https://bugs.python.org/issue42781 +RedirectTemp /22-12 https://docs.python.org/3/howto/descriptor.html +RedirectTemp /22-13 https://github.com/python/cpython/blob/e6d0107e13ed957109e79b796984d3d026a8660d/Lib/functools.py#L926 +RedirectTemp /22-14 https://docs.python.org/3/library/threading.html#rlock-objects +RedirectTemp /22-15 https://docs.python.org/3.10/library/functools.html#functools.cached_property +RedirectTemp /22-16 https://www.wsj.com/articles/SB10001424052970203914304576627102996831200 +RedirectTemp /22-17 https://www.youtube.com/watch?v=s35rVw1zskA&feature=youtu.be +RedirectTemp /22-18 https://docs.python.org/3/library/functions.html#dir +RedirectTemp /22-19 https://github.com/python/cpython/blob/19903085c3ad7a17c8047e1556c700f2eb109931/Lib/cmd.py#L214 +RedirectTemp /22-20 https://docs.python.org/3/library/functions.html#hasattr +RedirectTemp /22-21 https://docs.python.org/3.10/reference/datamodel.html#special-method-lookup +RedirectTemp /22-22 https://docs.python.org/3/library/functions.html +RedirectTemp /22-23 https://docs.python.org/3/reference/datamodel.html#customizing-attribute-access +RedirectTemp /22-24 https://docs.python.org/3/reference/datamodel.html#special-method-lookup +RedirectTemp /22-25 https://docs.python.org/3/library/stdtypes.html#special-attributes +RedirectTemp /22-26 http://wiki.c2.com/?WelcomeVisitors +RedirectTemp /22-27 http://wiki.c2.com/?UniformAccessPrinciple +RedirectTemp /22-28 https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html +RedirectTemp /22-29 http://www.pingo.io/docs/ +RedirectTemp /22-30 https://www.drdobbs.com/javas-new-considered-harmful/184405016 +RedirectTemp /22-31 https://www.python.org/dev/peps/pep-0008/#class-names +############################################################ 23 +RedirectTemp /23-1 http://www.aleax.it/goo_pydp.pdf +RedirectTemp /23-2 https://docs.python.org/3.10/reference/datamodel.html#implementing-descriptors +RedirectTemp /23-3 https://docs.python.org/3/howto/descriptor.html +RedirectTemp /23-4 https://docs.python.org/3/howto/ +RedirectTemp /23-5 http://www.aleax.it/Python/nylug05_om.pdf +RedirectTemp /23-6 https://www.youtube.com/watch?v=VOzvpHoYQoo +RedirectTemp /23-7 https://www.python.org/dev/peps/pep-0487/#trait-descriptors +RedirectTemp /23-8 https://dreamsongs.com/RiseOfWorseIsBetter.html +RedirectTemp /23-9 http://web.archive.org/web/20031002184114/www.amk.ca/python/writing/warts.html +RedirectTemp /23-10 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this +RedirectTemp /23-11 http://python-history.blogspot.com/2009/02/adding-support-for-user-defined-classes.html +############################################################ 24 +RedirectTemp /24-1 https://docs.python.org/3/library/stdtypes.html#special-attributes +RedirectTemp /24-2 https://docs.djangoproject.com/en/3.2/topics/db/models/#meta-options +RedirectTemp /24-3 https://www.python.org/dev/peps/pep-3155/ +RedirectTemp /24-4 https://github.com/python/cpython/blob/3.9/Lib/collections/__init__.py +RedirectTemp /24-5 https://en.wikipedia.org/wiki/Tony_Hoare#Apologies_and_retractions +RedirectTemp /24-6 https://go.dev/tour/basics/12 +RedirectTemp /24-7 https://bugs.python.org/issue42102 +RedirectTemp /24-8 https://docs.python.org/3/reference/datamodel.html#object.__init_subclass__ +RedirectTemp /24-9 https://www.python.org/dev/peps/pep-0557/#abstract +RedirectTemp /24-10 https://github.com/python/cpython/blob/3.9/Lib/dataclasses.py +RedirectTemp /24-11 https://docs.python.org/3/reference/datamodel.html#creating-the-class-object +RedirectTemp /24-12 https://mail.python.org/pipermail/python-list/2002-December/134521.html +RedirectTemp /24-13 https://mail.python.org/pipermail/python-list/2002-July/162558.html +RedirectTemp /24-14 https://github.com/fluentpython/example-code/tree/master/21-class-metaprog/bulkfood +RedirectTemp /24-15 https://en.wikipedia.org/wiki/Principle_of_least_astonishment +RedirectTemp /24-16 https://docs.python.org/3/reference/datamodel.html#object.__class_getitem__ +RedirectTemp /24-17 https://en.wikipedia.org/wiki/Trait_(computer_programming) +RedirectTemp /24-18 https://en.wikipedia.org/wiki/Aspect-oriented_programming +RedirectTemp /24-19 https://dhh.dk/arc/000416.html +RedirectTemp /24-20 https://github.com/cjrh/autoslot +RedirectTemp /24-21 https://docs.python.org/3/reference/datamodel.html#customizing-class-creation +RedirectTemp /24-22 https://docs.python.org/3/library/functions.html#type +RedirectTemp /24-23 https://docs.python.org/3/library/stdtypes.html#special-attributes +RedirectTemp /24-24 https://docs.python.org/3/library/types.html +RedirectTemp /24-25 https://www.python.org/dev/peps/pep-3129/ +RedirectTemp /24-26 https://www.youtube.com/watch?v=cAGliEJV9_o +RedirectTemp /24-27 https://docs.python.org/3/library/functools.html#functools.total_ordering +RedirectTemp /24-28 https://www.python.org/download/releases/2.2.3/descrintro/ +RedirectTemp /24-29 https://github.com/lihaoyi/macropy +RedirectTemp /24-30 https://people.eecs.berkeley.edu/~bh/ss-toc2.html +# content of short.htaccess file created and managed by short.py + +# appended: 2025-05-23 15:12:13 +RedirectTemp /22 https://pythonfluente.com/2/#pattern_matching_case_study_sec +RedirectTemp /23 https://pythonfluente.com/2/#how_slicing_works +RedirectTemp /24 https://pythonfluente.com/2/#sliceable_sequence +RedirectTemp /25 https://pythonfluente.com/2/#virtual_subclass_sec +RedirectTemp /26 https://pythonfluente.com/2/#environment_class_ex +RedirectTemp /27 https://pythonfluente.com/2/#subclass_builtin_woes +RedirectTemp /28 https://pythonfluente.com/2/#slots_section +RedirectTemp /29 https://pythonfluente.com/2/#typeddict_sec +RedirectTemp /2a https://pythonfluente.com/2/#problems_annot_runtime_sec +RedirectTemp /2b https://pythonfluente.com/2/#legacy_deprecated_typing_box +RedirectTemp /2c https://pythonfluente.com/2/#positional_pattern_implement_sec diff --git a/links/short.htaccess b/links/short.htaccess index 6b09a50..86fe3e2 100644 --- a/links/short.htaccess +++ b/links/short.htaccess @@ -1 +1,14 @@ # content of short.htaccess file created and managed by short.py + +# appended: 2025-05-23 15:12:13 +RedirectTemp /22 https://pythonfluente.com/2/#pattern_matching_case_study_sec +RedirectTemp /23 https://pythonfluente.com/2/#how_slicing_works +RedirectTemp /24 https://pythonfluente.com/2/#sliceable_sequence +RedirectTemp /25 https://pythonfluente.com/2/#virtual_subclass_sec +RedirectTemp /26 https://pythonfluente.com/2/#environment_class_ex +RedirectTemp /27 https://pythonfluente.com/2/#subclass_builtin_woes +RedirectTemp /28 https://pythonfluente.com/2/#slots_section +RedirectTemp /29 https://pythonfluente.com/2/#typeddict_sec +RedirectTemp /2a https://pythonfluente.com/2/#problems_annot_runtime_sec +RedirectTemp /2b https://pythonfluente.com/2/#legacy_deprecated_typing_box +RedirectTemp /2c https://pythonfluente.com/2/#positional_pattern_implement_sec From cf3161ca006b106bfc0ba698e9135e9cdfb51e55 Mon Sep 17 00:00:00 2001 From: Luciano Ramalho Date: Wed, 4 Jun 2025 18:54:30 -0300 Subject: [PATCH 66/66] moved URL shortening code to https://github.com/pythonfluente/pythonfluente2e --- links/README.md | 54 +-- links/custom.htaccess | 1072 ----------------------------------------- links/deploy.sh | 2 - links/sample-urls.txt | 47 -- links/short.htaccess | 14 - links/short.py | 95 ---- 6 files changed, 4 insertions(+), 1280 deletions(-) delete mode 100644 links/custom.htaccess delete mode 100755 links/deploy.sh delete mode 100644 links/sample-urls.txt delete mode 100644 links/short.htaccess delete mode 100755 links/short.py diff --git a/links/README.md b/links/README.md index 2a3d80a..65749b2 100644 --- a/links/README.md +++ b/links/README.md @@ -1,52 +1,6 @@ -# Short links for URLs in the book +This file is deployed as `.htaccess` to the FPY.LI domain +to map short URLs in Fluent Python to the original URLs. -## Problem: link rot +To update it, I use tools in this other repo: -_Fluent Python, Second Edition_ has more than 1000 links to external resources. -Inevitably, some of those links will rot as time passes. -But I can't change the URLs in the print book... - -## Solution: indirection - -I replaced almost all URLs in the book with shortened versions that go through the `fpy.li` site which I control. -The site has an `.htaccess` file with *temporary* redirects. - -When I find out a link is stale, I can thange the redirect in `.htaccess` to a new target, -which may be a link to copy in the Internet Archive's -[Wayback Machine](https://archive.org/web/) -o the link in the book is back in service through the updated redirect. - - -## Help wanted - -Please report broken links as bugs in the [`FPY.LI.htaccess`](FPY.LI.htaccess) file. -Also, feel free to send pull requests with fixes to that file. -When I accept a PR, I will redeploy it to `fpy.li/.htaccess`. - - -## Details - -Almost all URLs in the book are replaced with shortened versions like -[`http://fpy.li/1-3`](http://fpy.li/1-3)—for chapter 1, link #3. - -There are also custom short URLs like -[`https://fpy.li/code`](https://fpy.li/code) which redirects to the example code repository. -I used custom short URLs for URLs with 3 or more mentions, or links to PEPs. - -Exceptions: - -- URLs with `oreilly` in them are unchanged; -- `fluentpython.com` URL (with no path) is unchanged; - -The `custom.htaccess` file contains redirects with custom names -plus numbered URLs generated from the links in each chapter in -the Second Edition in English. - -`short.htaccess` has redirects made by `short.py`, starting -with the Second Edition in Brazilian Portuguese. - -```shell -cat custom.htaccess short.htaccess > FPY.LI.htaccess -``` - -`FPY.LI.htaccess` is deployed at the root folder in `http://fpy.li`. +https://github.com/pythonfluente/pythonfluente2e diff --git a/links/custom.htaccess b/links/custom.htaccess deleted file mode 100644 index cc779db..0000000 --- a/links/custom.htaccess +++ /dev/null @@ -1,1072 +0,0 @@ -ErrorDocument 404 /404.html - -# main resources -RedirectTemp /book https://www.oreilly.com/library/view/fluent-python-2nd/9781492056348/ -RedirectTemp /code https://github.com/fluentpython/example-code-2e -RedirectTemp /home https://www.fluentpython.com/ - -# URLs mentioned at least three times -RedirectTemp /bisect https://www.fluentpython.com/extra/ordered-sequences-with-bisect/ -RedirectTemp /cardxvi https://www.python.org/dev/peps/pep-0484/#the-numeric-tower -RedirectTemp /collec https://docs.python.org/3/library/collections.html -RedirectTemp /dask https://dask.org/ -RedirectTemp /dtmodel https://docs.python.org/3/reference/datamodel.html -RedirectTemp /descr101 https://www.python.org/download/releases/2.2.3/descrintro/ -RedirectTemp /descrhow https://docs.python.org/3/howto/descriptor.html -RedirectTemp /doctest https://docs.python.org/3/library/doctest.html -RedirectTemp /effectpy https://effectivepython.com/ -RedirectTemp /fmtspec https://docs.python.org/3/library/string.html#formatspec -RedirectTemp /gunicorn https://gunicorn.org/ -RedirectTemp /hashint https://www.fluentpython.com/extra/internals-of-sets-and-dicts/ -RedirectTemp /hattingh https://www.oreilly.com/library/view/using-asyncio-in/9781492075325/ -RedirectTemp /httpx https://www.python-httpx.org/ -RedirectTemp /initvar https://docs.python.org/3/library/dataclasses.html#init-only-variables -RedirectTemp /mypy https://mypy.readthedocs.io/en/stable/ -RedirectTemp /norvigdp http://norvig.com/design-patterns/ -RedirectTemp /nsphere https://en.wikipedia.org/wiki/N-sphere -RedirectTemp /oldcoro https://www.fluentpython.com/extra/classic-coroutines/ -RedirectTemp /pandas https://pandas.pydata.org/ -RedirectTemp /pycook3 https://www.oreilly.com/library/view/python-cookbook-3rd/9781449357337/ -RedirectTemp /pynut3 https://www.oreilly.com/library/view/python-in-a/9781491913833/ -RedirectTemp /pypydif https://doc.pypy.org/en/latest/cpython_differences.html#subclasses-of-built-in-types -RedirectTemp /shed4051 https://github.com/python/typeshed/issues/4051 -RedirectTemp /specattr https://docs.python.org/3/library/stdtypes.html#special-attributes -RedirectTemp /typecoro https://docs.python.org/3.10/library/typing.html#typing.Coroutine -RedirectTemp /typing https://docs.python.org/3/library/typing.html -RedirectTemp /weakref https://www.fluentpython.com/extra/weak-references/ - -# URL added during QA of the Second Edition -RedirectTemp /bdfl https://www.artima.com/weblogs/viewpost.jsp?thread=235725 - -# Python Enhancement Proposals -RedirectTemp /pep218 https://www.python.org/dev/peps/pep-0218/ -RedirectTemp /pep227 https://www.python.org/dev/peps/pep-0227/ -RedirectTemp /pep255 https://www.python.org/dev/peps/pep-0255/ -RedirectTemp /pep342 https://www.python.org/dev/peps/pep-0342/ -RedirectTemp /pep343 https://www.python.org/dev/peps/pep-0343/ -RedirectTemp /pep357 https://www.python.org/dev/peps/pep-0357/ -RedirectTemp /pep362 https://www.python.org/dev/peps/pep-0362/ -RedirectTemp /pep371 https://www.python.org/dev/peps/pep-0371/ -RedirectTemp /pep380 https://www.python.org/dev/peps/pep-0380/ -RedirectTemp /pep393 https://www.python.org/dev/peps/pep-0393/ -RedirectTemp /pep412 https://www.python.org/dev/peps/pep-0412/ -RedirectTemp /pep442 https://www.python.org/dev/peps/pep-0442/ -RedirectTemp /pep443 https://www.python.org/dev/peps/pep-0443/ -RedirectTemp /pep448 https://www.python.org/dev/peps/pep-0448/ -RedirectTemp /pep455 https://www.python.org/dev/peps/pep-0455/ -RedirectTemp /pep456 https://www.python.org/dev/peps/pep-0456/ -RedirectTemp /pep461 https://www.python.org/dev/peps/pep-0461/ -RedirectTemp /pep465 https://www.python.org/dev/peps/pep-0465/ -RedirectTemp /pep467 https://www.python.org/dev/peps/pep-0467/ -RedirectTemp /pep482 https://www.python.org/dev/peps/pep-0482/ -RedirectTemp /pep483 https://www.python.org/dev/peps/pep-0483/ -RedirectTemp /pep484 https://www.python.org/dev/peps/pep-0484/ -RedirectTemp /pep487 https://www.python.org/dev/peps/pep-0487/ -RedirectTemp /pep492 https://www.python.org/dev/peps/pep-0492/ -RedirectTemp /pep519 https://www.python.org/dev/peps/pep-0519/ -RedirectTemp /pep525 https://www.python.org/dev/peps/pep-0525/ -RedirectTemp /pep526 https://www.python.org/dev/peps/pep-0526/ -RedirectTemp /pep528 https://www.python.org/dev/peps/pep-0528/ -RedirectTemp /pep529 https://www.python.org/dev/peps/pep-0529/ -RedirectTemp /pep530 https://www.python.org/dev/peps/pep-0530/ -RedirectTemp /pep544 https://www.python.org/dev/peps/pep-0544/ -RedirectTemp /pep554 https://www.python.org/dev/peps/pep-0554/ -RedirectTemp /pep557 https://www.python.org/dev/peps/pep-0557/ -RedirectTemp /pep560 https://www.python.org/dev/peps/pep-0560/ -RedirectTemp /pep561 https://www.python.org/dev/peps/pep-0561/ -RedirectTemp /pep563 https://www.python.org/dev/peps/pep-0563/ -RedirectTemp /pep570 https://www.python.org/dev/peps/pep-0570/ -RedirectTemp /pep572 https://www.python.org/dev/peps/pep-0572/ -RedirectTemp /pep584 https://www.python.org/dev/peps/pep-0584/ -RedirectTemp /pep585 https://www.python.org/dev/peps/pep-0585/ -RedirectTemp /pep586 https://www.python.org/dev/peps/pep-0586/ -RedirectTemp /pep589 https://www.python.org/dev/peps/pep-0589/ -RedirectTemp /pep591 https://www.python.org/dev/peps/pep-0591/ -RedirectTemp /pep593 https://www.python.org/dev/peps/pep-0593/ -RedirectTemp /pep604 https://www.python.org/dev/peps/pep-0604/ -RedirectTemp /pep612 https://www.python.org/dev/peps/pep-0612/ -RedirectTemp /pep613 https://www.python.org/dev/peps/pep-0613/ -RedirectTemp /pep616 https://www.python.org/dev/peps/pep-0616/ -RedirectTemp /pep617 https://www.python.org/dev/peps/pep-0617/ -RedirectTemp /pep618 https://www.python.org/dev/peps/pep-0618/ -RedirectTemp /pep634 https://www.python.org/dev/peps/pep-0634/ -RedirectTemp /pep635 https://www.python.org/dev/peps/pep-0635/ -RedirectTemp /pep636 https://www.python.org/dev/peps/pep-0636/ -RedirectTemp /pep638 https://www.python.org/dev/peps/pep-0638/ -RedirectTemp /pep645 https://www.python.org/dev/peps/pep-0645/ -RedirectTemp /pep646 https://www.python.org/dev/peps/pep-0646/ -RedirectTemp /pep647 https://www.python.org/dev/peps/pep-0647/ -RedirectTemp /pep649 https://www.python.org/dev/peps/pep-0649/ -RedirectTemp /pep654 https://www.python.org/dev/peps/pep-0654/ -RedirectTemp /pep655 https://www.python.org/dev/peps/pep-0655/ -RedirectTemp /pep661 https://www.python.org/dev/peps/pep-0661/ -RedirectTemp /pep3099 https://www.python.org/dev/peps/pep-3099/ -RedirectTemp /pep3102 https://www.python.org/dev/peps/pep-3102/ -RedirectTemp /pep3104 https://www.python.org/dev/peps/pep-3104/ -RedirectTemp /pep3106 https://www.python.org/dev/peps/pep-3106/ -RedirectTemp /pep3107 https://www.python.org/dev/peps/pep-3107/ -RedirectTemp /pep3115 https://www.python.org/dev/peps/pep-3115/ -RedirectTemp /pep3118 https://www.python.org/dev/peps/pep-3118/ -RedirectTemp /pep3119 https://www.python.org/dev/peps/pep-3119/ -RedirectTemp /pep3129 https://www.python.org/dev/peps/pep-3129/ -RedirectTemp /pep3132 https://www.python.org/dev/peps/pep-3132/ -RedirectTemp /pep3141 https://www.python.org/dev/peps/pep-3141/ -RedirectTemp /pep3148 https://www.python.org/dev/peps/pep-3148/ -RedirectTemp /pep3155 https://www.python.org/dev/peps/pep-3155/ -RedirectTemp /pep3333 https://www.python.org/dev/peps/pep-3333/ - -# Remaining URLs by chapter - -############################################################ p -RedirectTemp /p-1 https://mail.python.org/pipermail/python-list/2002-December/134521.html -RedirectTemp /p-2 https://docs.python.org/3.10/tutorial/ -RedirectTemp /p-3 https://docs.python.org/3/tutorial/ -RedirectTemp /p-4 https://www.oreilly.com/library/view/fluent-python-2nd/9781492056348/ -RedirectTemp /p-5 https://www.oreilly.com/online-learning/try-now.html -RedirectTemp /p-6 https://www.oreilly.com/library/view/fluent-python-2nd/9781492056348/ -RedirectTemp /p-7 https://stackoverflow.com/users/95810/alex-martelli -RedirectTemp /p-8 https://pythonpro.com.br -RedirectTemp /p-9 https://groups.google.com/g/python-brasil -RedirectTemp /p-10 https://www.coffeelab.com.br/ -RedirectTemp /p-11 https://garoa.net.br/wiki/P%C3%A1gina_principal -############################################################ a -RedirectTemp /a-1 https://groups.google.com/forum/#!topic/python-tulip/Y4bhLNbKs74 -RedirectTemp /a-2 https://docs.python.org/3/library/asyncio-eventloop.html#executor -RedirectTemp /a-3 https://www.youtube.com/watch?v=x-kB2o8sd5c -RedirectTemp /a-4 https://www.youtube.com/watch?v=OSGv2VnC0go -RedirectTemp /a-5 https://mail.python.org/pipermail/python-ideas/2015-March/032557.html -RedirectTemp /a-6 https://pypi.org/project/pep8/ -RedirectTemp /a-7 https://pypi.org/project/flake8/ -RedirectTemp /a-8 https://pypi.org/project/pyflakes/ -RedirectTemp /a-9 https://pypi.org/project/mccabe/ -RedirectTemp /a-10 https://google.github.io/styleguide/pyguide.html -RedirectTemp /a-11 https://flask.palletsprojects.com/en/1.1.x/styleguide/ -RedirectTemp /a-12 https://docs.python-guide.org/ -RedirectTemp /a-13 https://david.goodger.org/projects/pycon/2007/idiomatic/handout.html -RedirectTemp /a-14 https://docs.mongodb.com/manual/about/#about-the-documentation-process -RedirectTemp /a-15 https://blog.startifact.com/posts/older/what-is-pythonic.html -RedirectTemp /a-16 https://mail.python.org/pipermail/tutor/2003-October/thread.html#25930 -RedirectTemp /a-17 https://mail.python.org/pipermail/python-list/2003-April/192027.html -RedirectTemp /a-18 https://www.python.org/doc/essays/ -############################################################ 01 -RedirectTemp /1-1 http://hugunin.net/story_of_jython.html -RedirectTemp /1-2 https://www.oreilly.com/library/view/jython-essentials/9781449397364/ -RedirectTemp /1-3 https://docs.python.org/3/reference/lexical_analysis.html#reserved-classes-of-identifiers -RedirectTemp /1-4 https://docs.python.org/3.10/library/string.html#format-string-syntax -RedirectTemp /1-5 https://stackoverflow.com/questions/1436703/what-is-the-difference-between-str-and-repr -RedirectTemp /1-6 https://docs.python.org/3/library/stdtypes.html#truth -RedirectTemp /1-7 https://docs.python.org/3/tutorial/controlflow.html#unpacking-argument-lists -RedirectTemp /1-8 https://www.python.org/doc/humor/#the-zen-of-python -RedirectTemp /1-9 https://stackoverflow.com/users/95810/alex-martelli -RedirectTemp /1-10 https://en.wikipedia.org/wiki/Object_model -RedirectTemp /1-11 https://www.dourish.com/goodies/jargon.html -RedirectTemp /1-12 https://zopeinterface.readthedocs.io/en/latest/ -RedirectTemp /1-13 https://plone.org/ -############################################################ 02 -RedirectTemp /2-1 https://github.com/fluentpython/example-code-2e/blob/master/02-array-seq/listcomp_speed.py -RedirectTemp /2-2 https://www.python.org/dev/peps/pep-3132/ -RedirectTemp /2-3 https://stackoverflow.com/questions/68630/are-tuples-more-efficient-than-lists-in-python/22140115#22140115 -RedirectTemp /2-4 https://docs.python.org/3/whatsnew/3.5.html#pep-448-additional-unpacking-generalizations -RedirectTemp /2-5 https://docs.python.org/3/whatsnew/3.5.html#pep-448-additional-unpacking-generalizations -RedirectTemp /2-6 https://docs.python.org/3.10/whatsnew/3.10.html#pep-634-structural-pattern-matching -RedirectTemp /2-7 https://docs.python.org/3.10/whatsnew/3.10.html -RedirectTemp /2-8 https://en.wikipedia.org/wiki/Switch_statement#Fallthrough -RedirectTemp /2-9 https://en.wikipedia.org/wiki/Dangling_else -RedirectTemp /2-10 https://github.com/gvanrossum/patma/blob/3ece6444ef70122876fd9f0099eb9490a2d630df/EXAMPLES.md#case-6-a-very-deep-iterable-and-type-match-with-extraction -RedirectTemp /2-11 https://github.com/fluentpython/lispy/blob/main/original/norvig/lis.py -RedirectTemp /2-12 https://norvig.com/lispy.html -RedirectTemp /2-13 https://numpy.org/doc/stable/user/quickstart.html#indexing-slicing-and-iterating -RedirectTemp /2-14 https://pythontutor.com/ -RedirectTemp /2-15 https://en.wikipedia.org/wiki/Fluent_interface -RedirectTemp /2-16 https://docs.python.org/3/library/bisect.html#bisect.insort -RedirectTemp /2-17 https://stackoverflow.com/questions/4845418/when-should-a-memoryview-be-used/ -RedirectTemp /2-18 https://www.fluentpython.com/extra/parsing-binary-struct/ -RedirectTemp /2-19 http://www.netlib.org -RedirectTemp /2-20 https://pandas.pydata.org/ -RedirectTemp /2-21 https://scikit-learn.org/stable/ -RedirectTemp /2-22 https://docs.python.org/3/howto/sorting.html -RedirectTemp /2-23 https://www.python.org/dev/peps/pep-3132/ -RedirectTemp /2-24 https://bugs.python.org/issue2292 -RedirectTemp /2-25 https://docs.python.org/3.10/whatsnew/3.10.html#pep-634-structural-pattern-matching -RedirectTemp /2-26 https://docs.python.org/3.10/whatsnew/3.10.html -RedirectTemp /2-27 https://www.python.org/dev/peps/pep-0636/#appendix-a-quick-intro -RedirectTemp /2-28 https://eli.thegreenplace.net/2011/11/28/less-copies-in-python-with-the-buffer-protocol-and-memoryviews/ -RedirectTemp /2-29 https://jakevdp.github.io/PythonDataScienceHandbook/ -RedirectTemp /2-30 https://www.oreilly.com/library/view/python-for-data/9781491957653/ -RedirectTemp /2-31 https://www.labri.fr/perso/nrougier/from-python-to-numpy/ -RedirectTemp /2-32 https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html -RedirectTemp /2-33 http://www.fonts101.com/fonts/view/Uncategorized/34398/Dijkstra -RedirectTemp /2-34 https://docs.python.org/3/reference/datamodel.html#objects-values-and-types -RedirectTemp /2-35 https://en.wikipedia.org/wiki/Timsort -RedirectTemp /2-36 http://www.groklaw.net/pdf3/OraGoogle-1202.pdf -RedirectTemp /2-37 https://www.python.org/doc/humor/#id9 -############################################################ 03 -RedirectTemp /3-1 https://www.python.org/dev/peps/pep-0584/#motivation -RedirectTemp /3-2 https://docs.python.org/3.10/c-api/typeobj.html#Py_TPFLAGS_MAPPING -RedirectTemp /3-3 https://docs.python.org/3/glossary.html#term-hashable -RedirectTemp /3-4 https://docs.python.org/3/glossary.html#term-hashable -RedirectTemp /3-5 http://www.aleax.it/Python/accu04_Relearn_Python_alex.pdf -RedirectTemp /3-6 https://github.com/pingo-io/pingo-py -RedirectTemp /3-7 https://github.com/fluentpython/example-code-2e/blob/master/03-dict-set/missing.py -RedirectTemp /3-8 https://docs.python.org/3/library/collections.html#collections.ChainMap -RedirectTemp /3-9 https://docs.python.org/3/library/collections.html#collections.Counter -RedirectTemp /3-10 https://docs.python.org/3/library/shelve.html -RedirectTemp /3-11 https://docs.python.org/3/library/dbm.html -RedirectTemp /3-12 https://docs.python.org/3/library/pickle.html -RedirectTemp /3-13 https://nedbatchelder.com/blog/202006/pickles_nine_flaws.html -RedirectTemp /3-14 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Lib/_collections_abc.py#L813 -RedirectTemp /3-15 https://mail.python.org/pipermail/python-dev/2015-May/140003.html -RedirectTemp /3-16 https://bugs.python.org/issue18986 -RedirectTemp /3-17 https://github.com/fluentpython/example-code-2e/blob/master/03-dict-set/transformdict.py -RedirectTemp /3-18 http://gandenberger.org/2018/03/10/ordered-dicts-vs-ordereddict/ -RedirectTemp /3-19 https://www.pypy.org/ -RedirectTemp /3-20 https://morepypy.blogspot.com/2015/01/faster-more-memory-efficient-and-more.html -RedirectTemp /3-21 https://www.npopov.com/2014/12/22/PHPs-new-hashtable-implementation.html -RedirectTemp /3-22 https://www.youtube.com/watch?v=66P5FMkWoVU -RedirectTemp /3-23 https://pyvideo.org/video/276/the-mighty-dictionary-55/ -RedirectTemp /3-24 https://www.youtube.com/watch?v=p33CVV29OG8 -RedirectTemp /3-25 https://docs.python.org/3/whatsnew/3.6.html#new-dict-implementation -RedirectTemp /3-26 https://github.com/python/cpython/blob/cf7eaa4617295747ee5646c4e2b7e7a16d7c64ab/Objects/dictobject.c -RedirectTemp /3-27 https://github.com/python/cpython/blob/cf7eaa4617295747ee5646c4e2b7e7a16d7c64ab/Objects/dictnotes.txt -RedirectTemp /3-28 https://www.youtube.com/watch?v=tGAngdU_8D8 -RedirectTemp /3-29 https://speakerdeck.com/ramalho/python-set-practice-at-pycon -RedirectTemp /3-30 https://github.com/standupdev/uintset -RedirectTemp /3-31 https://spectrum.ieee.org/hans-peter-luhn-and-the-birth-of-the-hashing-algorithm -RedirectTemp /3-32 http://www.json.org/fatfree.html -RedirectTemp /3-33 https://twitter.com/mitsuhiko/status/1229385843585974272 -############################################################ 04 -RedirectTemp /4-1 https://www.slideshare.net/fischertrav/character-encoding-unicode-how-to-with-dignity-33352863 -RedirectTemp /4-2 https://pyvideo.org/video/2625/character-encoding-and-unicode-in-python/ -RedirectTemp /4-3 https://www.fluentpython.com/extra/parsing-binary-struct/ -RedirectTemp /4-4 https://www.fluentpython.com/extra/multi-character-emojis/ -RedirectTemp /4-5 https://w3techs.com/technologies/overview/character_encoding -RedirectTemp /4-6 https://docs.python.org/3/library/codecs.html#codecs.register_error -RedirectTemp /4-7 https://docs.python.org/3/library/stdtypes.html#str.isascii -RedirectTemp /4-8 https://pypi.org/project/chardet/ -RedirectTemp /4-9 https://docs.python.org/3/library/codecs.html#encodings-and-unicode -RedirectTemp /4-10 https://nedbatchelder.com/text/unipain/unipain.html -RedirectTemp /4-11 https://devblogs.microsoft.com/commandline/windows-command-line-unicode-and-utf-8-output-text-buffer/ -RedirectTemp /4-12 https://docs.python.org/3/using/cmdline.html#envvar-PYTHONIOENCODING -RedirectTemp /4-13 https://docs.python.org/3/using/cmdline.html#envvar-PYTHONLEGACYWINDOWSSTDIO -RedirectTemp /4-14 https://docs.python.org/3/library/locale.html#locale.getpreferredencoding -RedirectTemp /4-15 http://www.w3.org/TR/charmod-norm/ -RedirectTemp /4-16 https://docs.python.org/3/library/locale.html?highlight=strxfrm#locale.strxfrm -RedirectTemp /4-17 https://pypi.org/project/pyuca/ -RedirectTemp /4-18 https://github.com/jtauber/pyuca -RedirectTemp /4-19 http://www.unicode.org/Public/UCA/6.3.0/allkeys.txt -RedirectTemp /4-20 https://pypi.org/project/PyICU/ -RedirectTemp /4-21 https://docs.python.org/3.10/library/stdtypes.html#str.isalpha -RedirectTemp /4-22 https://en.wikipedia.org/wiki/Unicode_character_property#General_Category -RedirectTemp /4-23 https://en.wikipedia.org/wiki/Unicode_character_property -RedirectTemp /4-24 https://github.com/microsoft/terminal -RedirectTemp /4-25 https://docs.python.org/3/library/unicodedata.html -RedirectTemp /4-26 https://docs.python.org/3/reference/lexical_analysis.html#string-literal-concatenation -RedirectTemp /4-27 https://docs.python.org/3/library/re.html -RedirectTemp /4-28 https://nedbatchelder.com/text/unipain.html -RedirectTemp /4-29 https://www.slideshare.net/fischertrav/character-encoding-unicode-how-to-with-dignity-33352863 -RedirectTemp /4-30 https://pyvideo.org/video/2625/character-encoding-and-unicode-in-python/ -RedirectTemp /4-31 https://regebro.wordpress.com/2011/03/23/unconfusing-unicode-what-is-unicode/ -RedirectTemp /4-32 https://docs.python.org/3/howto/unicode.html -RedirectTemp /4-33 https://diveintopython3.net/strings.html -RedirectTemp /4-34 https://diveintopython3.net/ -RedirectTemp /4-35 https://finderiko.com/python-book -RedirectTemp /4-36 https://docs.python.org/3.0/whatsnew/3.0.html#text-vs-data-instead-of-unicode-vs-8-bit -RedirectTemp /4-37 https://lucumr.pocoo.org/2013/7/2/the-updated-guide-to-unicode/ -RedirectTemp /4-38 http://python-notes.curiousefficiency.org/en/latest/python3/binary_protocols.html -RedirectTemp /4-39 http://python-notes.curiousefficiency.org/en/latest/python3/text_file_processing.html -RedirectTemp /4-40 https://docs.python.org/3/library/codecs.html#standard-encodings -RedirectTemp /4-41 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Tools/unicode/listcodecs.py -RedirectTemp /4-42 https://www.oreilly.com/library/view/unicode-explained/059610121X/ -RedirectTemp /4-43 https://www.informit.com/store/unicode-demystified-a-practical-programmers-guide-to-9780201700527 -RedirectTemp /4-44 https://unicodebook.readthedocs.io/index.html -RedirectTemp /4-45 https://www.w3.org/International/wiki/Case_folding -RedirectTemp /4-46 http://www.w3.org/TR/charmod-norm/ -RedirectTemp /4-47 http://unicode.org/reports/tr15/ -RedirectTemp /4-48 http://www.unicode.org/faq/normalization.html -RedirectTemp /4-49 http://www.unicode.org/ -RedirectTemp /4-50 http://www.macchiato.com/unicode/nfc-faq -RedirectTemp /4-51 https://stories.moma.org/the-original-emoji-set-has-been-added-to-the-museum-of-modern-arts-collection-c6060e141f61?gi=c403f5a840a5 -RedirectTemp /4-52 https://emojipedia.org/ -RedirectTemp /4-53 https://blog.emojipedia.org/correcting-the-record-on-the-first-emoji-set/ -RedirectTemp /4-54 http://emojitracker.com/ -RedirectTemp /4-55 http://www.unicode.org/glossary/#plain_text -RedirectTemp /4-56 http://www.methods.co.nz/asciidoc/ -RedirectTemp /4-57 https://atlas.oreilly.com/ -############################################################ 05 -RedirectTemp /5-1 https://docs.python.org/3/library/typing.html#typing.TypedDict -RedirectTemp /5-2 https://docs.python.org/3.10/library/inspect.html#inspect.get_annotations -RedirectTemp /5-3 https://docs.python.org/3/library/typing.html#typing.get_type_hints -RedirectTemp /5-4 https://docs.python.org/3.8/library/collections.html#collections.somenamedtuple._asdict -RedirectTemp /5-5 https://www.jetbrains.com/pycharm/ -RedirectTemp /5-6 https://www.python.org/dev/peps/pep-0484/#acceptable-type-hints -RedirectTemp /5-7 https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass -RedirectTemp /5-8 https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass -RedirectTemp /5-9 https://docs.python.org/3/library/dataclasses.html -RedirectTemp /5-10 https://docs.python.org/3/library/dataclasses.html#inheritance -RedirectTemp /5-11 https://www.python.org/dev/peps/pep-0526/#class-and-instance-variable-annotations -RedirectTemp /5-12 https://dublincore.org/specifications/dublin-core/ -RedirectTemp /5-13 https://en.wikipedia.org/wiki/Dublin_Core -RedirectTemp /5-14 https://martinfowler.com/bliki/CodeSmell.html -RedirectTemp /5-15 https://martinfowler.com/books/refactoring.html -RedirectTemp /5-16 https://www.python.org/dev/peps/pep-0634/#class-patterns -RedirectTemp /5-17 https://docs.python.org/3/library/dataclasses.html -RedirectTemp /5-18 https://www.python.org/dev/peps/pep-0557/#id47 -RedirectTemp /5-19 https://www.python.org/dev/peps/pep-0557/#id48 -RedirectTemp /5-20 https://www.python.org/dev/peps/pep-0557/#id33 -RedirectTemp /5-21 https://realpython.com -RedirectTemp /5-22 https://realpython.com/python-data-classes/ -RedirectTemp /5-23 https://www.youtube.com/watch?v=T-TwcmT6Rcw -RedirectTemp /5-24 https://www.attrs.org/en/stable/ -RedirectTemp /5-25 https://glyph.twistedmatrix.com/2016/08/attrs.html -RedirectTemp /5-26 https://www.attrs.org/en/stable/why.html -RedirectTemp /5-27 https://github.com/dabeaz/cluegen -RedirectTemp /5-28 https://refactoring.guru/ -RedirectTemp /5-29 https://refactoring.guru/smells/data-class -RedirectTemp /5-30 https://web.archive.org/web/20190204130328/http://catb.org/esr/jargon/html/G/Guido.html -RedirectTemp /5-31 https://web.archive.org/web/20190211161610/http://catb.org/esr/jargon/html/index.html -RedirectTemp /5-32 https://www.attrs.org/en/stable/ -############################################################ 06 -RedirectTemp /6-1 https://www.olin.edu/faculty/profile/lynn-andrea-stein/ -RedirectTemp /6-2 https://docs.python.org/3/reference/datamodel.html#objects-values-and-types -RedirectTemp /6-3 https://pythontutor.com/ -RedirectTemp /6-4 https://docs.python.org/3/library/copy.html -RedirectTemp /6-5 https://en.wikipedia.org/wiki/Principle_of_least_astonishment -RedirectTemp /6-6 https://docs.python.org/3/reference/datamodel.html#object.%5C_%5C_del__ -RedirectTemp /6-7 https://emptysqua.re/blog/pypy-garbage-collection-and-a-deadlock/ -RedirectTemp /6-8 https://www.youtube.com/watch?v=HHFCFJSPWrI&feature=youtu.be -RedirectTemp /6-9 http://pymotw.com/3/copy/ -RedirectTemp /6-10 http://pymotw.com/3/weakref/ -RedirectTemp /6-11 https://docs.python.org/3/library/gc.html -RedirectTemp /6-12 https://devguide.python.org/garbage_collector/ -RedirectTemp /6-13 https://devguide.python.org/ -RedirectTemp /6-14 https://www.python.org/dev/peps/pep-0442/ -RedirectTemp /6-15 https://en.wikipedia.org/wiki/String_interning -RedirectTemp /6-16 https://en.wikipedia.org/wiki/Haddocks%27_Eyes -RedirectTemp /6-17 https://thp.io/2012/python-gc/python_gc_final_2012-01-22.pdf -############################################################ 07 -RedirectTemp /7-1 http://python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html -RedirectTemp /7-2 https://www.fluentpython.com/extra/function-introspection/ -RedirectTemp /7-3 https://docs.python.org/3/library/functions.html#map -RedirectTemp /7-4 https://en.wikipedia.org/wiki/Functional_programming -RedirectTemp /7-5 https://docs.python.org/3/howto/functional.html -RedirectTemp /7-6 https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy -RedirectTemp /7-7 https://docs.python.org/3/whatsnew/3.8.html#positional-only-parameters -RedirectTemp /7-8 https://docs.python.org/3/whatsnew/3.8.html#positional-only-parameters -RedirectTemp /7-9 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Lib/functools.py#L341 -RedirectTemp /7-10 https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy -RedirectTemp /7-11 https://docs.python.org/3/howto/functional.html -RedirectTemp /7-12 https://stackoverflow.com/questions/3252228/python-why-is-functools-partial-necessary -RedirectTemp /7-13 https://speakerdeck.com/ramalho/beyond-paradigms-berlin-edition -RedirectTemp /7-14 https://www.youtube.com/watch?v=bF3a2VYXxa0 -RedirectTemp /7-15 http://cs.brown.edu/~sk/Publications/Papers/Published/sk-teach-pl-post-linnaean/ -RedirectTemp /7-16 http://python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html -RedirectTemp /7-17 https://raw.githubusercontent.com/python/cpython/main/Misc/HISTORY -RedirectTemp /7-18 http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html -############################################################ 08 -RedirectTemp /8-1 https://www.python.org/dev/peps/pep-0484/#non-goals -RedirectTemp /8-2 https://github.com/python/typing/issues/182 -RedirectTemp /8-3 https://github.com/python/mypy/issues/731 -RedirectTemp /8-4 https://github.com/google/pytype -RedirectTemp /8-5 https://github.com/Microsoft/pyright -RedirectTemp /8-6 https://pyre-check.org/ -RedirectTemp /8-7 https://mypy.readthedocs.io/en/stable/introduction.html -RedirectTemp /8-8 https://mypy.readthedocs.io/en/stable/config_file.html -RedirectTemp /8-9 https://pypi.org/project/flake8/ -RedirectTemp /8-10 https://pypi.org/project/blue/ -RedirectTemp /8-11 https://pypi.org/project/black/ -RedirectTemp /8-12 https://wefearchange.org/2020/11/steeringcouncil.rst.html -RedirectTemp /8-13 https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes -RedirectTemp /8-14 https://en.wikipedia.org/wiki/Barbara_Liskov -RedirectTemp /8-15 https://en.wikipedia.org/wiki/Behavioral_subtyping -RedirectTemp /8-16 https://www.python.org/dev/peps/pep-0585/#implementation -RedirectTemp /8-17 https://docs.python.org/3/library/typing.html#module-contents -RedirectTemp /8-18 https://en.wikipedia.org/wiki/Geohash -RedirectTemp /8-19 https://en.wikipedia.org/wiki/Inverted_index -RedirectTemp /8-20 https://docs.python.org/3/library/typing.html#typing.List -RedirectTemp /8-21 https://docs.python.org/3/library/typing.html#typing.Dict -RedirectTemp /8-22 https://docs.python.org/3/library/typing.html#typing.Set -RedirectTemp /8-23 https://www.python.org/dev/peps/pep-0585/#implementation -RedirectTemp /8-24 https://docs.python.org/3/library/numbers.html -RedirectTemp /8-25 https://docs.python.org/3/library/typing.html#typing.List -RedirectTemp /8-26 https://github.com/python/typeshed -RedirectTemp /8-27 https://github.com/python/typeshed/blob/66cd36268a6a667714efaa27198a41d0d7f89477/stdlib/2and3/math.pyi#L45 -RedirectTemp /8-28 https://docs.python.org/3/library/statistics.html#statistics.mode -RedirectTemp /8-29 https://github.com/python/cpython/blob/822efa5695b5ba6c2316c1400e4e9ec2546f7ea5/Lib/statistics.py#L534 -RedirectTemp /8-30 https://github.com/python/typeshed/blob/e1e99245bb46223928eba68d4fc74962240ba5b4/stdlib/3/statistics.pyi -RedirectTemp /8-31 https://docs.python.org/3/library/statistics.html#statistics.mode -RedirectTemp /8-32 https://github.com/python/typeshed/blob/a8834fcd46339e17fc8add82b5803a1ce53d3d60/stdlib/3/statistics.pyi#L32 -RedirectTemp /8-33 https://mail.python.org/archives/list/python-dev@python.org/thread/CLVXXPQ2T2LQ5MP2Y53VVQFCXYWQJHKZ/ -RedirectTemp /8-34 https://docs.python.org/3/library/typing.html#typing.Callable -RedirectTemp /8-35 https://pypi.org/project/blue/ -RedirectTemp /8-36 https://www.python.org/dev/peps/pep-0484/#id38 -RedirectTemp /8-37 https://docs.google.com/document/d/1aXs1tpwzPjW9MdsG5dI7clNFyYayFBkcXwRDo-qvbIk/preview -RedirectTemp /8-38 https://www.oreilly.com/library/view/the-best-software/9781590595008/ -RedirectTemp /8-39 https://www.youtube.com/watch?v=YFexUDjHO6w -RedirectTemp /8-40 https://www.youtube.com/watch?v=YFexUDjHO6w&t=13m40s -RedirectTemp /8-41 https://bernat.tech/posts/the-state-of-type-hints-in-python/ -RedirectTemp /8-42 https://realpython.com/python-type-checking/ -RedirectTemp /8-43 https://cjolowicz.github.io/posts/hypermodern-python-04-typing/ -RedirectTemp /8-44 https://mypy.readthedocs.io/en/stable/index.html -RedirectTemp /8-45 https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html -RedirectTemp /8-46 https://mypy.readthedocs.io/en/stable/common_issues.html -RedirectTemp /8-47 https://github.com/typeddjango/awesome-python-typing -RedirectTemp /8-48 https://docs.python.org/3/library/functions.html#max -RedirectTemp /8-49 https://en.wikipedia.org/wiki/Linguistic_relativity -RedirectTemp /8-50 https://pypistats.org/top -RedirectTemp /8-51 https://github.com/psf/requests/issues/3855 -RedirectTemp /8-52 https://lwn.net/Articles/643399/ -RedirectTemp /8-53 https://docs.python-requests.org/en/master/api/#requests.request -RedirectTemp /8-54 https://queue.acm.org/detail.cfm?id=1039523 -############################################################ 09 -RedirectTemp /9-1 https://docs.python.org/3/library/dis.html -RedirectTemp /9-2 https://en.wikipedia.org/wiki/Memoization -RedirectTemp /9-3 https://numpy.org/doc/stable/user/basics.types.html -RedirectTemp /9-4 https://docs.python.org/3/library/functools.html#functools.singledispatch -RedirectTemp /9-5 https://github.com/GrahamDumpleton/wrapt/blob/develop/blog/README.md -RedirectTemp /9-6 https://github.com/GrahamDumpleton/wrapt/blob/develop/blog/01-how-you-implemented-your-python-decorator-is-wrong.md -RedirectTemp /9-7 https://wrapt.readthedocs.io/en/latest/ -RedirectTemp /9-8 https://www.oreilly.com/library/view/python-cookbook-3rd/9781449357337/ch09.html -RedirectTemp /9-9 https://pypi.org/project/decorator/ -RedirectTemp /9-10 https://wiki.python.org/moin/PythonDecoratorLibrary -RedirectTemp /9-11 http://web.archive.org/web/20201109032203/http://effbot.org/zone/closure.htm -RedirectTemp /9-12 https://www.python.org/dev/peps/pep-3104/ -RedirectTemp /9-13 https://www.python.org/dev/peps/pep-0227/ -RedirectTemp /9-14 https://www.python.org/dev/peps/pep-0443/ -RedirectTemp /9-15 https://www.artima.com/weblogs/viewpost.jsp?thread=101605 -RedirectTemp /9-16 https://reg.readthedocs.io/en/latest/ -RedirectTemp /9-17 https://morepath.readthedocs.io/en/latest/ -RedirectTemp /9-18 https://www.gnu.org/software/emacs/manual/html_node/elisp/Dynamic-Binding.html -RedirectTemp /9-19 http://www.paulgraham.com/rootsoflisp.html -RedirectTemp /9-20 http://www-formal.stanford.edu/jmc/recursive/recursive.html -RedirectTemp /9-21 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this -############################################################ 10 -RedirectTemp /10-1 https://en.wikipedia.org/wiki/Software_design_pattern -RedirectTemp /10-2 https://en.wikipedia.org/wiki/Iterator_pattern -RedirectTemp /10-3 https://github.com/python/mypy/issues/9397 -RedirectTemp /10-4 http://www.norvig.com/design-patterns/index.htm -RedirectTemp /10-5 https://pyvideo.org/video/1110/python-design-patterns/ -RedirectTemp /10-6 http://www.aleax.it/gdd_pydp.pdf -RedirectTemp /10-7 https://perl.plover.com/yak/design/ -RedirectTemp /10-8 https://en.wikipedia.org/wiki/Turtles_all_the_way_down -############################################################ 11 -RedirectTemp /11-1 https://blog.startifact.com/posts/older/what-is-pythonic.html -RedirectTemp /11-2 https://julien.danjou.info/guide-python-static-class-abstract-methods/ -RedirectTemp /11-3 https://docs.python.org/3/library/string.html#formatspec -RedirectTemp /11-4 https://docs.python.org/3/reference/lexical_analysis.html#f-strings -RedirectTemp /11-5 https://docs.python.org/3/library/string.html#format-string-syntax -RedirectTemp /11-6 https://docs.python.org/3/library/string.html#formatspec -RedirectTemp /11-7 https://docs.python.org/3/reference/datamodel.html#object.__hash__ -RedirectTemp /11-8 https://web.archive.org/web/20161025185040/http://pythonpaste.org/StyleGuide.html -RedirectTemp /11-9 https://docs.python.org/3/tutorial/modules.html#more-on-modules -RedirectTemp /11-10 https://docs.python.org/3/library/gettext.html#gettext.NullTranslations -RedirectTemp /11-11 https://github.com/fluentpython/example-code-2e/blob/master/11-pythonic-obj/mem_test.py -RedirectTemp /11-12 https://docs.python.org/3/reference/datamodel.html#basic-customization -RedirectTemp /11-13 http://esug.org/data/HistoricalDocuments/TheSmalltalkReport/ST07/04wo.pdf -RedirectTemp /11-14 https://www.artima.com/articles/the-simplest-thing-that-could-possibly-work#part3 -RedirectTemp /11-15 https://docs.oracle.com/javase/tutorial/essential/environment/security.html -RedirectTemp /11-16 https://github.com/fluentpython/example-code-2e/blob/master/11-pythonic-obj/private/Expose.java -RedirectTemp /11-17 https://docs.oracle.com/javase/tutorial/essential/environment/security.html -############################################################ 12 -RedirectTemp /12-1 https://en.wikipedia.org/wiki/Vector_space_model -RedirectTemp /12-2 https://pypi.org/project/gensim/ -RedirectTemp /12-3 https://docs.python.org/3/library/functions.html#enumerate -RedirectTemp /12-4 https://mathworld.wolfram.com/Hypersphere.html -RedirectTemp /12-5 https://en.wikipedia.org/wiki/Fold_(higher-order_function) -RedirectTemp /12-6 https://docs.python.org/2.5/whatsnew/pep-357.html -RedirectTemp /12-7 https://docs.python.org/3/reference/datamodel.html#special-method-names -RedirectTemp /12-8 https://en.wikipedia.org/wiki/KISS_principle -RedirectTemp /12-9 https://mail.python.org/pipermail/python-list/2000-July/046184.html -RedirectTemp /12-10 https://en.wikipedia.org/wiki/Duck_typing -RedirectTemp /12-11 https://mail.python.org/mailman/listinfo/python-list -RedirectTemp /12-12 https://mail.python.org/pipermail/python-list/2003-April/218568.html -############################################################ 13 -RedirectTemp /13-1 https://docs.python.org/3/c-api/index.html -RedirectTemp /13-2 https://docs.python.org/3/c-api/sequence.html -RedirectTemp /13-3 https://github.com/python/cpython/blob/31ceccb2c77854893f3a754aca04bedd74bedb10/Lib/_collections_abc.py#L870 -RedirectTemp /13-4 https://en.wikipedia.org/wiki/Monkey_patch -RedirectTemp /13-5 https://www.gevent.org/api/gevent.monkey.html -RedirectTemp /13-6 https://docs.python.org/3/library/random.html#random.shuffle -RedirectTemp /13-7 https://docs.python.org/3/reference/datamodel.html#emulating-container-types -RedirectTemp /13-8 https://docs.python.org/3/library/collections.html#collections.namedtuple -RedirectTemp /13-9 https://github.com/python/typeshed/blob/24afb531ffd07083d6a74be917342195062f7277/stdlib/collections/__init__.pyi -RedirectTemp /13-10 https://docs.python.org/3/glossary.html#term-abstract-base-class -RedirectTemp /13-11 https://en.wikipedia.org/wiki/Duck_typing#History -RedirectTemp /13-12 http://ptgmedia.pearsoncmg.com/images/020163371x/items/item33.html -RedirectTemp /13-13 https://docs.python.org/3/library/bisect.html#bisect.bisect -RedirectTemp /13-14 https://github.com/python/cpython/blob/main/Lib/_collections_abc.py -RedirectTemp /13-15 https://github.com/python/cpython/blob/main/Lib/abc.py -RedirectTemp /13-16 https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes -RedirectTemp /13-17 https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable -RedirectTemp /13-18 https://docs.python.org/3/library/abc.html -RedirectTemp /13-19 https://docs.python.org/dev/library/abc.html#abc.abstractmethod -RedirectTemp /13-20 https://docs.python.org/dev/library/abc.html -RedirectTemp /13-21 https://docs.python.org/3/library/os.html#os.urandom -RedirectTemp /13-22 https://github.com/python/mypy/issues/2922 -RedirectTemp /13-23 https://docs.python.org/3/library/stdtypes.html#truth -RedirectTemp /13-24 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Lib/_collections_abc.py -RedirectTemp /13-25 https://github.com/python/cpython/blob/0fbddb14dc03f61738af01af88e7d8aa8df07336/Lib/_collections_abc.py#L369 -RedirectTemp /13-26 https://github.com/python/cpython/blob/c0a9afe2ac1820409e6173bd1893ebee2cf50270/Lib/abc.py#L196 -RedirectTemp /13-27 https://bugs.python.org/issue31333 -RedirectTemp /13-28 https://github.com/python/cpython/blob/3635388f52b42e5280229104747962117104c453/Modules/_abc.c#L605 -RedirectTemp /13-29 https://github.com/python/cpython/blob/0fbddb14dc03f61738af01af88e7d8aa8df07336/Lib/_collections_abc.py#L881 -RedirectTemp /13-30 https://docs.python.org/3/library/typing.html#protocols -RedirectTemp /13-31 https://github.com/python/cpython/blob/3635388f52b42e5280229104747962117104c453/Lib/typing.py#L1751 -RedirectTemp /13-32 https://mail.python.org/archives/list/python-dev@python.org/thread/CLVXXPQ2T2LQ5MP2Y53VVQFCXYWQJHKZ/ -RedirectTemp /13-33 https://martinfowler.com/bliki/RoleInterface.html -RedirectTemp /13-34 https://en.wikipedia.org/wiki/Interface_segregation_principle -RedirectTemp /13-35 https://github.com/python/typeshed/blob/master/CONTRIBUTING.md -RedirectTemp /13-36 https://gist.github.com/asukakenji/ac8a05644a2e98f1d5ea8c299541fce9 -RedirectTemp /13-37 https://www.python.org/dev/peps/pep-0544/#runtime-checkable-decorator-and-narrowing-types-by-isinstance -RedirectTemp /13-38 https://www.python.org/dev/peps/pep-0544/#merging-and-extending-protocols -RedirectTemp /13-39 https://numpy.org/devdocs/user/basics.types.html -RedirectTemp /13-40 https://github.com/python/typeshed/blob/master/stdlib/statistics.pyi -RedirectTemp /13-41 https://bugs.python.org/issue41974 -RedirectTemp /13-42 https://glyph.twistedmatrix.com/2020/07/new-duck.html -RedirectTemp /13-43 https://glyph.twistedmatrix.com/2021/03/interfaces-and-protocols.html -RedirectTemp /13-44 https://plone.org/ -RedirectTemp /13-45 https://trypyramid.com/ -RedirectTemp /13-46 https://twistedmatrix.com/trac/ -RedirectTemp /13-47 https://www.artima.com/articles/contracts-in-python -RedirectTemp /13-48 https://martinfowler.com/bliki/DynamicTyping.html -RedirectTemp /13-49 https://martinfowler.com/bliki/RoleInterface.html -RedirectTemp /13-50 https://mypy.readthedocs.io/en/stable/protocols.html -RedirectTemp /13-51 https://pymotw.com/3/abc/index.html -RedirectTemp /13-52 https://www.python.org/dev/peps/pep-3119/ -RedirectTemp /13-53 https://www.python.org/dev/peps/pep-3141/ -RedirectTemp /13-54 https://docs.python.org/3/library/numbers.html -RedirectTemp /13-55 https://github.com/python/mypy/issues/3186 -RedirectTemp /13-56 https://stackoverflow.com/questions/69334475/how-to-hint-at-number-types-i-e-subclasses-of-number-not-numbers-themselv/69383462#69383462 -RedirectTemp /13-57 https://github.com/python/mypy/issues/3186 -RedirectTemp /13-58 https://martinfowler.com/articles/lean-inception/ -RedirectTemp /13-59 https://martinfowler.com -RedirectTemp /13-60 https://www.jetbrains.com/pycharm/ -RedirectTemp /13-61 https://wingware.com/ -RedirectTemp /13-62 https://code.visualstudio.com/ -############################################################ 14 -RedirectTemp /14-1 http://worrydream.com/EarlyHistoryOfSmalltalk/ -RedirectTemp /14-2 https://docs.python.org/3/tutorial/classes.html -RedirectTemp /14-3 https://docs.python.org/3/library/collections.html#ordereddict-examples-and-recipes -RedirectTemp /14-4 https://discuss.python.org/t/is-it-time-to-deprecate-unbound-super-methods/1833 -RedirectTemp /14-5 https://doc.pypy.org/en/latest/cpython_differences.html#subclasses-of-built-in-types -RedirectTemp /14-6 https://docs.python.org/3/library/collections.html -RedirectTemp /14-7 https://github.com/fluentpython/example-code-2e/blob/master/14-inheritance/strkeydict_dictsub.py -RedirectTemp /14-8 https://doc.pypy.org/en/latest/cpython_differences.html#subclasses-of-built-in-types -RedirectTemp /14-9 https://en.wikipedia.org/wiki/Breadth-first_search -RedirectTemp /14-10 https://www.python.org/download/releases/2.3/mro/ -RedirectTemp /14-11 https://github.com/fluentpython/example-code-2e/blob/master/14-inheritance/uppermixin.py -RedirectTemp /14-12 https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html -RedirectTemp /14-13 https://docs.python.org/3/library/collections.abc.html -RedirectTemp /14-14 https://github.com/python/cpython/blob/8ece98a7e418c3c68a4c61bc47a2d0931b59a889/Lib/collections/__init__.py#L1084 -RedirectTemp /14-15 https://docs.python.org/3/library/http.server.html -RedirectTemp /14-16 https://github.com/python/cpython/blob/17c23167942498296f0bdfffe52e72d53d66d693/Lib/http/server.py#L144 -RedirectTemp /14-17 https://github.com/python/cpython/blob/699ee016af5736ffc80f68359617611a22b72943/Lib/socketserver.py#L664 -RedirectTemp /14-18 https://docs.python.org/3/library/socketserver.html#socketserver.ForkingMixIn -RedirectTemp /14-19 https://docs.python.org/3/library/os.html#os.fork -RedirectTemp /14-20 https://en.wikipedia.org/wiki/POSIX -RedirectTemp /14-21 http://ccbv.co.uk/ -RedirectTemp /14-22 https://github.com/django/django/tree/main/django/views/generic -RedirectTemp /14-23 https://en.wikipedia.org/wiki/Template_method_pattern -RedirectTemp /14-24 https://docs.python.org/3/library/tkinter.html -RedirectTemp /14-25 https://docs.python.org/3/library/tkinter.ttk.html -RedirectTemp /14-26 https://docs.oracle.com/javase/10/docs/api/java/awt/package-tree.html -RedirectTemp /14-27 https://docs.oracle.com/javase/10/docs/api/javax/swing/package-tree.html -RedirectTemp /14-28 https://squeak.org/ -RedirectTemp /14-29 https://github.com/django/django/blob/b64db05b9cedd96905d637a2d824cbbf428e40e7/django/views/generic/list.py#L194 -RedirectTemp /14-30 https://github.com/python/cpython/blob/8ed183391241f0c73e7ba7f42b1d49fc02985f7b/Lib/tkinter/__init__.py#L2618 -RedirectTemp /14-31 https://docs.python.org/3/library/socketserver.html -RedirectTemp /14-32 https://docs.python.org/3/library/socketserver.html#socketserver.BaseServer -RedirectTemp /14-33 https://github.com/python/cpython/blob/699ee016af5736ffc80f68359617611a22b72943/Lib/socketserver.py#L153 -RedirectTemp /14-34 https://docs.python.org/3/library/typing.html#typing.final -RedirectTemp /14-35 https://docs.python.org/3/library/typing.html#typing.Final -RedirectTemp /14-36 https://docs.python.org/3/library/collections.abc.html -RedirectTemp /14-37 https://hynek.me/articles/python-subclassing-redux/ -RedirectTemp /14-38 https://www.oreilly.com/library/view/python-cookbook-3rd/9781449357337/ch08.html#super -RedirectTemp /14-39 https://rhettinger.wordpress.com/2011/05/26/super-considered-super/ -RedirectTemp /14-40 https://fuhm.net/super-harmful/ -RedirectTemp /14-41 https://stackoverflow.com/questions/30190185/how-to-use-super-with-one-argument/30190341#30190341 -RedirectTemp /14-42 https://www.artima.com/weblogs/viewpost.jsp?thread=246488 -RedirectTemp /14-43 https://www.artima.com/weblogs/viewpost.jsp?thread=281127 -RedirectTemp /14-44 https://www.artima.com/weblogs/viewpost.jsp?thread=246341 -RedirectTemp /14-45 https://www.artima.com/weblogs/viewpost.jsp?thread=246483 -RedirectTemp /14-46 https://www.artima.com/weblogs/viewpost.jsp?thread=236275 -RedirectTemp /14-47 https://www.artima.com/weblogs/viewpost.jsp?thread=236278 -RedirectTemp /14-48 https://www.artima.com/weblogs/viewpost.jsp?thread=237121 -RedirectTemp /14-49 https://python-patterns.guide/gang-of-four/composition-over-inheritance/ -RedirectTemp /14-50 https://python-patterns.guide/ -RedirectTemp /14-51 https://www.youtube.com/watch?v=3MNVP9-hglc -RedirectTemp /14-52 http://worrydream.com/EarlyHistoryOfSmalltalk/ -RedirectTemp /14-53 https://en.wikipedia.org/wiki/Polymorphism_(computer_science) -############################################################ 15 -RedirectTemp /15-1 https://www.youtube.com/watch?v=csL8DLXGNlU&t=92m5s -RedirectTemp /15-2 https://github.com/python/typeshed/blob/a8834fcd46339e17fc8add82b5803a1ce53d3d60/stdlib/2and3/builtins.pyi#L1434 -RedirectTemp /15-3 https://github.com/python/typeshed/blob/a8834fcd46339e17fc8add82b5803a1ce53d3d60/stdlib/2and3/builtins.pyi -RedirectTemp /15-4 https://twitter.com/gwidion/status/1265384692464967680 -RedirectTemp /15-5 https://pypi.org/project/pydantic/ -RedirectTemp /15-6 https://google.github.io/pytype/faq.html -RedirectTemp /15-7 https://google.github.io/pytype/faq.html -RedirectTemp /15-8 https://lxml.de/ -RedirectTemp /15-9 https://docs.python.org/3/library/xml.etree.elementtree.html -RedirectTemp /15-10 https://mypy.readthedocs.io/en/stable/common_issues.html -RedirectTemp /15-11 https://mypy.readthedocs.io/en/stable/common_issues.html#types-of-empty-collections -RedirectTemp /15-12 https://github.com/python/typing/issues/182 -RedirectTemp /15-13 https://pypi.org/project/pydantic/ -RedirectTemp /15-14 https://mypy.readthedocs.io/en/stable/type_narrowing.html#casts -RedirectTemp /15-15 https://github.com/python/cpython/blob/bee66d3cb98e740f9d8057eb7f503122052ca5d8/Lib/typing.py#L1340 -RedirectTemp /15-16 https://www.python.org/dev/peps/pep-0484/#casts -RedirectTemp /15-17 https://github.com/python/typeshed/issues/5535 -RedirectTemp /15-18 https://docs.python.org/3/library/asyncio-stream.html#tcp-echo-server-using-streams -RedirectTemp /15-19 https://github.com/python/cpython/blob/b798ab06937f8bb24b444a49dd42e11fff15e654/Lib/test/test_asyncio/test_server.py#L55 -RedirectTemp /15-20 https://en.wikipedia.org/wiki/Code_smell -RedirectTemp /15-21 https://mail.python.org/archives/list/typing-sig@python.org/message/5LCWMN2UY2UQNLC5Z47GHBZKSPZW4I63/ -RedirectTemp /15-22 https://mypy.readthedocs.io/en/stable/error_codes.html#error-codes -RedirectTemp /15-23 https://github.com/fluentpython/example-code-2e/blob/master/15-more-types/clip_annot.py -RedirectTemp /15-24 https://docs.python.org/3/library/typing.html#introspection-helpers -RedirectTemp /15-25 https://docs.python.org/3.10/library/inspect.html#inspect.get_annotations -RedirectTemp /15-26 https://www.python.org/dev/peps/pep-0563/#abstract -RedirectTemp /15-27 https://mail.python.org/archives/list/python-dev@python.org/message/ZBJ7MD6CSGM6LZAOTET7GXAVBZB7O77O/ -RedirectTemp /15-28 https://docs.python.org/3.10/howto/annotations.html -RedirectTemp /15-29 https://docs.python.org/3/library/typing.html#user-defined-generic-types -RedirectTemp /15-30 https://github.com/python/typeshed/blob/bfc83c365a0b26ab16586beac77ff16729d0e473/stdlib/builtins.pyi#L743 -RedirectTemp /15-31 https://docs.python.org/3.10/library/typing.html#typing.FrozenSet -RedirectTemp /15-32 https://docs.python.org/3.10/library/typing.html#typing.Generator -RedirectTemp /15-33 https://docs.python.org/3.10/library/typing.html#typing.AsyncGenerator -RedirectTemp /15-34 https://github.com/python/cpython/blob/46b16d0bdbb1722daed10389e27226a2370f1635/Lib/typing.py#L1786 -RedirectTemp /15-35 https://github.com/python/typeshed/blob/2a9f081abbf01134e4e04ced6a750107db904d70/stdlib/builtins.pyi#L239 -RedirectTemp /15-36 https://www.oreilly.com/library/view/robust-python/9781098100650/ -RedirectTemp /15-37 https://www.python.org/dev/peps/pep-0484/#covariance-and-contravariance -RedirectTemp /15-38 https://mypy.readthedocs.io/en/stable/generics.html#variance-of-generic-types -RedirectTemp /15-39 https://mypy.readthedocs.io/en/stable/common_issues.html#variance -RedirectTemp /15-40 https://www.artima.com/weblogs/viewpost.jsp?thread=85551 -RedirectTemp /15-41 https://dl.acm.org/action/cookieAbsent -RedirectTemp /15-42 http://bracha.org/pluggableTypesPosition.pdf -RedirectTemp /15-43 https://www.researchgate.net/publication/213886116_Static_Typing_Where_Possible_Dynamic_Typing_When_Needed_The_End_of_the_Cold_War_Between_Programming_Languages -RedirectTemp /15-44 https://www.atomickotlin.com/atomickotlin/ -RedirectTemp /15-45 https://www.informit.com/store/effective-java-9780134685991 -RedirectTemp /15-46 https://www.manning.com/books/programming-with-types -RedirectTemp /15-47 https://www.oreilly.com/library/view/programming-typescript/9781492037644/ -RedirectTemp /15-48 https://www.informit.com/store/dart-programming-language-9780321927705 -RedirectTemp /15-49 https://www.yodaiken.com/2017/09/15/bad-ideas-in-type-theory/ -RedirectTemp /15-50 https://www.yodaiken.com/2017/11/30/types-considered-harmful-ii/ -RedirectTemp /15-51 https://web.archive.org/web/20071010002142/http://weblogs.java.net/blog/arnold/archive/2005/06/generics_consid_1.html -RedirectTemp /15-52 https://github.com/python/cpython/blob/3e7ee02327db13e4337374597cdc4458ecb9e3ad/Lib/asyncio/trsock.py#L5 -RedirectTemp /15-53 https://www.python.org/dev/peps/pep-0484/#covariance-and-contravariance -############################################################ 16 -RedirectTemp /16-1 http://www.gotw.ca/publications/c_family_interview.htm -RedirectTemp /16-2 https://docs.python.org/3/reference/expressions.html#unary-arithmetic-and-bitwise-operations -RedirectTemp /16-3 https://docs.python.org/3/reference/datamodel.html#object.__neg__ -RedirectTemp /16-4 https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#boolean-indexing -RedirectTemp /16-5 https://docs.python.org/3/library/collections.html#collections.Counter -RedirectTemp /16-6 https://docs.python.org/3/reference/datamodel.html#emulating-container-types -RedirectTemp /16-7 https://docs.python.org/3/library/numbers.html#implementing-the-arithmetic-operations -RedirectTemp /16-8 https://www.fluentpython.com/lingo/#fail-fast -RedirectTemp /16-9 https://github.com/python/cpython/blob/0bbf30e2b910bc9c5899134ae9d73a8df968da35/Objects/typeobject.c#L4598 -RedirectTemp /16-10 https://neopythonic.blogspot.com/2019/03/why-operators-are-useful.html -RedirectTemp /16-11 https://treyhunner.com/2019/03/python-deep-comparisons-and-code-readability/ -RedirectTemp /16-12 https://docs.python.org/3/library/numbers.html#implementing-the-arithmetic-operations -RedirectTemp /16-13 https://docs.python.org/3/library/pathlib.html -RedirectTemp /16-14 https://pypi.org/project/scapy/ -RedirectTemp /16-15 https://scapy.readthedocs.io/en/latest/usage.html#stacking-layers -RedirectTemp /16-16 https://docs.python.org/3/library/functools.html#functools.total_ordering -RedirectTemp /16-17 https://wiki.illinois.edu//wiki/download/attachments/273416327/ingalls.pdf -RedirectTemp /16-18 https://wiki.illinois.edu//wiki/download/attachments/273416327/double-dispatch.pdf -RedirectTemp /16-19 http://www.gotw.ca/publications/c_family_interview.htm -RedirectTemp /16-20 http://www.gotw.ca/publications/c_family_interview.htm -RedirectTemp /16-21 https://doc.rust-lang.org/std/ops/index.html -RedirectTemp /16-22 https://www.fluentpython.com/lingo/#lazy -############################################################ 17 -RedirectTemp /17-1 http://www.paulgraham.com/icad.html -RedirectTemp /17-2 https://en.wikipedia.org/wiki/Sentinel_value -RedirectTemp /17-3 https://docs.python.org/3.10/library/functions.html#iter -RedirectTemp /17-4 https://docs.python.org/3.10/library/functions.html#iter -RedirectTemp /17-5 https://github.com/python/cpython/blob/b1930bf75f276cd7ca08c4455298128d89adf7d1/Lib/_collections_abc.py#L271 -RedirectTemp /17-6 https://github.com/python/cpython/blob/main/Lib/types.py#L6 -RedirectTemp /17-7 https://en.wikipedia.org/wiki/CLU_(programming_language) -RedirectTemp /17-8 https://docs.python.org/3/glossary.html -RedirectTemp /17-9 https://docs.python.org/3/glossary.html#term-generator-iterator -RedirectTemp /17-10 https://docs.python.org/3/glossary.html#term-generator-expression -RedirectTemp /17-11 https://marc.info/?l=python-list&m=141826925106951&w=2 -RedirectTemp /17-12 https://docs.python.org/3/library/os.html#os.walk -RedirectTemp /17-13 https://docs.python.org/3/library/itertools.html -RedirectTemp /17-14 https://docs.python.org/3/library/exceptions.html#exception-hierarchy -RedirectTemp /17-15 https://en.wikipedia.org/wiki/Depth-first_search -RedirectTemp /17-16 https://docs.python.org/3.10/library/typing.html#typing.TypeAlias -RedirectTemp /17-17 https://docs.python.org/3/library/typing.html#typing.Generator -RedirectTemp /17-18 http://www.dabeaz.com/coroutines/Coroutines.pdf -RedirectTemp /17-19 http://www.dabeaz.com/coroutines/Coroutines.pdf -RedirectTemp /17-20 https://mail.python.org/pipermail/python-ideas/2009-April/003841.html -RedirectTemp /17-21 https://mail.python.org/pipermail/python-ideas/2009-April/003912.html -RedirectTemp /17-22 https://docs.python.org/3/library/exceptions.html#StopIteration -RedirectTemp /17-23 https://docs.python.org/3/reference/expressions.html#yield-expressions -RedirectTemp /17-24 https://docs.python.org/3/reference/index.html -RedirectTemp /17-25 https://github.com/python/cpython/blob/6f743e7a4da904f61dfa84cc7d7385e4dcc79ac5/Lib/typing.py#L2060 -RedirectTemp /17-26 http://catb.org/~esr/jargon/html/G/grok.html -RedirectTemp /17-27 https://docs.python.org/3/reference/expressions.html#yieldexpr -RedirectTemp /17-28 https://docs.python.org/3/library/itertools.html -RedirectTemp /17-29 https://docs.python.org/3/library/itertools.html#itertools-recipes -RedirectTemp /17-30 https://more-itertools.readthedocs.io/en/stable/index.html -RedirectTemp /17-31 https://rittau.org/2006/11/java-iterators-are-not-iterable/ -RedirectTemp /17-32 https://docs.python.org/3/whatsnew/3.3.html#pep-380-syntax-for-delegating-to-a-subgenerator -RedirectTemp /17-33 http://www.dabeaz.com/generators/ -RedirectTemp /17-34 http://www.dabeaz.com/coroutines/ -RedirectTemp /17-35 https://archive.org/details/pyvideo_213___pycon-2009-a-curious-course-on-coroutines-and-concurrency-part-1-of-3 -RedirectTemp /17-36 https://archive.org/details/pyvideo_215___pycon-2009-a-curious-course-on-coroutines-and-concurrency-part-2-of-3 -RedirectTemp /17-37 https://archive.org/details/pyvideo_214___pycon-2009-a-curious-course-on-coroutines-and-concurrency-part-3-of-3 -RedirectTemp /17-38 http://www.dabeaz.com/finalgenerator/ -RedirectTemp /17-39 https://web.archive.org/web/20200218150637/http://seriously.dontusethiscode.com/2013/05/01/greedy-coroutine.html -RedirectTemp /17-40 https://effectivepython.com/ -RedirectTemp /17-41 https://effectivepython.com/2015/03/10/consider-coroutines-to-run-many-functions-concurrently -RedirectTemp /17-42 https://en.wikipedia.org/wiki/Conway's_Game_of_Life -RedirectTemp /17-43 https://gist.github.com/ramalho/da5590bc38c973408839 -RedirectTemp /17-44 https://gist.github.com/ramalho/da5590bc38c973408839 -RedirectTemp /17-45 https://journal.code4lib.org/articles/4893 -RedirectTemp /17-46 https://github.com/fluentpython/isis2json -RedirectTemp /17-47 https://github.com/fluentpython/isis2json/blob/master/README.rst -############################################################ 18 -RedirectTemp /18-1 https://pyvideo.org/video/1669/keynote-3/ -RedirectTemp /18-2 https://docs.python.org/3/library/sqlite3.html#using-the-connection-as-a-context-manager -RedirectTemp /18-3 https://docs.python.org/3/library/threading.html#using-locks-conditions-and-semaphores-in-the-with-statement -RedirectTemp /18-4 https://docs.python.org/3/library/decimal.html#decimal.localcontext -RedirectTemp /18-5 https://docs.python.org/3/library/unittest.mock.html#patch -RedirectTemp /18-6 https://docs.python.org/3/library/contextlib.html#contextlib.redirect_stdout -RedirectTemp /18-7 https://docs.python.org/3/library/sys.html#sys.exc_info -RedirectTemp /18-8 https://en.wikipedia.org/wiki/LL_parser -RedirectTemp /18-9 https://docs.python.org/3/library/contextlib.html -RedirectTemp /18-10 https://github.com/python/cpython/blob/8afab2ebbc1b343cd88d058914cf622fe687a2be/Lib/contextlib.py#L123 -RedirectTemp /18-11 https://www.zopatista.com/python/2013/11/26/inplace-file-rewriting/ -RedirectTemp /18-12 https://docs.python.org/3/library/fileinput.html#fileinput.input -RedirectTemp /18-13 https://www.zopatista.com/python/2013/11/26/inplace-file-rewriting/ -RedirectTemp /18-14 https://en.wikipedia.org/wiki/Euclidean_algorithm -RedirectTemp /18-15 https://github.com/fluentpython/example-code-2e/tree/master/18-with-match/lispy/py3.10/ -RedirectTemp /18-16 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/original/lispy.py -RedirectTemp /18-17 https://github.com/fluentpython/example-code-2e/blob/6527037ae7319ba370a1ee2d9fe79214d0ed9452/18-with-match/lispy/py3.10/lis.py#L35 -RedirectTemp /18-18 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/py3.10/examples_test.py -RedirectTemp /18-19 https://github.com/python/typeshed/issues/6042 -RedirectTemp /18-20 https://github.com/fluentpython/lispy/tree/main/mylis -RedirectTemp /18-21 https://github.com/fluentpython/example-code-2e/blob/00e4741926e1b771ee7c753148b1415c0bd12e39/02-array-seq/lispy/py3.10/examples_test.py -RedirectTemp /18-22 https://mitpress.mit.edu/sites/default/files/sicp/index.html -RedirectTemp /18-23 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/py3.10/examples_test.py -RedirectTemp /18-24 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/py3.10/lis.py -RedirectTemp /18-25 https://www.python.org/dev/peps/pep-0634/#or-patterns -RedirectTemp /18-26 https://en.wikipedia.org/wiki/Lambda#Character_encodings -RedirectTemp /18-27 https://docs.python.org/3/reference/compound_stmts.html -RedirectTemp /18-28 https://docs.python.org/3/glossary.html#term-eafp -RedirectTemp /18-29 https://speakerdeck.com/pyconslides/pycon-keynote-python-is-awesome-by-raymond-hettinger?slide=21 -RedirectTemp /18-30 https://docs.python.org/3/reference/compound_stmts.html -RedirectTemp /18-31 https://stackoverflow.com/questions/16138232/is-it-a-good-practice-to-use-try-except-else-in-python -RedirectTemp /18-32 https://docs.python.org/3/library/stdtypes.html#typecontextmanager -RedirectTemp /18-33 https://docs.python.org/3/reference/datamodel.html#with-statement-context-managers -RedirectTemp /18-34 https://speakerdeck.com/pyconslides/pycon-keynote-python-is-awesome-by-raymond-hettinger?slide=21 -RedirectTemp /18-35 https://speakerdeck.com/pyconslides/transforming-code-into-beautiful-idiomatic-python-by-raymond-hettinger-1?slide=34 -RedirectTemp /18-36 https://preshing.com/20110920/the-python-with-statement-by-example/ -RedirectTemp /18-37 https://www.rath.org/on-the-beauty-of-pythons-exitstack.html -RedirectTemp /18-38 https://norvig.com/lispy.html -RedirectTemp /18-39 https://norvig.com/lispy2.html -RedirectTemp /18-40 https://github.com/norvig/pytudes -RedirectTemp /18-41 https://github.com/fluentpython/lispy -RedirectTemp /18-42 https://racket-lang.org/ -RedirectTemp /18-43 https://pyvideo.org/video/1669/keynote-3/ -RedirectTemp /18-44 https://en.wikipedia.org/wiki/Tail_call -RedirectTemp /18-45 https://2ality.com/2015/06/tail-call-optimization.html -RedirectTemp /18-46 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/original/lis.py -RedirectTemp /18-47 https://github.com/fluentpython/example-code-2e/blob/master/18-with-match/lispy/original/lispy.py -RedirectTemp /18-48 http://neopythonic.blogspot.com/2009/04/final-words-on-tail-calls.html -RedirectTemp /18-49 https://webkit.org/blog/6240/ecmascript-6-proper-tail-calls-in-webkit/ -RedirectTemp /18-50 http://kangax.github.io/compat-table/es6/ -RedirectTemp /18-51 https://world.hey.com/mgmarlow/what-happened-to-proper-tail-calls-in-javascript-5494c256 -RedirectTemp /18-52 http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html -RedirectTemp /18-53 https://github.com/fluentpython/lispy/blob/main/mylis/mylis_2/lis.py -RedirectTemp /18-54 https://github.com/fluentpython/lispy/tree/main/mylis -############################################################ 19 -RedirectTemp /19-1 https://go.dev/blog/waza-talk -RedirectTemp /19-2 https://en.wikipedia.org/wiki/Graphics_processing_unit -RedirectTemp /19-3 https://docs.python.org/3/library/sys.html#sys.getswitchinterval -RedirectTemp /19-4 https://docs.python.org/3/library/sys.html#sys.setswitchinterval -RedirectTemp /19-5 https://en.wikipedia.org/wiki/System_call -RedirectTemp /19-6 https://mail.python.org/pipermail/python-dev/2009-October/093356.html -RedirectTemp /19-7 http://www.dabeaz.com/finalgenerator/ -RedirectTemp /19-8 https://docs.python.org/3/library/threading.html#thread-objects -RedirectTemp /19-9 https://www.pypy.org/ -RedirectTemp /19-10 https://mail.python.org/pipermail/python-list/2009-February/675659.html -RedirectTemp /19-11 https://en.wikipedia.org/wiki/Braille_Patterns -RedirectTemp /19-12 https://docs.python.org/3/library/multiprocessing.shared_memory.html -RedirectTemp /19-13 https://docs.python.org/3/library/multiprocessing.shared_memory.html#multiprocessing.shared_memory.ShareableList -RedirectTemp /19-14 https://greenlet.readthedocs.io/en/latest/ -RedirectTemp /19-15 https://docs.sqlalchemy.org/en/14/changelog/migration_14.html#asynchronous-io-support-for-core-and-orm -RedirectTemp /19-16 https://docs.sqlalchemy.org/en/14/orm/extensions/asyncio.html -RedirectTemp /19-17 http://www.gevent.org/ -RedirectTemp /19-18 https://github.com/gevent/gevent/wiki/Projects -RedirectTemp /19-19 https://docs.python.org/3/library/concurrent.futures.html#processpoolexecutor-example -RedirectTemp /19-20 https://github.com/python/asyncio/issues/284 -RedirectTemp /19-21 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor -RedirectTemp /19-22 https://mail.python.org/archives/list/python-dev@python.org/message/JBYXQH3NV3YBF7P2HLHB5CD6V3GVTY55/ -RedirectTemp /19-23 https://docs.python.org/3/library/queue.html#queue.SimpleQueue.get -RedirectTemp /19-24 https://en.wikipedia.org/wiki/Race_condition -RedirectTemp /19-25 https://github.com/fluentpython/example-code-2e/commit/2c1230579db99738a5e5e6802063bda585f6476d -RedirectTemp /19-26 https://github.com/fluentpython/example-code-2e/blob/master/19-concurrency/primes/README.md -RedirectTemp /19-27 https://github.com/fluentpython/example-code-2e/blob/master/19-concurrency/primes/threads.py -RedirectTemp /19-28 https://en.wikipedia.org/wiki/Context_switch -RedirectTemp /19-29 http://www.gotw.ca/publications/concurrency-ddj.htm -RedirectTemp /19-30 https://www.ansible.com/ -RedirectTemp /19-31 https://saltproject.io/ -RedirectTemp /19-32 https://www.fabfile.org/ -RedirectTemp /19-33 https://engineering.fb.com/2016/05/27/production-engineering/python-in-production-engineering/ -RedirectTemp /19-34 https://jupyter.org/ -RedirectTemp /19-35 https://docs.bokeh.org/en/latest/index.html -RedirectTemp /19-36 https://www.tensorflow.org/ -RedirectTemp /19-37 https://pytorch.org/ -RedirectTemp /19-38 https://www.oreilly.com/radar/where-programming-ops-ai-and-the-cloud-are-headed-in-2021/ -RedirectTemp /19-39 https://www.youtube.com/watch?v=ods97a5Pzw0 -RedirectTemp /19-40 https://www.thoughtworks.com/radar/techniques/high-performance-envy-web-scale-envy -RedirectTemp /19-41 https://modwsgi.readthedocs.io/en/master/ -RedirectTemp /19-42 https://uwsgi-docs.readthedocs.io/en/latest/ -RedirectTemp /19-43 https://unit.nginx.org/ -RedirectTemp /19-44 https://www.techatbloomberg.com/blog/configuring-uwsgi-production-deployment/ -RedirectTemp /19-45 https://www.youtube.com/watch?v=p6R1h2Nn468 -RedirectTemp /19-46 https://asgi.readthedocs.io/en/latest/index.html -RedirectTemp /19-47 https://docs.celeryproject.org/en/stable/getting-started/introduction.html -RedirectTemp /19-48 https://python-rq.org/ -RedirectTemp /19-49 https://docs.celeryproject.org/en/stable/faq.html#what-kinds-of-things-should-i-use-celery-for -RedirectTemp /19-50 https://redis.io/ -RedirectTemp /19-51 https://realpython.com/intro-to-python-threading/ -RedirectTemp /19-52 https://pymotw.com/3/concurrency.html -RedirectTemp /19-53 https://www.pearson.com/us/higher-education/program/Hellmann-Python-3-Standard-Library-by-Example-The/PGM328871.html -RedirectTemp /19-54 https://docs.python.org/3/library/multiprocessing.html#programming-guidelines -RedirectTemp /19-55 https://docs.python.org/3/library/multiprocessing.html -RedirectTemp /19-56 https://www.oreilly.com/library/view/high-performance-python/9781492055013/ -RedirectTemp /19-57 https://link.springer.com/book/10.1007/978-1-4842-5793-7?error=cookies_not_supported&code=2ed5d61d-ae9f-4f3d-94ac-0f68cf45ea4f -RedirectTemp /19-58 https://www.packtpub.com/product/parallel-programming-with-python/9781783288397 -RedirectTemp /19-59 https://greenteapress.com/wp/semaphores/ -RedirectTemp /19-60 https://docs.python.org/3/c-api/init.html#thread-state-and-the-global-interpreter-lock -RedirectTemp /19-61 https://docs.python.org/3/faq/library.html#can-t-we-get-rid-of-the-global-interpreter-lock -RedirectTemp /19-62 https://www.artima.com/weblogs/viewpost.jsp?thread=214235 -RedirectTemp /19-63 http://jessenoller.com/blog/2009/02/01/python-threads-and-the-global-interpreter-lock -RedirectTemp /19-64 https://realpython.com/products/cpython-internals-book/ -RedirectTemp /19-65 http://www.dabeaz.com/GIL/ -RedirectTemp /19-66 http://www.dabeaz.com/python/UnderstandingGIL.pdf -RedirectTemp /19-67 https://bugs.python.org/issue7946#msg223110 -RedirectTemp /19-68 https://bugs.python.org/issue7946 -RedirectTemp /19-69 https://www.fullstackpython.com/ -RedirectTemp /19-70 https://www.oreilly.com/library/view/high-performance-python/9781492055013/ -RedirectTemp /19-71 https://www.packtpub.com/product/parallel-programming-with-python/9781783288397 -RedirectTemp /19-72 https://www.packtpub.com/product/distributed-computing-with-python/9781785889691 -RedirectTemp /19-73 https://towardsdatascience.com/python-performance-and-gpus-1be860ffd58d?gi=a7d537cc2fb4 -RedirectTemp /19-74 https://instagram-engineering.com/web-service-efficiency-at-instagram-with-python-4976d078e366?gi=12a441991c88 -RedirectTemp /19-75 https://www.oreilly.com/library/view/architecture-patterns-with/9781492052197/ -RedirectTemp /19-76 https://www.cosmicpython.com/ -RedirectTemp /19-77 https://pypi.org/project/lelo/ -RedirectTemp /19-78 https://github.com/npryce/python-parallelize -RedirectTemp /19-79 https://github.com/ericsnowcurrently/multi-core-python/wiki -RedirectTemp /19-80 https://gist.github.com/markshannon/79cace3656b40e21b7021504daee950c -RedirectTemp /19-81 https://mail.python.org/archives/list/python-dev@python.org/message/YOOQZCFOKEPQ24YHWWLQSJ3RCXFMS7D7/ -RedirectTemp /19-82 https://en.wikipedia.org/wiki/Communicating_sequential_processes -RedirectTemp /19-83 https://github.com/stackless-dev/stackless/wiki -RedirectTemp /19-84 https://www.eveonline.com -RedirectTemp /19-85 https://www.ccpgames.com/ -RedirectTemp /19-86 https://stackless.readthedocs.io/en/3.6-slp/stackless-python.html#history -RedirectTemp /19-87 https://doc.pypy.org/en/latest/stackless.html -RedirectTemp /19-88 https://greenlet.readthedocs.io/en/latest/ -RedirectTemp /19-89 http://www.gevent.org/ -RedirectTemp /19-90 http://thespianpy.com/doc/ -RedirectTemp /19-91 https://pykka.readthedocs.io/en/latest/ -RedirectTemp /19-92 https://www.manning.com/books/rabbitmq-in-action -RedirectTemp /19-93 https://pragprog.com/titles/pb7con/seven-concurrency-models-in-seven-weeks/ -RedirectTemp /19-94 https://en.wikipedia.org/wiki/OpenCL -RedirectTemp /19-95 https://media.pragprog.com/titles/pb7con/Bonus_Chapter.pdf -RedirectTemp /19-96 https://martinfowler.com/ -RedirectTemp /19-97 https://martinfowler.com/articles/patterns-of-distributed-systems/ -RedirectTemp /19-98 https://www.oreilly.com/library/view/designing-data-intensive-applications/9781491903063/ -RedirectTemp /19-99 https://www.oreilly.com/library/view/oscon-2016-video/9781491965153/video247021.html -RedirectTemp /19-100 https://www.oreilly.com/library/view/designing-for-scalability/9781449361556/ -RedirectTemp /19-101 https://www.thoughtworks.com/radar/techniques/high-performance-envy-web-scale-envy -RedirectTemp /19-102 https://en.wikipedia.org/wiki/KISS_principle -RedirectTemp /19-103 https://www.usenix.org/conference/hotos15/workshop-program/presentation/mcsherry -############################################################ 20 -RedirectTemp /20-1 https://www.artima.com/weblogs/viewpost.jsp?thread=299551 -RedirectTemp /20-2 https://docs.python.org/3/library/http.server.html -RedirectTemp /20-3 https://www.youtube.com/watch?v=A9e9Cy1UkME -RedirectTemp /20-4 https://www.cia.gov/the-world-factbook/ -RedirectTemp /20-5 https://docs.python-requests.org/en/latest/ -RedirectTemp /20-6 https://docs.python.org/3.10/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor -RedirectTemp /20-7 https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.as_completed -RedirectTemp /20-8 https://docs.python.org/3/library/concurrent.futures.html -RedirectTemp /20-9 https://docs.python.org/3.10/library/concurrent.futures.html#concurrent.futures.Executor -RedirectTemp /20-10 https://github.com/fluentpython/example-code-2e/blob/master/20-executors/getflags/flags2_common.py -RedirectTemp /20-11 https://github.com/noamraph/tqdm -RedirectTemp /20-12 https://www.youtube.com/watch?v=M8Z65tAl5l4 -RedirectTemp /20-13 https://github.com/noamraph/tqdm/blob/master/README.md -RedirectTemp /20-14 https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.as_completed -RedirectTemp /20-15 https://docs.python.org/3/library/asyncio-task.html#asyncio.as_completed -RedirectTemp /20-16 https://www.cloudflare.com/ -RedirectTemp /20-17 https://github.com/fluentpython/example-code-2e/tree/master/20-executors/getflags -RedirectTemp /20-18 https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/418 -RedirectTemp /20-19 https://en.wikipedia.org/wiki/Embarrassingly_parallel -RedirectTemp /20-20 https://pyvideo.org/video/480/pyconau-2010--the-future-is-soon/ -RedirectTemp /20-21 http://www.dabeaz.com/coroutines/ -RedirectTemp /20-22 https://en.wikipedia.org/wiki/POSIX_Threads -RedirectTemp /20-23 https://en.wikipedia.org/wiki/C_dynamic_memory_allocation -RedirectTemp /20-24 https://pragprog.com/titles/pb7con/seven-concurrency-models-in-seven-weeks/ -RedirectTemp /20-25 https://hexdocs.pm/ecto/getting-started.html -############################################################ 21 -RedirectTemp /21-1 https://docs.python.org/3/library/asyncio.html -RedirectTemp /21-2 https://bugs.python.org/issue43216 -RedirectTemp /21-3 https://bugs.python.org/issue36921 -RedirectTemp /21-4 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.getaddrinfo -RedirectTemp /21-5 https://docs.python.org/3/library/socket.html#socket.getaddrinfo -RedirectTemp /21-6 https://docs.python.org/3.10/library/asyncio-eventloop.html#asyncio.get_event_loop -RedirectTemp /21-7 https://www.python.org/dev/peps/pep-0492/#await-expression -RedirectTemp /21-8 https://www.fluentpython.com/extra/classic-coroutines/#yield_from_meaning_sec -RedirectTemp /21-9 https://github.com/fluentpython/example-code-2e/tree/master/20-executors/getflags -RedirectTemp /21-10 https://magicstack.github.io/asyncpg/current/ -RedirectTemp /21-11 https://magicstack.github.io/asyncpg/current/api/index.html#transactions -RedirectTemp /21-12 https://magicstack.github.io/asyncpg/current/api/index.html#transactions -RedirectTemp /21-13 https://github.com/MagicStack/asyncpg/blob/4d39a05268ce4cc01b00458223a767542da048b8/asyncpg/transaction.py#L57 -RedirectTemp /21-14 https://magicstack.github.io/asyncpg/current/usage.html#connection-pools -RedirectTemp /21-15 https://gist.github.com/jboner/2841832 -RedirectTemp /21-16 https://en.wikipedia.org/wiki/Network-attached_storage -RedirectTemp /21-17 https://en.wikipedia.org/wiki/Semaphore_(programming) -RedirectTemp /21-18 https://en.wikipedia.org/wiki/Semaphore_(programming) -RedirectTemp /21-19 https://groups.google.com/forum/#!msg/python-tulip/PdAEtwpaJHs/7fqb-Qj2zJoJ -RedirectTemp /21-20 https://web.archive.org/web/20151209151711/http://tritarget.org/blog/2012/11/28/the-pyramid-of-doom-a-javascript-style-trap -RedirectTemp /21-21 https://stackoverflow.com/questions/53701841/what-is-the-use-case-for-future-add-done-callback/53710563 -RedirectTemp /21-22 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor -RedirectTemp /21-23 https://motor.readthedocs.io/en/stable/ -RedirectTemp /21-24 https://emptysqua.re/blog/response-to-asynchronous-python-and-databases/ -RedirectTemp /21-25 https://docs.python.org/3/library/asyncio-stream.html#tcp-echo-server-using-streams -RedirectTemp /21-26 https://en.wikipedia.org/wiki/Phaistos_Disc -RedirectTemp /21-27 https://en.wikipedia.org/wiki/Inverted_index -RedirectTemp /21-28 https://fastapi.tiangolo.com/ -RedirectTemp /21-29 https://swagger.io/specification/ -RedirectTemp /21-30 https://asgi.readthedocs.io/en/latest/implementations.html -RedirectTemp /21-31 https://pydantic-docs.helpmanual.io/ -RedirectTemp /21-32 https://doc.traefik.io/traefik/ -RedirectTemp /21-33 https://fastapi.tiangolo.com/project-generation/ -RedirectTemp /21-34 https://fastapi.tiangolo.com/tutorial/response-model/ -RedirectTemp /21-35 https://docs.python.org/3/library/asyncio-stream.html#asyncio.start_server -RedirectTemp /21-36 https://github.com/python/typeshed/issues/5535 -RedirectTemp /21-37 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.Server.serve_forever -RedirectTemp /21-38 https://docs.python.org/3/library/asyncio-stream.html#asyncio.StreamWriter.close -RedirectTemp /21-39 https://docs.python.org/3/library/asyncio-stream.html#streamwriter -RedirectTemp /21-40 https://docs.python.org/3/library/asyncio-stream.html -RedirectTemp /21-41 https://docs.python.org/3/library/asyncio-protocol.html -RedirectTemp /21-42 https://docs.python.org/3/library/asyncio-protocol.html#tcp-echo-server -RedirectTemp /21-43 https://github.com/aio-libs/aiopg -RedirectTemp /21-44 https://docs.python.org/3/whatsnew/3.8.html#asyncio -RedirectTemp /21-45 https://datatracker.ietf.org/doc/html/rfc6761 -RedirectTemp /21-46 https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager -RedirectTemp /21-47 https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager -RedirectTemp /21-48 https://docs.python.org/3/library/asyncio-task.html#asyncio.gather -RedirectTemp /21-49 https://curio.readthedocs.io/en/latest/index.html -RedirectTemp /21-50 https://curio.readthedocs.io/en/latest/reference.html#task-groups -RedirectTemp /21-51 https://en.wikipedia.org/wiki/Structured_concurrency -RedirectTemp /21-52 https://mail.python.org/archives/list/python-dev@python.org/thread/2ORDAW74LGE3ZI2QETPJRT2ZL7MCCPG2/ -RedirectTemp /21-53 https://www.python.org/dev/peps/pep-0654/#motivation -RedirectTemp /21-54 https://curio.readthedocs.io/en/latest/reference.html#AWAIT -RedirectTemp /21-55 https://www.python-httpx.org/async/#curio -RedirectTemp /21-56 https://github.com/dabeaz/curio/tree/78bca8a6ad677ef51e1568ac7b3e51441ab49c42/examples -RedirectTemp /21-57 https://datatracker.ietf.org/doc/html/rfc8305 -RedirectTemp /21-58 https://trio.readthedocs.io/en/stable/ -RedirectTemp /21-59 https://www.youtube.com/watch?v=M-sc73Y-zQA -RedirectTemp /21-60 https://en.wikipedia.org/wiki/Technical_debt -RedirectTemp /21-61 https://www.youtube.com/watch?v=E-1Y4kSsAFc -RedirectTemp /21-62 https://github.com/dabeaz/curio -RedirectTemp /21-63 https://trio.readthedocs.io/en/stable/ -RedirectTemp /21-64 https://curio.readthedocs.io/en/latest/#curio-university -RedirectTemp /21-65 https://vorpus.org/blog/some-thoughts-on-asynchronous-api-design-in-a-post-asyncawait-world/ -RedirectTemp /21-66 https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/ -RedirectTemp /21-67 https://stackoverflow.com/questions/49482969/what-is-the-core-difference-between-asyncio-and-trio -RedirectTemp /21-68 https://docs.python.org/3/library/asyncio.html -RedirectTemp /21-69 https://bugs.python.org/issue33649 -RedirectTemp /21-70 https://docs.python.org/3/library/asyncio-dev.html -RedirectTemp /21-71 https://www.youtube.com/watch?v=iG6fr81xHKA -RedirectTemp /21-72 https://www.youtube.com/watch?v=F19R_M4Nay4 -RedirectTemp /21-73 https://asherman.io/projects/unsync.html -RedirectTemp /21-74 https://pyladies.com/ -RedirectTemp /21-75 https://www.youtube.com/watch?v=sW76-pRkZk8 -RedirectTemp /21-76 https://www.youtube.com/watch?v=Xbl7XjFYsN4 -RedirectTemp /21-77 https://www.youtube.com/watch?v=02CLD-42VdI -RedirectTemp /21-78 https://micropython.org/ -RedirectTemp /21-79 https://docs.micropython.org/en/latest/library/uasyncio.html -RedirectTemp /21-80 https://www.encode.io/articles/python-async-frameworks-beyond-developer-tribalism -RedirectTemp /21-81 https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/ -RedirectTemp /21-82 https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/ -RedirectTemp /21-83 https://github.com/MagicStack/uvloop -RedirectTemp /21-84 http://magic.io/blog/uvloop-blazing-fast-python-networking/ -RedirectTemp /21-85 https://github.com/MagicStack/httptools -RedirectTemp /21-86 https://docs.aiohttp.org/en/stable/ -RedirectTemp /21-87 https://github.com/wg/wrk -RedirectTemp /21-88 https://twistedmatrix.com/trac/ -############################################################ 22 -RedirectTemp /22-1 https://github.com/fluentpython/example-code-2e/blob/master/22-dyn-attr-prop/oscon/data/osconfeed.json -RedirectTemp /22-2 https://pypi.org/project/attrdict/ -RedirectTemp /22-3 https://pypi.org/project/addict/ -RedirectTemp /22-4 https://github.com/ActiveState/code/tree/master/recipes/Python/52308_simple_but_handy_collector_bunch_named_stuff -RedirectTemp /22-5 https://docs.python.org/3/library/types.html#types.SimpleNamespace -RedirectTemp /22-6 https://docs.python.org/3/library/argparse.html#argparse.Namespace -RedirectTemp /22-7 https://docs.python.org/3/library/multiprocessing.html#multiprocessing.managers.Namespace -RedirectTemp /22-8 https://github.com/fluentpython/example-code-2e/blob/master/22-dyn-attr-prop/oscon/schedule_v2.py -RedirectTemp /22-9 https://docs.python.org/3/library/functools.html#functools.cached_property -RedirectTemp /22-10 https://docs.python.org/3/library/functools.html#functools.cached_property -RedirectTemp /22-11 https://bugs.python.org/issue42781 -RedirectTemp /22-12 https://docs.python.org/3/howto/descriptor.html -RedirectTemp /22-13 https://github.com/python/cpython/blob/e6d0107e13ed957109e79b796984d3d026a8660d/Lib/functools.py#L926 -RedirectTemp /22-14 https://docs.python.org/3/library/threading.html#rlock-objects -RedirectTemp /22-15 https://docs.python.org/3.10/library/functools.html#functools.cached_property -RedirectTemp /22-16 https://www.wsj.com/articles/SB10001424052970203914304576627102996831200 -RedirectTemp /22-17 https://www.youtube.com/watch?v=s35rVw1zskA&feature=youtu.be -RedirectTemp /22-18 https://docs.python.org/3/library/functions.html#dir -RedirectTemp /22-19 https://github.com/python/cpython/blob/19903085c3ad7a17c8047e1556c700f2eb109931/Lib/cmd.py#L214 -RedirectTemp /22-20 https://docs.python.org/3/library/functions.html#hasattr -RedirectTemp /22-21 https://docs.python.org/3.10/reference/datamodel.html#special-method-lookup -RedirectTemp /22-22 https://docs.python.org/3/library/functions.html -RedirectTemp /22-23 https://docs.python.org/3/reference/datamodel.html#customizing-attribute-access -RedirectTemp /22-24 https://docs.python.org/3/reference/datamodel.html#special-method-lookup -RedirectTemp /22-25 https://docs.python.org/3/library/stdtypes.html#special-attributes -RedirectTemp /22-26 http://wiki.c2.com/?WelcomeVisitors -RedirectTemp /22-27 http://wiki.c2.com/?UniformAccessPrinciple -RedirectTemp /22-28 https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html -RedirectTemp /22-29 http://www.pingo.io/docs/ -RedirectTemp /22-30 https://www.drdobbs.com/javas-new-considered-harmful/184405016 -RedirectTemp /22-31 https://www.python.org/dev/peps/pep-0008/#class-names -############################################################ 23 -RedirectTemp /23-1 http://www.aleax.it/goo_pydp.pdf -RedirectTemp /23-2 https://docs.python.org/3.10/reference/datamodel.html#implementing-descriptors -RedirectTemp /23-3 https://docs.python.org/3/howto/descriptor.html -RedirectTemp /23-4 https://docs.python.org/3/howto/ -RedirectTemp /23-5 http://www.aleax.it/Python/nylug05_om.pdf -RedirectTemp /23-6 https://www.youtube.com/watch?v=VOzvpHoYQoo -RedirectTemp /23-7 https://www.python.org/dev/peps/pep-0487/#trait-descriptors -RedirectTemp /23-8 https://dreamsongs.com/RiseOfWorseIsBetter.html -RedirectTemp /23-9 http://web.archive.org/web/20031002184114/www.amk.ca/python/writing/warts.html -RedirectTemp /23-10 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this -RedirectTemp /23-11 http://python-history.blogspot.com/2009/02/adding-support-for-user-defined-classes.html -############################################################ 24 -RedirectTemp /24-1 https://docs.python.org/3/library/stdtypes.html#special-attributes -RedirectTemp /24-2 https://docs.djangoproject.com/en/3.2/topics/db/models/#meta-options -RedirectTemp /24-3 https://www.python.org/dev/peps/pep-3155/ -RedirectTemp /24-4 https://github.com/python/cpython/blob/3.9/Lib/collections/__init__.py -RedirectTemp /24-5 https://en.wikipedia.org/wiki/Tony_Hoare#Apologies_and_retractions -RedirectTemp /24-6 https://go.dev/tour/basics/12 -RedirectTemp /24-7 https://bugs.python.org/issue42102 -RedirectTemp /24-8 https://docs.python.org/3/reference/datamodel.html#object.__init_subclass__ -RedirectTemp /24-9 https://www.python.org/dev/peps/pep-0557/#abstract -RedirectTemp /24-10 https://github.com/python/cpython/blob/3.9/Lib/dataclasses.py -RedirectTemp /24-11 https://docs.python.org/3/reference/datamodel.html#creating-the-class-object -RedirectTemp /24-12 https://mail.python.org/pipermail/python-list/2002-December/134521.html -RedirectTemp /24-13 https://mail.python.org/pipermail/python-list/2002-July/162558.html -RedirectTemp /24-14 https://github.com/fluentpython/example-code/tree/master/21-class-metaprog/bulkfood -RedirectTemp /24-15 https://en.wikipedia.org/wiki/Principle_of_least_astonishment -RedirectTemp /24-16 https://docs.python.org/3/reference/datamodel.html#object.__class_getitem__ -RedirectTemp /24-17 https://en.wikipedia.org/wiki/Trait_(computer_programming) -RedirectTemp /24-18 https://en.wikipedia.org/wiki/Aspect-oriented_programming -RedirectTemp /24-19 https://dhh.dk/arc/000416.html -RedirectTemp /24-20 https://github.com/cjrh/autoslot -RedirectTemp /24-21 https://docs.python.org/3/reference/datamodel.html#customizing-class-creation -RedirectTemp /24-22 https://docs.python.org/3/library/functions.html#type -RedirectTemp /24-23 https://docs.python.org/3/library/stdtypes.html#special-attributes -RedirectTemp /24-24 https://docs.python.org/3/library/types.html -RedirectTemp /24-25 https://www.python.org/dev/peps/pep-3129/ -RedirectTemp /24-26 https://www.youtube.com/watch?v=cAGliEJV9_o -RedirectTemp /24-27 https://docs.python.org/3/library/functools.html#functools.total_ordering -RedirectTemp /24-28 https://www.python.org/download/releases/2.2.3/descrintro/ -RedirectTemp /24-29 https://github.com/lihaoyi/macropy -RedirectTemp /24-30 https://people.eecs.berkeley.edu/~bh/ss-toc2.html diff --git a/links/deploy.sh b/links/deploy.sh deleted file mode 100755 index ced9bd9..0000000 --- a/links/deploy.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -scp FPY.LI.htaccess dh_i4p2ka@fpy.li:~/fpy.li/.htaccess diff --git a/links/sample-urls.txt b/links/sample-urls.txt deleted file mode 100644 index 9eac47c..0000000 --- a/links/sample-urls.txt +++ /dev/null @@ -1,47 +0,0 @@ -https://www.oreilly.com/library/view/fluent-python-2nd/9781492056348/ -https://dask.org/ -http://example.com/1572039572038573208 -http://www.unicode.org/ -https://www.techcrunch.com/2024/startup-funding-trends -https://blog.medium.com/writing-tips-for-beginners -https://github.com/microsoft/typescript -https://stackoverflow.com/questions/javascript-async-await -https://www.reddit.com/r/programming/hot -https://docs.google.com/spreadsheets/create -https://www.youtube.com/watch?v=dQw4w9WgXcQ -https://www.amazon.com/dp/B08N5WRWNW -https://support.apple.com/iphone-setup-guide -https://www.wikipedia.org/wiki/Machine_Learning -https://www.linkedin.com/in/johndoe123 -https://www.instagram.com/p/CxYz123AbC/ -https://twitter.com/elonmusk/status/1234567890 -https://www.facebook.com/events/987654321 -https://drive.google.com/file/d/1AbCdEfGhIjKlMnOp/view -https://www.dropbox.com/s/qwerty123/document.pdf -https://zoom.us/j/1234567890?pwd=abcdef -https://calendly.com/janedoe/30min-meeting -https://www.shopify.com/admin/products/new -https://stripe.com/docs/api/charges/create -https://www.paypal.com/invoice/create -https://mailchimp.com/campaigns/dashboard -https://analytics.google.com/analytics/web/ -https://console.aws.amazon.com/s3/buckets -https://portal.azure.com/dashboard -https://www.figma.com/file/AbCdEf123456/design-system -https://www.notion.so/workspace/project-notes -https://trello.com/b/AbCdEfGh/marketing-board -https://slack.com/app_redirect?channel=general -https://discord.gg/AbCdEfGh123 -https://www.twitch.tv/streamername/videos -https://www.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M -https://www.netflix.com/browse/genre/83 -https://www.hulu.com/series/breaking-bad-2008 -https://www.airbnb.com/rooms/12345678 -https://www.booking.com/hotel/us/grand-plaza.html -https://www.expedia.com/flights/search?trip=roundtrip -https://www.uber.com/ride/request -https://www.doordash.com/store/pizza-palace-123 -https://www.grubhub.com/restaurant/tacos-el-rey-456 -https://www.zillow.com/homes/for_sale/San-Francisco-CA -https://www.craigslist.org/about/sites -https://www.python.org/dev/peps/pep-0484/ \ No newline at end of file diff --git a/links/short.htaccess b/links/short.htaccess deleted file mode 100644 index 86fe3e2..0000000 --- a/links/short.htaccess +++ /dev/null @@ -1,14 +0,0 @@ -# content of short.htaccess file created and managed by short.py - -# appended: 2025-05-23 15:12:13 -RedirectTemp /22 https://pythonfluente.com/2/#pattern_matching_case_study_sec -RedirectTemp /23 https://pythonfluente.com/2/#how_slicing_works -RedirectTemp /24 https://pythonfluente.com/2/#sliceable_sequence -RedirectTemp /25 https://pythonfluente.com/2/#virtual_subclass_sec -RedirectTemp /26 https://pythonfluente.com/2/#environment_class_ex -RedirectTemp /27 https://pythonfluente.com/2/#subclass_builtin_woes -RedirectTemp /28 https://pythonfluente.com/2/#slots_section -RedirectTemp /29 https://pythonfluente.com/2/#typeddict_sec -RedirectTemp /2a https://pythonfluente.com/2/#problems_annot_runtime_sec -RedirectTemp /2b https://pythonfluente.com/2/#legacy_deprecated_typing_box -RedirectTemp /2c https://pythonfluente.com/2/#positional_pattern_implement_sec diff --git a/links/short.py b/links/short.py deleted file mode 100755 index d67c71d..0000000 --- a/links/short.py +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/env python3 - -""" -short.py generates unique short URLs. - -This script reads lines from stdin or files named as arguments, then: - -1. retrieves or creates new short URLs, taking into account existing RedirectTemp - directives in custom.htaccess or short.htaccess; -2. appends RedirectTemp directives for newly created short URLs to short.htaccess; -3. outputs the list of (short, long) URLs retrieved or created. - -""" - -import fileinput -import itertools -from collections.abc import Iterator -from time import strftime - -HTACCESS_CUSTOM = 'custom.htaccess' -HTACCESS_SHORT = 'short.htaccess' -HTACCESS_FILES = (HTACCESS_CUSTOM, HTACCESS_SHORT) -BASE_DOMAIN = 'fpy.li' - - -def load_redirects() -> tuple[dict, dict]: - redirects = {} - targets = {} - for filename in HTACCESS_FILES: - with open(filename) as fp: - for line in fp: - if line.startswith('RedirectTemp'): - _, short, long = line.split() - short = short[1:] # Remove leading slash - assert short not in redirects, f'{filename}: duplicate redirect from {short}' - # htaccess.custom is live since 2022, we can't change it remove duplicate targets - if filename != HTACCESS_CUSTOM: - assert long not in targets, f'{filename}: duplicate redirect to {long}' - redirects[short] = long - targets[long] = short - return redirects, targets - - -SDIGITS = '23456789abcdefghjkmnpqrstvwxyz' - - -def gen_short(start_len=1) -> Iterator[str]: - """Generate every possible sequence of SDIGITS, starting with start_len""" - length = start_len - while True: - for short in itertools.product(SDIGITS, repeat=length): - yield ''.join(short) - length += 1 - - -def gen_unused_short(redirects: dict) -> Iterator[str]: - """Generate next available short URL of len >= 2.""" - for short in gen_short(2): - if short not in redirects: - yield short - - -def shorten(urls: list[str]) -> list[tuple[str, str]]: - """Return (short, long) pairs, appending directives to HTACCESS_SHORT as needed.""" - redirects, targets = load_redirects() - iter_short = gen_unused_short(redirects) - pairs = [] - timestamp = strftime('%Y-%m-%d %H:%M:%S') - with open(HTACCESS_SHORT, 'a') as fp: - for long in urls: - assert BASE_DOMAIN not in long, f'{long} is a {BASE_DOMAIN} URL' - if long in targets: - short = targets[long] - else: - short = next(iter_short) - redirects[short] = long - targets[long] = short - if timestamp: - fp.write(f'\n# appended: {timestamp}\n') - timestamp = None - fp.write(f'RedirectTemp /{short} {long}\n') - pairs.append((short, long)) - - return pairs - - -def main() -> None: - """read URLS from filename arguments or stdin""" - urls = [line.strip() for line in fileinput.input(encoding='utf-8')] - for short, long in shorten(urls): - print(f'{BASE_DOMAIN}/{short}\t{long}') - - -if __name__ == '__main__': - main()