ch15: draft examples
This commit is contained in:
parent
5312d4f824
commit
1689eec623
41
15-more-types/cafeteria/cafeteria.py
Normal file
41
15-more-types/cafeteria/cafeteria.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
from typing import TypeVar, Generic
|
||||||
|
|
||||||
|
|
||||||
|
class Beverage:
|
||||||
|
"""Any beverage"""
|
||||||
|
|
||||||
|
|
||||||
|
class Juice(Beverage):
|
||||||
|
"""Any fruit juice"""
|
||||||
|
|
||||||
|
|
||||||
|
class OrangeJuice(Juice):
|
||||||
|
"""Delicious juice Brazilian oranges"""
|
||||||
|
|
||||||
|
|
||||||
|
class Coak(Beverage):
|
||||||
|
"""Secret formula with lots of sugar"""
|
||||||
|
|
||||||
|
|
||||||
|
BeverageT = TypeVar('BeverageT', bound=Beverage)
|
||||||
|
JuiceT = TypeVar('JuiceT', bound=Juice)
|
||||||
|
|
||||||
|
|
||||||
|
class BeverageDispenser(Generic[BeverageT]):
|
||||||
|
|
||||||
|
beverage: BeverageT
|
||||||
|
|
||||||
|
def __init__(self, beverage: BeverageT) -> None:
|
||||||
|
self.beverage = beverage
|
||||||
|
|
||||||
|
def dispense(self) -> BeverageT:
|
||||||
|
return self.beverage
|
||||||
|
|
||||||
|
|
||||||
|
class JuiceDispenser(BeverageDispenser[JuiceT]):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Cafeteria:
|
||||||
|
def __init__(self, dispenser: BeverageDispenser[JuiceT]):
|
||||||
|
self.dispenser = dispenser
|
23
15-more-types/cafeteria/cafeteria_demo.py
Normal file
23
15-more-types/cafeteria/cafeteria_demo.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
from cafeteria import (
|
||||||
|
Cafeteria,
|
||||||
|
BeverageDispenser,
|
||||||
|
JuiceDispenser,
|
||||||
|
Juice,
|
||||||
|
OrangeJuice,
|
||||||
|
Coak,
|
||||||
|
)
|
||||||
|
|
||||||
|
orange = OrangeJuice()
|
||||||
|
|
||||||
|
orange_dispenser: JuiceDispenser[OrangeJuice] = JuiceDispenser(orange)
|
||||||
|
|
||||||
|
juice: Juice = orange_dispenser.dispense()
|
||||||
|
|
||||||
|
soda = Coak()
|
||||||
|
|
||||||
|
## Value of type variable "JuiceT" of "JuiceDispenser" cannot be "Coak"
|
||||||
|
# soda_dispenser = JuiceDispenser(soda)
|
||||||
|
|
||||||
|
soda_dispenser = BeverageDispenser(soda)
|
||||||
|
|
||||||
|
arnold_hall = Cafeteria(soda_dispenser)
|
16
15-more-types/collections_variance.py
Normal file
16
15-more-types/collections_variance.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
from collections.abc import Collection, Sequence
|
||||||
|
|
||||||
|
col_int: Collection[int]
|
||||||
|
|
||||||
|
seq_int: Sequence[int] = (1, 2, 3)
|
||||||
|
|
||||||
|
## Incompatible types in assignment
|
||||||
|
## expression has type "Collection[int]"
|
||||||
|
## variable has type "Sequence[int]"
|
||||||
|
# seq_int = col_int
|
||||||
|
|
||||||
|
col_int = seq_int
|
||||||
|
|
||||||
|
## List item 0 has incompatible type "float"
|
||||||
|
## expected "int"
|
||||||
|
# col_int = [1.1]
|
@ -1,5 +1,4 @@
|
|||||||
import random
|
from typing import TYPE_CHECKING
|
||||||
from typing import Iterable, TYPE_CHECKING, List
|
|
||||||
|
|
||||||
from erp import EnterpriserRandomPopper
|
from erp import EnterpriserRandomPopper
|
||||||
import randompop
|
import randompop
|
||||||
@ -9,7 +8,6 @@ def test_issubclass() -> None:
|
|||||||
assert issubclass(EnterpriserRandomPopper, randompop.RandomPopper)
|
assert issubclass(EnterpriserRandomPopper, randompop.RandomPopper)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_isinstance_untyped_items_argument() -> None:
|
def test_isinstance_untyped_items_argument() -> None:
|
||||||
items = [1, 2, 3]
|
items = [1, 2, 3]
|
||||||
popper = EnterpriserRandomPopper(items) # [int] is not required
|
popper = EnterpriserRandomPopper(items) # [int] is not required
|
59
15-more-types/gen_contra.py
Normal file
59
15-more-types/gen_contra.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
"""
|
||||||
|
In ``Generator[YieldType, SendType, ReturnType]``,
|
||||||
|
``SendType`` is contravariant.
|
||||||
|
The other type variables are covariant.
|
||||||
|
|
||||||
|
This is how ``typing.Generator`` is declared::
|
||||||
|
|
||||||
|
class Generator(Iterator[T_co], Generic[T_co, T_contra, V_co]):
|
||||||
|
|
||||||
|
(from https://docs.python.org/3/library/typing.html#typing.Generator)
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from typing import Generator
|
||||||
|
|
||||||
|
|
||||||
|
# Generator[YieldType, SendType, ReturnType]
|
||||||
|
|
||||||
|
def gen_float_take_int() -> Generator[float, int, str]:
|
||||||
|
received = yield -1.0
|
||||||
|
while received:
|
||||||
|
received = yield float(received)
|
||||||
|
return 'Done'
|
||||||
|
|
||||||
|
|
||||||
|
def gen_float_take_float() -> Generator[float, float, str]:
|
||||||
|
received = yield -1.0
|
||||||
|
while received:
|
||||||
|
received = yield float(received)
|
||||||
|
return 'Done'
|
||||||
|
|
||||||
|
|
||||||
|
def gen_float_take_complex() -> Generator[float, complex, str]:
|
||||||
|
received = yield -1.0
|
||||||
|
while received:
|
||||||
|
received = yield abs(received)
|
||||||
|
return 'Done'
|
||||||
|
|
||||||
|
# Generator[YieldType, SendType, ReturnType]
|
||||||
|
|
||||||
|
g0: Generator[float, float, str] = gen_float_take_float()
|
||||||
|
|
||||||
|
g1: Generator[complex, float, str] = gen_float_take_float()
|
||||||
|
|
||||||
|
## Incompatible types in assignment
|
||||||
|
## expression has type "Generator[float, float, str]"
|
||||||
|
## variable has type "Generator[int, float, str]")
|
||||||
|
# g2: Generator[int, float, str] = gen_float_take_float()
|
||||||
|
|
||||||
|
|
||||||
|
# Generator[YieldType, SendType, ReturnType]
|
||||||
|
|
||||||
|
g3: Generator[float, int, str] = gen_float_take_float()
|
||||||
|
|
||||||
|
## Incompatible types in assignment
|
||||||
|
## expression has type "Generator[float, float, str]"
|
||||||
|
## variable has type "Generator[float, complex, str]")
|
||||||
|
## g4: Generator[float, complex, str] = gen_float_take_float()
|
||||||
|
|
47
15-more-types/petbox/petbox.py
Normal file
47
15-more-types/petbox/petbox.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
from typing import TypeVar, Generic, Any
|
||||||
|
|
||||||
|
|
||||||
|
class Pet:
|
||||||
|
"""Domestic animal kept for companionship."""
|
||||||
|
|
||||||
|
|
||||||
|
class Dog(Pet):
|
||||||
|
"""Canis familiaris"""
|
||||||
|
|
||||||
|
|
||||||
|
class Cat(Pet):
|
||||||
|
"""Felis catus"""
|
||||||
|
|
||||||
|
|
||||||
|
class Siamese(Cat):
|
||||||
|
"""Cat breed from Thailand"""
|
||||||
|
|
||||||
|
|
||||||
|
T = TypeVar('T')
|
||||||
|
|
||||||
|
|
||||||
|
class Box(Generic[T]):
|
||||||
|
def put(self, item: T) -> None:
|
||||||
|
self.contents = item
|
||||||
|
|
||||||
|
def get(self) -> T:
|
||||||
|
return self.contents
|
||||||
|
|
||||||
|
|
||||||
|
T_contra = TypeVar('T_contra', contravariant=True)
|
||||||
|
|
||||||
|
|
||||||
|
class InBox(Generic[T_contra]):
|
||||||
|
def put(self, item: T) -> None:
|
||||||
|
self.contents = item
|
||||||
|
|
||||||
|
|
||||||
|
T_co = TypeVar('T_co', covariant=True)
|
||||||
|
|
||||||
|
|
||||||
|
class OutBox(Generic[T_co]):
|
||||||
|
def __init__(self, contents: Any):
|
||||||
|
self.contents = contents
|
||||||
|
|
||||||
|
def get(self) -> Any:
|
||||||
|
return self.contents
|
42
15-more-types/petbox/petbox_demo.py
Normal file
42
15-more-types/petbox/petbox_demo.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from petbox import *
|
||||||
|
|
||||||
|
|
||||||
|
cat_box: Box[Cat] = Box()
|
||||||
|
|
||||||
|
si = Siamese()
|
||||||
|
|
||||||
|
cat_box.put(si)
|
||||||
|
|
||||||
|
animal = cat_box.get()
|
||||||
|
|
||||||
|
#if TYPE_CHECKING:
|
||||||
|
# reveal_type(animal) # Revealed: petbox.Cat*
|
||||||
|
|
||||||
|
|
||||||
|
################### Covariance
|
||||||
|
|
||||||
|
out_box: OutBox[Cat] = OutBox(Cat())
|
||||||
|
|
||||||
|
out_box_si: OutBox[Siamese] = OutBox(Siamese())
|
||||||
|
|
||||||
|
## Incompatible types in assignment
|
||||||
|
## expression has type "OutBox[Cat]"
|
||||||
|
# variable has type "OutBox[Siamese]"
|
||||||
|
# out_box_si = out_box
|
||||||
|
|
||||||
|
out_box = out_box_si
|
||||||
|
|
||||||
|
################### Contravariance
|
||||||
|
|
||||||
|
in_box: InBox[Cat] = InBox()
|
||||||
|
|
||||||
|
in_box_si: InBox[Siamese] = InBox()
|
||||||
|
|
||||||
|
in_box_si = in_box
|
||||||
|
|
||||||
|
## Incompatible types in assignment
|
||||||
|
## expression has type "InBox[Siamese]"
|
||||||
|
## variable has type "InBox[Cat]"
|
||||||
|
# in_box = in_box_si
|
@ -4,7 +4,7 @@ from typing import Iterable, TYPE_CHECKING
|
|||||||
from randompick_generic import GenericRandomPicker
|
from randompick_generic import GenericRandomPicker
|
||||||
|
|
||||||
|
|
||||||
class LottoPicker():
|
class LottoPicker:
|
||||||
def __init__(self, items: Iterable[int]) -> None:
|
def __init__(self, items: Iterable[int]) -> None:
|
||||||
self._items = list(items)
|
self._items = list(items)
|
||||||
random.shuffle(self._items)
|
random.shuffle(self._items)
|
@ -1,4 +1,4 @@
|
|||||||
from typing import Protocol, TypeVar, runtime_checkable, Any
|
from typing import Protocol, runtime_checkable, Any
|
||||||
|
|
||||||
|
|
||||||
@runtime_checkable
|
@runtime_checkable
|
@ -3,7 +3,7 @@ import random
|
|||||||
from typing import Any, Iterable, TYPE_CHECKING
|
from typing import Any, Iterable, TYPE_CHECKING
|
||||||
|
|
||||||
|
|
||||||
class SimplePopper():
|
class SimplePopper:
|
||||||
def __init__(self, items: Iterable) -> None:
|
def __init__(self, items: Iterable) -> None:
|
||||||
self._items = list(items)
|
self._items = list(items)
|
||||||
random.shuffle(self._items)
|
random.shuffle(self._items)
|
32
15-more-types/typeddict/books.py
Normal file
32
15-more-types/typeddict/books.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# tag::BOOKDICT[]
|
||||||
|
from typing import TypedDict, List
|
||||||
|
import json
|
||||||
|
|
||||||
|
class BookDict(TypedDict):
|
||||||
|
isbn: str
|
||||||
|
title: str
|
||||||
|
authors: List[str]
|
||||||
|
pagecount: int
|
||||||
|
# end::BOOKDICT[]
|
||||||
|
|
||||||
|
# tag::TOXML[]
|
||||||
|
AUTHOR_EL = '<AUTHOR>{}</AUTHOR>'
|
||||||
|
|
||||||
|
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>
|
||||||
|
else:
|
||||||
|
tag = key.upper()
|
||||||
|
elements.append(f'<{tag}>{value}</{tag}>')
|
||||||
|
xml = '\n\t'.join(elements)
|
||||||
|
return f'<BOOK>\n\t{xml}\n</BOOK>'
|
||||||
|
# end::TOXML[]
|
||||||
|
|
||||||
|
# tag::FROMJSON[]
|
||||||
|
def from_json(data: str) -> BookDict:
|
||||||
|
whatever: BookDict = json.loads(data) # <1>
|
||||||
|
return whatever # <2>
|
||||||
|
# end::FROMJSON[]
|
32
15-more-types/typeddict/books_any.py
Normal file
32
15-more-types/typeddict/books_any.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# tag::BOOKDICT[]
|
||||||
|
from typing import TypedDict, List
|
||||||
|
import json
|
||||||
|
|
||||||
|
class BookDict(TypedDict):
|
||||||
|
isbn: str
|
||||||
|
title: str
|
||||||
|
authors: List[str]
|
||||||
|
pagecount: int
|
||||||
|
# end::BOOKDICT[]
|
||||||
|
|
||||||
|
# tag::TOXML[]
|
||||||
|
AUTHOR_EL = '<AUTHOR>{}</AUTHOR>'
|
||||||
|
|
||||||
|
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)
|
||||||
|
else:
|
||||||
|
tag = key.upper()
|
||||||
|
elements.append(f'<{tag}>{value}</{tag}>')
|
||||||
|
xml = '\n\t'.join(elements)
|
||||||
|
return f'<BOOK>\n\t{xml}\n</BOOK>'
|
||||||
|
# end::TOXML[]
|
||||||
|
|
||||||
|
# tag::FROMJSON[]
|
||||||
|
def from_json(data: str) -> BookDict:
|
||||||
|
whatever = json.loads(data) # <1>
|
||||||
|
return whatever # <2>
|
||||||
|
# end::FROMJSON[]
|
20
15-more-types/typeddict/demo_books.py
Normal file
20
15-more-types/typeddict/demo_books.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
from books import BookDict
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
def demo() -> None: # <1>
|
||||||
|
book = BookDict( # <2>
|
||||||
|
isbn='0134757599',
|
||||||
|
title='Refactoring, 2e',
|
||||||
|
authors=['Martin Fowler', 'Kent Beck'],
|
||||||
|
pagecount=478
|
||||||
|
)
|
||||||
|
authors = book['authors'] # <3>
|
||||||
|
if TYPE_CHECKING: # <4>
|
||||||
|
reveal_type(authors) # <5>
|
||||||
|
authors = 'Bob' # <6>
|
||||||
|
book['weight'] = 4.2
|
||||||
|
del book['title']
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
demo()
|
23
15-more-types/typeddict/demo_not_book.py
Normal file
23
15-more-types/typeddict/demo_not_book.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
from books import to_xml, from_json
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
def demo() -> None:
|
||||||
|
NOT_BOOK_JSON = """
|
||||||
|
{"title": "Andromeda Strain",
|
||||||
|
"flavor": "pistachio",
|
||||||
|
"authors": true}
|
||||||
|
"""
|
||||||
|
not_book = from_json(NOT_BOOK_JSON) # <1>
|
||||||
|
if TYPE_CHECKING: # <2>
|
||||||
|
reveal_type(not_book)
|
||||||
|
reveal_type(not_book['authors'])
|
||||||
|
|
||||||
|
print(not_book) # <3>
|
||||||
|
print(not_book['flavor']) # <4>
|
||||||
|
|
||||||
|
xml = to_xml(not_book) # <5>
|
||||||
|
print(xml) # <6>
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
demo()
|
112
15-more-types/typeddict/test_books.py
Normal file
112
15-more-types/typeddict/test_books.py
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import json
|
||||||
|
from typing import cast
|
||||||
|
|
||||||
|
from books import BookDict, to_xml, from_json
|
||||||
|
|
||||||
|
XML_SAMPLE = """
|
||||||
|
<BOOK>
|
||||||
|
\t<ISBN>0134757599</ISBN>
|
||||||
|
\t<TITLE>Refactoring, 2e</TITLE>
|
||||||
|
\t<AUTHOR>Martin Fowler</AUTHOR>
|
||||||
|
\t<AUTHOR>Kent Beck</AUTHOR>
|
||||||
|
\t<PAGECOUNT>478</PAGECOUNT>
|
||||||
|
</BOOK>
|
||||||
|
""".strip()
|
||||||
|
|
||||||
|
|
||||||
|
# using plain dicts
|
||||||
|
|
||||||
|
def test_1() -> None:
|
||||||
|
xml = to_xml({
|
||||||
|
'isbn': '0134757599',
|
||||||
|
'title': 'Refactoring, 2e',
|
||||||
|
'authors': ['Martin Fowler', 'Kent Beck'],
|
||||||
|
'pagecount': 478,
|
||||||
|
})
|
||||||
|
assert xml == XML_SAMPLE
|
||||||
|
|
||||||
|
def test_2() -> None:
|
||||||
|
xml = to_xml(dict(
|
||||||
|
isbn='0134757599',
|
||||||
|
title='Refactoring, 2e',
|
||||||
|
authors=['Martin Fowler', 'Kent Beck'],
|
||||||
|
pagecount=478))
|
||||||
|
assert xml == XML_SAMPLE
|
||||||
|
|
||||||
|
def test_5() -> None:
|
||||||
|
book_data: BookDict = dict(
|
||||||
|
isbn='0134757599',
|
||||||
|
title='Refactoring, 2e',
|
||||||
|
authors=['Martin Fowler', 'Kent Beck'],
|
||||||
|
pagecount=478
|
||||||
|
)
|
||||||
|
xml = to_xml(book_data)
|
||||||
|
assert xml == XML_SAMPLE
|
||||||
|
|
||||||
|
def test_6() -> None:
|
||||||
|
book_data = dict(
|
||||||
|
isbn='0134757599',
|
||||||
|
title='Refactoring, 2e',
|
||||||
|
authors=['Martin Fowler', 'Kent Beck'],
|
||||||
|
pagecount=478
|
||||||
|
)
|
||||||
|
xml = to_xml(cast(BookDict, book_data)) # cast needed
|
||||||
|
assert xml == XML_SAMPLE
|
||||||
|
|
||||||
|
def test_4() -> None:
|
||||||
|
xml = to_xml(BookDict(
|
||||||
|
isbn='0134757599',
|
||||||
|
title='Refactoring, 2e',
|
||||||
|
authors=['Martin Fowler', 'Kent Beck'],
|
||||||
|
pagecount=478))
|
||||||
|
assert xml == XML_SAMPLE
|
||||||
|
|
||||||
|
def test_7() -> None:
|
||||||
|
book_data = BookDict(
|
||||||
|
isbn='0134757599',
|
||||||
|
title='Refactoring, 2e',
|
||||||
|
authors=['Martin Fowler', 'Kent Beck'],
|
||||||
|
pagecount=478
|
||||||
|
)
|
||||||
|
xml = to_xml(book_data)
|
||||||
|
assert xml == XML_SAMPLE
|
||||||
|
|
||||||
|
def test_8() -> None:
|
||||||
|
book_data: BookDict = {
|
||||||
|
'isbn': '0134757599',
|
||||||
|
'title': 'Refactoring, 2e',
|
||||||
|
'authors': ['Martin Fowler', 'Kent Beck'],
|
||||||
|
'pagecount': 478,
|
||||||
|
}
|
||||||
|
xml = to_xml(book_data)
|
||||||
|
assert xml == XML_SAMPLE
|
||||||
|
|
||||||
|
BOOK_JSON = """
|
||||||
|
{"isbn": "0134757599",
|
||||||
|
"title": "Refactoring, 2e",
|
||||||
|
"authors": ["Martin Fowler", "Kent Beck"],
|
||||||
|
"pagecount": 478}
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test_load_book_0() -> None:
|
||||||
|
book_data: BookDict = json.loads(BOOK_JSON) # typed var
|
||||||
|
xml = to_xml(book_data)
|
||||||
|
assert xml == XML_SAMPLE
|
||||||
|
|
||||||
|
def test_load_book() -> None:
|
||||||
|
book_data = from_json(BOOK_JSON)
|
||||||
|
xml = to_xml(book_data)
|
||||||
|
assert xml == XML_SAMPLE
|
||||||
|
|
||||||
|
|
||||||
|
NOT_BOOK_JSON = """
|
||||||
|
{"isbn": 3.141592653589793
|
||||||
|
"title": [1, 2, 3],
|
||||||
|
"authors": ["Martin Fowler", "Kent Beck"],
|
||||||
|
"flavor": "strawberry"}
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test_load_not_book() -> None:
|
||||||
|
book_data: BookDict = json.loads(BOOK_JSON) # typed var
|
||||||
|
xml = to_xml(book_data)
|
||||||
|
assert xml == XML_SAMPLE
|
20
15-more-types/typeddict/test_books_check_fails.py
Normal file
20
15-more-types/typeddict/test_books_check_fails.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
from books import BookDict, to_xml
|
||||||
|
|
||||||
|
XML_SAMPLE = """
|
||||||
|
<BOOK>
|
||||||
|
\t<ISBN>0134757599</ISBN>
|
||||||
|
\t<TITLE>Refactoring, 2e</TITLE>
|
||||||
|
\t<AUTHOR>Martin Fowler</AUTHOR>
|
||||||
|
\t<AUTHOR>Kent Beck</AUTHOR>
|
||||||
|
\t<PAGECOUNT>478</PAGECOUNT>
|
||||||
|
</BOOK>
|
||||||
|
""".strip()
|
||||||
|
|
||||||
|
def test_3() -> None:
|
||||||
|
xml = to_xml(BookDict(dict([ # Expected keyword arguments, {...}, or dict(...) in TypedDict constructor
|
||||||
|
('isbn', '0134757599'),
|
||||||
|
('title', 'Refactoring, 2e'),
|
||||||
|
('authors', ['Martin Fowler', 'Kent Beck']),
|
||||||
|
('pagecount', 478),
|
||||||
|
])))
|
||||||
|
assert xml == XML_SAMPLE
|
58
README.md
58
README.md
@ -1,6 +1,6 @@
|
|||||||
# Fluent Python 2e example code
|
# Fluent Python 2e example code
|
||||||
|
|
||||||
Example code for the book **Fluent Python, 2<sup>nd</sup> edition** by Luciano Ramalho (O'Reilly, 2021).
|
Example code for the book **Fluent Python, 2<sup>nd</sup> edition** by Luciano Ramalho (O'Reilly, 2020).
|
||||||
|
|
||||||
> **BEWARE**: This is a work in progress!
|
> **BEWARE**: This is a work in progress!
|
||||||
>
|
>
|
||||||
@ -14,40 +14,40 @@ Example code for the book **Fluent Python, 2<sup>nd</sup> edition** by Luciano R
|
|||||||
|
|
||||||
All chapters are undergoing review and updates, including significant rewrites in the chapters about concurrency in **Part V**.
|
All chapters are undergoing review and updates, including significant rewrites in the chapters about concurrency in **Part V**.
|
||||||
|
|
||||||
New chapters in **Fluent Python 2<sup>nd</sup> edition** are marked with 🆕.
|
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.
|
||||||
|
|
||||||
Part / Chapter #|Title|Directory|1<sup>st</sup> edition Chapter #
|
Part / Chapter #|Title|Directory|Notebook|1<sup>st</sup> ed. Chapter #
|
||||||
---:|---|---|:---:
|
---:|---|---|---|:---:
|
||||||
**I – Prologue**|
|
**I – Prologue**|
|
||||||
1|The Python Data Model|[01-data-model](01-data-model)|1
|
1|The Python Data Model|[01-data-model](01-data-model)|[data-model.ipynb](01-data-model/data-model.ipynb)|1
|
||||||
**II – Data Structures**|
|
**II – Data Structures**|
|
||||||
2|An Array of Sequences|[02-array-seq](02-array-seq)|2
|
2|An Array of Sequences|[02-array-seq](02-array-seq)|[array-seq.ipynb](02-array-seq/array-seq.ipynb)|2
|
||||||
3|Dictionaries and Sets|[03-dict-set](03-dict-set)|3
|
3|Dictionaries and Sets|[03-dict-set](03-dict-set)||3
|
||||||
4|Text versus Bytes|[04-text-byte](04-text-byte)|4
|
4|Text versus Bytes|[04-text-byte](04-text-byte)||4
|
||||||
5|Record-like Data Structures|[05-record-like](05-record-like)|🆕
|
🆕 5|Record-like Data Structures|[05-record-like](05-record-like)||–
|
||||||
6|Object References, Mutability, and Recycling|[06-obj-ref](06-obj-ref)|8
|
6|Object References, Mutability, and Recycling|[06-obj-ref](06-obj-ref)||8
|
||||||
**III – Functions as Objects**|
|
**III – Functions as Objects**|
|
||||||
7|First-Class Funcions|[07-1class-func](07-1class-func)|5
|
7|First-Class Funcions|[07-1class-func](07-1class-func)||5
|
||||||
8|Type Hints in Function Definitions|[08-def-type-hints](08-def-type-hints)|🆕
|
🆕 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
|
9|Function 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
|
10|Design Patterns with First-Class Functions|[10-dp-1class-func](10-dp-1class-func)||6
|
||||||
**IV – Object-Oriented Idioms**|
|
**IV – Object-Oriented Idioms**|
|
||||||
11|A Pythonic Object|[11-pythonic-obj](11-pythonic-obj)|9
|
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|Sequence Hacking, Hashing, and Slicing|[12-seq-hacking](12-seq-hacking)||10
|
||||||
13|Interfaces, Protocols, and ABCs|[13-protocl-abc](13-protocol-abc)|11
|
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 Good or For Worse|[14-inheritance](14-inheritance)||12
|
||||||
15|More About Type Hints|15-more-typing|🆕
|
🆕 15|More About Type Hints|[15-more-types](15-more-types)||–
|
||||||
16|Operator Overloading: Doing It Right|[16-op-overloading](16-op-overloading)|13
|
16|Operator Overloading: Doing It Right|[16-op-overloading](16-op-overloading)||13
|
||||||
**V – Control Flow**|
|
**V – Control Flow**|
|
||||||
17|Iterables, Iterators, and Generators|[17-it-generator](17-it-generator)|14
|
17|Iterables, Iterators, and Generators|[17-it-generator](17-it-generator)||14
|
||||||
18|Context Managers and else Blocks|[18-context-mngr](18-context-mngr)|15
|
18|Context Managers and else Blocks|[18-context-mngr](18-context-mngr)||15
|
||||||
19|Classic Coroutines|[19-coroutine](19-coroutine)|16
|
19|Classic Coroutines|[19-coroutine](19-coroutine)||16
|
||||||
20|Concurrency Models in Python|[20-concurrency](20-concurrency)|🆕
|
🆕 20|Concurrency Models in Python|[20-concurrency](20-concurrency)||-
|
||||||
21|Concurrency with Futures|[21-futures](21-futures)|17
|
21|Concurrency with Futures|[21-futures](21-futures)||17
|
||||||
22|Asynchronous Programming|[22-async](22-async)|18
|
22|Asynchronous Programming|[22-async](22-async)||18
|
||||||
**VI – Metaprogramming**|
|
**VI – Metaprogramming**|
|
||||||
23|Dynamic Attributes and Properties|[23-dyn-attr-prop](23-dyn-attr-prop)|19
|
23|Dynamic Attributes and Properties|[22-dyn-attr-prop](22-dyn-attr-prop)||19
|
||||||
24|Attribute Descriptors|[24-descriptor](24-descriptor)|20
|
24|Attribute Descriptors|[23-descriptor](23-descriptor)||20
|
||||||
25|Class Metaprogramming|[25-class-metaprog](25-class-metaprog)|21
|
25|Class Metaprogramming|[24-class-metaprog](24-class-metaprog)||21
|
||||||
|
Loading…
Reference in New Issue
Block a user