sync with O'Reilly Atlas
This commit is contained in:
1
05-data-classes/README.asciidoc
Normal file
1
05-data-classes/README.asciidoc
Normal file
@@ -0,0 +1 @@
|
||||
== Record-like Structures
|
||||
22
05-data-classes/cards.doctest
Normal file
22
05-data-classes/cards.doctest
Normal file
@@ -0,0 +1,22 @@
|
||||
>>> from cards import Card
|
||||
>>> helen = Card('Q', 'hearts')
|
||||
>>> helen
|
||||
Card(rank='Q', suit='hearts')
|
||||
|
||||
>>> cards = [Card(r, s) for s in Card.suits for r in Card.ranks]
|
||||
>>> cards[:3]
|
||||
[Card(rank='2', suit='spades'), Card(rank='3', suit='spades'), Card(rank='4', suit='spades')]
|
||||
>>> sorted(cards)[:3]
|
||||
[Card(rank='2', suit='clubs'), Card(rank='2', suit='diamonds'), Card(rank='2', suit='hearts')]
|
||||
|
||||
>>> from cards_enum import Card, Suit, Rank
|
||||
>>> helen = Card('Q', 'hearts')
|
||||
>>> helen
|
||||
Card(rank='Q', suit='hearts')
|
||||
|
||||
>>> cards = [Card(r, s) for s in Suit for r in Rank]
|
||||
>>> cards[:3]
|
||||
[Card(rank='2', suit='spades'), Card(rank='3', suit='spades'), Card(rank='4', suit='spades')]
|
||||
>>> sorted(cards)[:3]
|
||||
[Card(rank='2', suit='clubs'), Card(rank='2', suit='diamonds'), Card(rank='2', suit='hearts')]
|
||||
>>> for card in cards[12::13]: print(card)
|
||||
9
05-data-classes/cards.py
Normal file
9
05-data-classes/cards.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass(order=True)
|
||||
class Card:
|
||||
rank: str
|
||||
suit: str
|
||||
|
||||
ranks = [str(n) for n in range(2, 10)] + list('JQKA')
|
||||
suits = 'spades diamonds clubs hearts'.split()
|
||||
14
05-data-classes/cards_enum.py
Normal file
14
05-data-classes/cards_enum.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from dataclasses import dataclass
|
||||
import enum
|
||||
|
||||
Suit = enum.IntEnum('Suit', 'spades diamonds clubs hearts')
|
||||
Rank = enum.Enum('Rank', [str(n) for n in range(2, 10)] + list('JQKA'))
|
||||
|
||||
@dataclass(order=True)
|
||||
class Card:
|
||||
rank: Suit
|
||||
suit: Rank
|
||||
|
||||
def __str__(self):
|
||||
glyphs = [chr(x) for x in range(0x2660, 0x2664)]
|
||||
return f'{self.rank} of {glyphs[self.suit-1]}'
|
||||
16
05-data-classes/class/coordinates.py
Normal file
16
05-data-classes/class/coordinates.py
Normal file
@@ -0,0 +1,16 @@
|
||||
"""
|
||||
``Coordinate``: a simple class with a custom ``__str__``::
|
||||
|
||||
>>> moscow = Coordinate(55.756, 37.617)
|
||||
>>> print(moscow) # doctest:+ELLIPSIS
|
||||
<coordinates.Coordinate object at 0x...>
|
||||
"""
|
||||
|
||||
# tag::COORDINATE[]
|
||||
class Coordinate:
|
||||
|
||||
def __init__(self, lat, lon):
|
||||
self.lat = lat
|
||||
self.lon = lon
|
||||
|
||||
# end::COORDINATE[]
|
||||
9
05-data-classes/dataclass/club.py
Normal file
9
05-data-classes/dataclass/club.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
|
||||
@dataclass
|
||||
class ClubMember:
|
||||
|
||||
name: str
|
||||
guests: list = field(default_factory=list)
|
||||
|
||||
6
05-data-classes/dataclass/club_generic.py
Normal file
6
05-data-classes/dataclass/club_generic.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
@dataclass
|
||||
class ClubMember:
|
||||
name: str
|
||||
guests: list[str] = field(default_factory=list) # <1>
|
||||
9
05-data-classes/dataclass/club_wrong.py
Normal file
9
05-data-classes/dataclass/club_wrong.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
# tag::CLUBMEMBER[]
|
||||
@dataclass
|
||||
class ClubMember:
|
||||
|
||||
name: str
|
||||
guests: list = []
|
||||
# end::CLUBMEMBER[]
|
||||
23
05-data-classes/dataclass/coordinates.py
Normal file
23
05-data-classes/dataclass/coordinates.py
Normal file
@@ -0,0 +1,23 @@
|
||||
"""
|
||||
``Coordinate``: simple class decorated with ``dataclass`` and a custom ``__str__``::
|
||||
|
||||
>>> moscow = Coordinate(55.756, 37.617)
|
||||
>>> print(moscow)
|
||||
55.8°N, 37.6°E
|
||||
|
||||
"""
|
||||
|
||||
# tag::COORDINATE[]
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Coordinate:
|
||||
lat: float
|
||||
lon: float
|
||||
|
||||
def __str__(self):
|
||||
ns = 'N' if self.lat >= 0 else 'S'
|
||||
we = 'E' if self.lon >= 0 else 'W'
|
||||
return f'{abs(self.lat):.1f}°{ns}, {abs(self.lon):.1f}°{we}'
|
||||
# end::COORDINATE[]
|
||||
50
05-data-classes/dataclass/hackerclub.py
Normal file
50
05-data-classes/dataclass/hackerclub.py
Normal file
@@ -0,0 +1,50 @@
|
||||
# tag::DOCTESTS[]
|
||||
"""
|
||||
``HackerClubMember`` objects accept an optional ``handle`` argument::
|
||||
|
||||
>>> anna = HackerClubMember('Anna Ravenscroft', handle='AnnaRaven')
|
||||
>>> anna
|
||||
HackerClubMember(name='Anna Ravenscroft', guests=[], handle='AnnaRaven')
|
||||
|
||||
If ``handle`` is ommitted, it's set to the first part of the member's name::
|
||||
|
||||
>>> leo = HackerClubMember('Leo Rochael')
|
||||
>>> leo
|
||||
HackerClubMember(name='Leo Rochael', guests=[], handle='Leo')
|
||||
|
||||
Members must have a unique handle. The following ``leo2`` will not be created,
|
||||
because its ``handle`` would be 'Leo', which was taken by ``leo``::
|
||||
|
||||
>>> leo2 = HackerClubMember('Leo DaVinci')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: handle 'Leo' already exists.
|
||||
|
||||
To fix, ``leo2`` must be created with an explicit ``handle``::
|
||||
|
||||
>>> leo2 = HackerClubMember('Leo DaVinci', handle='Neo')
|
||||
>>> leo2
|
||||
HackerClubMember(name='Leo DaVinci', guests=[], handle='Neo')
|
||||
"""
|
||||
# end::DOCTESTS[]
|
||||
|
||||
# tag::HACKERCLUB[]
|
||||
from dataclasses import dataclass
|
||||
from club import ClubMember
|
||||
|
||||
@dataclass
|
||||
class HackerClubMember(ClubMember): # <1>
|
||||
|
||||
all_handles = set() # <2>
|
||||
|
||||
handle: str = '' # <3>
|
||||
|
||||
def __post_init__(self):
|
||||
cls = self.__class__ # <4>
|
||||
if self.handle == '': # <5>
|
||||
self.handle = self.name.split()[0]
|
||||
if self.handle in cls.all_handles: # <6>
|
||||
msg = f'handle {self.handle!r} already exists.'
|
||||
raise ValueError(msg)
|
||||
cls.all_handles.add(self.handle) # <7>
|
||||
# end::HACKERCLUB[]
|
||||
51
05-data-classes/dataclass/hackerclub_annotated.py
Normal file
51
05-data-classes/dataclass/hackerclub_annotated.py
Normal file
@@ -0,0 +1,51 @@
|
||||
# tag::DOCTESTS[]
|
||||
"""
|
||||
``HackerClubMember`` objects can be created with a ``name`` and an optional ``handle``::
|
||||
|
||||
>>> anna = HackerClubMember('Anna Ravenscroft', handle='AnnaRaven')
|
||||
>>> anna
|
||||
HackerClubMember(name='Anna Ravenscroft', guests=[], handle='AnnaRaven')
|
||||
|
||||
If ``handle`` is ommitted, it's set to the first part of the member's name::
|
||||
|
||||
>>> leo = HackerClubMember('Leo Rochael')
|
||||
>>> leo
|
||||
HackerClubMember(name='Leo Rochael', guests=[], handle='Leo')
|
||||
|
||||
Members must have a unique handle. This ``leo2`` will not be created,
|
||||
because its ``handle`` would be 'Leo', which was taken by ``leo``::
|
||||
|
||||
>>> leo2 = HackerClubMember('Leo DaVinci')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: handle 'Leo' already exists.
|
||||
|
||||
To fix, ``leo2`` must be created with an explicit ``handle``::
|
||||
|
||||
>>> leo2 = HackerClubMember('Leo DaVinci', handle='Neo')
|
||||
>>> leo2
|
||||
HackerClubMember(name='Leo DaVinci', guests=[], handle='Neo')
|
||||
"""
|
||||
# end::DOCTESTS[]
|
||||
|
||||
# tag::HACKERCLUB[]
|
||||
from dataclasses import dataclass
|
||||
from typing import ClassVar
|
||||
from club import ClubMember
|
||||
|
||||
@dataclass
|
||||
class HackerClubMember(ClubMember):
|
||||
|
||||
all_handles: ClassVar[set[str]] = set()
|
||||
|
||||
handle: str = ''
|
||||
|
||||
def __post_init__(self):
|
||||
cls = self.__class__
|
||||
if self.handle == '':
|
||||
self.handle = self.name.split()[0]
|
||||
if self.handle in cls.all_handles:
|
||||
msg = f'handle {self.handle!r} already exists.'
|
||||
raise ValueError(msg)
|
||||
cls.all_handles.add(self.handle)
|
||||
# end::HACKERCLUB[]
|
||||
87
05-data-classes/dataclass/resource.py
Normal file
87
05-data-classes/dataclass/resource.py
Normal file
@@ -0,0 +1,87 @@
|
||||
"""
|
||||
Media resource description class with subset of the Dublin Core fields.
|
||||
|
||||
Default field values:
|
||||
|
||||
>>> r = Resource('0')
|
||||
>>> r # doctest: +NORMALIZE_WHITESPACE
|
||||
Resource(identifier='0', title='<untitled>', creators=[], date=None,
|
||||
type=<ResourceType.BOOK: 1>, description='', language='', subjects=[])
|
||||
|
||||
A complete resource record:
|
||||
# tag::DOCTEST[]
|
||||
|
||||
>>> description = 'Improving the design of existing code'
|
||||
>>> book = Resource('978-0-13-475759-9', 'Refactoring, 2nd Edition',
|
||||
... ['Martin Fowler', 'Kent Beck'], date(2018, 11, 19),
|
||||
... ResourceType.BOOK, description, 'EN',
|
||||
... ['computer programming', 'OOP'])
|
||||
>>> book # doctest: +NORMALIZE_WHITESPACE
|
||||
Resource(identifier='978-0-13-475759-9', title='Refactoring, 2nd Edition',
|
||||
creators=['Martin Fowler', 'Kent Beck'], date=datetime.date(2018, 11, 19),
|
||||
type=<ResourceType.BOOK: 1>, description='Improving the design of existing code',
|
||||
language='EN', subjects=['computer programming', 'OOP'])
|
||||
|
||||
# end::DOCTEST[]
|
||||
"""
|
||||
|
||||
# tag::DATACLASS[]
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Optional
|
||||
from enum import Enum, auto
|
||||
from datetime import date
|
||||
|
||||
|
||||
class ResourceType(Enum): # <1>
|
||||
BOOK = auto()
|
||||
EBOOK = auto()
|
||||
VIDEO = auto()
|
||||
|
||||
|
||||
@dataclass
|
||||
class Resource:
|
||||
"""Media resource description."""
|
||||
identifier: str # <2>
|
||||
title: str = '<untitled>' # <3>
|
||||
creators: list[str] = field(default_factory=list)
|
||||
date: Optional[date] = None # <4>
|
||||
type: ResourceType = ResourceType.BOOK # <5>
|
||||
description: str = ''
|
||||
language: str = ''
|
||||
subjects: list[str] = field(default_factory=list)
|
||||
# end::DATACLASS[]
|
||||
|
||||
|
||||
from typing import TypedDict
|
||||
|
||||
|
||||
class ResourceDict(TypedDict):
|
||||
identifier: str
|
||||
title: str
|
||||
creators: list[str]
|
||||
date: Optional[date]
|
||||
type: ResourceType
|
||||
description: str
|
||||
language: str
|
||||
subjects: list[str]
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
r = Resource('0')
|
||||
description = 'Improving the design of existing code'
|
||||
book = Resource('978-0-13-475759-9', 'Refactoring, 2nd Edition',
|
||||
['Martin Fowler', 'Kent Beck'], date(2018, 11, 19),
|
||||
ResourceType.BOOK, description,
|
||||
'EN', ['computer programming', 'OOP'])
|
||||
print(book)
|
||||
book_dict: ResourceDict = {
|
||||
'identifier': '978-0-13-475759-9',
|
||||
'title': 'Refactoring, 2nd Edition',
|
||||
'creators': ['Martin Fowler', 'Kent Beck'],
|
||||
'date': date(2018, 11, 19),
|
||||
'type': ResourceType.BOOK,
|
||||
'description': 'Improving the design of existing code',
|
||||
'language': 'EN',
|
||||
'subjects': ['computer programming', 'OOP']}
|
||||
book2 = Resource(**book_dict)
|
||||
print(book == book2)
|
||||
111
05-data-classes/dataclass/resource_repr.py
Normal file
111
05-data-classes/dataclass/resource_repr.py
Normal file
@@ -0,0 +1,111 @@
|
||||
"""
|
||||
Media resource description class with subset of the Dublin Core fields.
|
||||
|
||||
Default field values:
|
||||
|
||||
>>> r = Resource('0')
|
||||
>>> r # doctest: +NORMALIZE_WHITESPACE
|
||||
Resource(
|
||||
identifier = '0',
|
||||
title = '<untitled>',
|
||||
creators = [],
|
||||
date = None,
|
||||
type = <ResourceType.BOOK: 1>,
|
||||
description = '',
|
||||
language = '',
|
||||
subjects = [],
|
||||
)
|
||||
|
||||
A complete resource record:
|
||||
|
||||
>>> description = 'Improving the design of existing code'
|
||||
>>> book = Resource('978-0-13-475759-9', 'Refactoring, 2nd Edition',
|
||||
... ['Martin Fowler', 'Kent Beck'], date(2018, 11, 19),
|
||||
... ResourceType.BOOK, description, 'EN',
|
||||
... ['computer programming', 'OOP'])
|
||||
|
||||
# tag::DOCTEST[]
|
||||
>>> book # doctest: +NORMALIZE_WHITESPACE
|
||||
Resource(
|
||||
identifier = '978-0-13-475759-9',
|
||||
title = 'Refactoring, 2nd Edition',
|
||||
creators = ['Martin Fowler', 'Kent Beck'],
|
||||
date = datetime.date(2018, 11, 19),
|
||||
type = <ResourceType.BOOK: 1>,
|
||||
description = 'Improving the design of existing code',
|
||||
language = 'EN',
|
||||
subjects = ['computer programming', 'OOP'],
|
||||
)
|
||||
|
||||
# end::DOCTEST[]
|
||||
"""
|
||||
|
||||
from dataclasses import dataclass, field, fields
|
||||
from typing import Optional, TypedDict
|
||||
from enum import Enum, auto
|
||||
from datetime import date
|
||||
|
||||
|
||||
class ResourceType(Enum):
|
||||
BOOK = auto()
|
||||
EBOOK = auto()
|
||||
VIDEO = auto()
|
||||
|
||||
|
||||
@dataclass
|
||||
class Resource:
|
||||
"""Media resource description."""
|
||||
identifier: str
|
||||
title: str = '<untitled>'
|
||||
creators: list[str] = field(default_factory=list)
|
||||
date: Optional[date] = None
|
||||
type: ResourceType = ResourceType.BOOK
|
||||
description: str = ''
|
||||
language: str = ''
|
||||
subjects: list[str] = field(default_factory=list)
|
||||
|
||||
# tag::REPR[]
|
||||
def __repr__(self):
|
||||
cls = self.__class__
|
||||
cls_name = cls.__name__
|
||||
indent = ' ' * 4
|
||||
res = [f'{cls_name}('] # <1>
|
||||
for f in fields(cls): # <2>
|
||||
value = getattr(self, f.name) # <3>
|
||||
res.append(f'{indent}{f.name} = {value!r},') # <4>
|
||||
|
||||
res.append(')') # <5>
|
||||
return '\n'.join(res) # <6>
|
||||
# end::REPR[]
|
||||
|
||||
|
||||
class ResourceDict(TypedDict):
|
||||
identifier: str
|
||||
title: str
|
||||
creators: list[str]
|
||||
date: Optional[date]
|
||||
type: ResourceType
|
||||
description: str
|
||||
language: str
|
||||
subjects: list[str]
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
r = Resource('0')
|
||||
description = 'Improving the design of existing code'
|
||||
book = Resource('978-0-13-475759-9', 'Refactoring, 2nd Edition',
|
||||
['Martin Fowler', 'Kent Beck'], date(2018, 11, 19),
|
||||
ResourceType.BOOK, description,
|
||||
'EN', ['computer programming', 'OOP'])
|
||||
print(book)
|
||||
book_dict: ResourceDict = {
|
||||
'identifier': '978-0-13-475759-9',
|
||||
'title': 'Refactoring, 2nd Edition',
|
||||
'creators': ['Martin Fowler', 'Kent Beck'],
|
||||
'date': date(2018, 11, 19),
|
||||
'type': ResourceType.BOOK,
|
||||
'description': 'Improving the design of existing code',
|
||||
'language': 'EN',
|
||||
'subjects': ['computer programming', 'OOP']}
|
||||
book2 = Resource(**book_dict)
|
||||
print(book == book2)
|
||||
64
05-data-classes/frenchdeck.doctest
Normal file
64
05-data-classes/frenchdeck.doctest
Normal file
@@ -0,0 +1,64 @@
|
||||
>>> from frenchdeck import FrenchDeck, Card
|
||||
>>> beer_card = Card('7', 'diamonds')
|
||||
>>> beer_card
|
||||
Card(rank='7', suit='diamonds')
|
||||
>>> deck = FrenchDeck()
|
||||
>>> len(deck)
|
||||
52
|
||||
>>> deck[:3]
|
||||
[Card(rank='2', suit='spades'), Card(rank='3', suit='spades'), Card(rank='4', suit='spades')]
|
||||
>>> deck[12::13]
|
||||
[Card(rank='A', suit='spades'), Card(rank='A', suit='diamonds'), Card(rank='A', suit='clubs'), Card(rank='A', suit='hearts')]
|
||||
>>> Card('Q', 'hearts') in deck
|
||||
True
|
||||
>>> Card('Z', 'clubs') in deck
|
||||
False
|
||||
>>> for card in deck: # doctest: +ELLIPSIS
|
||||
... print(card)
|
||||
Card(rank='2', suit='spades')
|
||||
Card(rank='3', suit='spades')
|
||||
Card(rank='4', suit='spades')
|
||||
...
|
||||
>>> for card in reversed(deck): # doctest: +ELLIPSIS
|
||||
... print(card)
|
||||
Card(rank='A', suit='hearts')
|
||||
Card(rank='K', suit='hearts')
|
||||
Card(rank='Q', suit='hearts')
|
||||
...
|
||||
>>> for n, card in enumerate(deck, 1): # doctest: +ELLIPSIS
|
||||
... print(n, card)
|
||||
1 Card(rank='2', suit='spades')
|
||||
2 Card(rank='3', suit='spades')
|
||||
3 Card(rank='4', suit='spades')
|
||||
...
|
||||
|
||||
Sort with *spades high* overall ranking
|
||||
|
||||
# tag::SPADES_HIGH[]
|
||||
>>> Card.suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0) # <1>
|
||||
>>> def spades_high(card): # <2>
|
||||
... rank_value = FrenchDeck.ranks.index(card.rank)
|
||||
... suit_value = card.suit_values[card.suit]
|
||||
... return rank_value * len(card.suit_values) + suit_value
|
||||
...
|
||||
>>> Card.overall_rank = spades_high # <3>
|
||||
>>> lowest_card = Card('2', 'clubs')
|
||||
>>> highest_card = Card('A', 'spades')
|
||||
>>> lowest_card.overall_rank() # <4>
|
||||
0
|
||||
>>> highest_card.overall_rank()
|
||||
51
|
||||
|
||||
# end::SPADES_HIGH[]
|
||||
|
||||
|
||||
>>> for card in sorted(deck, key=Card.overall_rank): # doctest: +ELLIPSIS
|
||||
... print(card)
|
||||
Card(rank='2', suit='clubs')
|
||||
Card(rank='2', suit='diamonds')
|
||||
Card(rank='2', suit='hearts')
|
||||
...
|
||||
Card(rank='A', suit='diamonds')
|
||||
Card(rank='A', suit='hearts')
|
||||
Card(rank='A', suit='spades')
|
||||
|
||||
17
05-data-classes/frenchdeck.py
Normal file
17
05-data-classes/frenchdeck.py
Normal file
@@ -0,0 +1,17 @@
|
||||
import collections
|
||||
|
||||
Card = collections.namedtuple('Card', ['rank', 'suit'])
|
||||
|
||||
class FrenchDeck:
|
||||
ranks = [str(n) for n in range(2, 11)] + list('JQKA')
|
||||
suits = 'spades diamonds clubs hearts'.split()
|
||||
|
||||
def __init__(self):
|
||||
self._cards = [Card(rank, suit) for suit in self.suits
|
||||
for rank in self.ranks]
|
||||
|
||||
def __len__(self):
|
||||
return len(self._cards)
|
||||
|
||||
def __getitem__(self, position):
|
||||
return self._cards[position]
|
||||
92
05-data-classes/match_cities.py
Normal file
92
05-data-classes/match_cities.py
Normal file
@@ -0,0 +1,92 @@
|
||||
"""
|
||||
match_cities.py
|
||||
"""
|
||||
|
||||
# tag::CITY[]
|
||||
import typing
|
||||
|
||||
class City(typing.NamedTuple):
|
||||
continent: str
|
||||
name: str
|
||||
country: str
|
||||
|
||||
|
||||
cities = [
|
||||
City('Asia', 'Tokyo', 'JP'),
|
||||
City('Asia', 'Delhi', 'IN'),
|
||||
City('North America', 'Mexico City', 'MX'),
|
||||
City('North America', 'New York', 'US'),
|
||||
City('South America', 'São Paulo', 'BR'),
|
||||
]
|
||||
# end::CITY[]
|
||||
|
||||
# tag::ASIA[]
|
||||
def match_asian_cities():
|
||||
results = []
|
||||
for city in cities:
|
||||
match city:
|
||||
case City(continent='Asia'):
|
||||
results.append(city)
|
||||
return results
|
||||
# end::ASIA[]
|
||||
|
||||
# tag::ASIA_POSITIONAL[]
|
||||
def match_asian_cities_pos():
|
||||
results = []
|
||||
for city in cities:
|
||||
match city:
|
||||
case City('Asia'):
|
||||
results.append(city)
|
||||
return results
|
||||
# end::ASIA_POSITIONAL[]
|
||||
|
||||
|
||||
# tag::ASIA_COUNTRIES[]
|
||||
def match_asian_countries():
|
||||
results = []
|
||||
for city in cities:
|
||||
match city:
|
||||
case City(continent='Asia', country=cc):
|
||||
results.append(cc)
|
||||
return results
|
||||
# end::ASIA_COUNTRIES[]
|
||||
|
||||
# tag::ASIA_COUNTRIES_POSITIONAL[]
|
||||
def match_asian_countries_pos():
|
||||
results = []
|
||||
for city in cities:
|
||||
match city:
|
||||
case City('Asia', _, country):
|
||||
results.append(country)
|
||||
return results
|
||||
# end::ASIA_COUNTRIES_POSITIONAL[]
|
||||
|
||||
|
||||
def match_india():
|
||||
results = []
|
||||
for city in cities:
|
||||
match city:
|
||||
case City(_, name, 'IN'):
|
||||
results.append(name)
|
||||
return results
|
||||
|
||||
|
||||
def match_brazil():
|
||||
results = []
|
||||
for city in cities:
|
||||
match city:
|
||||
case City(country='BR', name=name):
|
||||
results.append(name)
|
||||
return results
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
tests = ((n, f) for n, f in globals().items() if n.startswith('match_'))
|
||||
|
||||
for name, func in tests:
|
||||
print(f'{name:15}\t{func()}')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
8
05-data-classes/meaning/demo_dc.py
Normal file
8
05-data-classes/meaning/demo_dc.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass
|
||||
class DemoDataClass:
|
||||
|
||||
a: int # <1>
|
||||
b: float = 1.1 # <2>
|
||||
c = 'spam' # <3>
|
||||
7
05-data-classes/meaning/demo_nt.py
Normal file
7
05-data-classes/meaning/demo_nt.py
Normal file
@@ -0,0 +1,7 @@
|
||||
import typing
|
||||
|
||||
class DemoNTClass(typing.NamedTuple):
|
||||
|
||||
a: int # <1>
|
||||
b: float = 1.1 # <2>
|
||||
c = 'spam' # <3>
|
||||
5
05-data-classes/meaning/demo_plain.py
Normal file
5
05-data-classes/meaning/demo_plain.py
Normal file
@@ -0,0 +1,5 @@
|
||||
class DemoPlainClass:
|
||||
|
||||
a: int # <1>
|
||||
b: float = 1.1 # <2>
|
||||
c = 'spam' # <3>
|
||||
22
05-data-classes/typing_namedtuple/coordinates.py
Normal file
22
05-data-classes/typing_namedtuple/coordinates.py
Normal file
@@ -0,0 +1,22 @@
|
||||
"""
|
||||
``Coordinate``: a simple ``NamedTuple`` subclass with a custom ``__str__``::
|
||||
|
||||
>>> moscow = Coordinate(55.756, 37.617)
|
||||
>>> print(moscow)
|
||||
55.8°N, 37.6°E
|
||||
|
||||
"""
|
||||
|
||||
# tag::COORDINATE[]
|
||||
from typing import NamedTuple
|
||||
|
||||
class Coordinate(NamedTuple):
|
||||
|
||||
lat: float
|
||||
lon: float
|
||||
|
||||
def __str__(self):
|
||||
ns = 'N' if self.lat >= 0 else 'S'
|
||||
we = 'E' if self.lon >= 0 else 'W'
|
||||
return f'{abs(self.lat):.1f}°{ns}, {abs(self.lon):.1f}°{we}'
|
||||
# end::COORDINATE[]
|
||||
20
05-data-classes/typing_namedtuple/coordinates2.py
Normal file
20
05-data-classes/typing_namedtuple/coordinates2.py
Normal file
@@ -0,0 +1,20 @@
|
||||
"""
|
||||
``Coordinate``: a simple ``NamedTuple`` subclass
|
||||
|
||||
This version has a field with a default value::
|
||||
|
||||
>>> moscow = Coordinate(55.756, 37.617)
|
||||
>>> moscow
|
||||
Coordinate(lat=55.756, lon=37.617, reference='WGS84')
|
||||
|
||||
"""
|
||||
|
||||
# tag::COORDINATE[]
|
||||
from typing import NamedTuple
|
||||
|
||||
class Coordinate(NamedTuple):
|
||||
|
||||
lat: float # <1>
|
||||
lon: float
|
||||
reference: str = 'WGS84' # <2>
|
||||
# end::COORDINATE[]
|
||||
9
05-data-classes/typing_namedtuple/nocheck_demo.py
Normal file
9
05-data-classes/typing_namedtuple/nocheck_demo.py
Normal file
@@ -0,0 +1,9 @@
|
||||
import typing
|
||||
|
||||
class Coordinate(typing.NamedTuple):
|
||||
|
||||
lat: float
|
||||
lon: float
|
||||
|
||||
trash = Coordinate('Ni!', None) # <1>
|
||||
print(trash)
|
||||
Reference in New Issue
Block a user