Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Classy Abstractions @ Python Web Conf
Search
Hynek Schlawack
June 18, 2020
Programming
0
170
Classy Abstractions @ Python Web Conf
Hynek Schlawack
June 18, 2020
Tweet
Share
More Decks by Hynek Schlawack
See All by Hynek Schlawack
Subclassing, Composition, Python, and You
hynek
3
100
On the Meaning of Version Numbers
hynek
0
270
Maintaining a Python Project When It’s Not Your Job
hynek
1
2.3k
How to Write Deployment-friendly Applications
hynek
0
2.5k
Solid Snakes or: How to Take 5 Weeks of Vacation
hynek
2
5.7k
Get Instrumented: How Prometheus Can Unify Your Metrics
hynek
4
11k
Beyond grep – PyCon JP
hynek
1
3.3k
Beyond grep – EuroPython Edition
hynek
1
10k
Beyond grep: Practical Logging and Metrics
hynek
3
1.2k
Other Decks in Programming
See All in Programming
5年分のツケを一気に払った話
soogie
3
1k
モジュラモノリス、その前に / Modular monolith, before that
euglena1215
4
400
Pydantic x Database API:turu-pyの開発
yassun7010
1
400
NANIMACHI
naokiito
0
930
Beyond the RuboCop Defaults
koic
2
480
Flutterアプリを生成AIで生成する勘所
rizumita
0
240
Infrastructure as Code でセキュリティを楽にしよう!
konokenj
5
1.4k
Applied NLP in the Age of Generative AI
inesmontani
PRO
3
1.1k
tsconfig.jsonの最近の新機能 ファイルパス編
uhyo
6
1.3k
フロントエンドの現在地とこれから
koba04
3
1.4k
利用者視点で考える、イテレータとの上手な付き合い方
syumai
4
210
Kubernetes上でOracle_Databaseの運用を楽にするOraOperatorの紹介
nnaka2992
0
140
Featured
See All Featured
Teambox: Starting and Learning
jrom
131
8.7k
[RailsConf 2023] Rails as a piece of cake
palkan
49
4.7k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
246
1.3M
Optimizing for Happiness
mojombo
375
69k
The Brand Is Dead. Long Live the Brand.
mthomps
53
38k
Infographics Made Easy
chrislema
239
18k
WebSockets: Embracing the real-time Web
robhawkes
59
7.3k
Docker and Python
trallard
40
3k
Into the Great Unknown - MozCon
thekraken
30
1.4k
GitHub's CSS Performance
jonrohan
1030
450k
The Cult of Friendly URLs
andyhume
76
6k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
29
1.7k
Transcript
Classy Abstractions Hynek Schlawack
[({},),({},)]
Primitive Obsession
Premature Optimization
None
–me, today “You’re wasting precious resources if you use a
high-level language but only use low-level primitives.”
None
PATHLIB
PATHLIB >>> p = Path() / "foo" / "bar"
PATHLIB >>> p = Path() / "foo" / "bar" >>>
p.absolute() PosixPath('/Users/hynek/foo/bar') >>> p.absolute() WindowsPath('C:/Users/Hynek Schlawack/foo/bar')
PATHLIB >>> p = Path() / "foo" / "bar" >>>
p.absolute() PosixPath('/Users/hynek/foo/bar') >>> p.absolute() WindowsPath('C:/Users/Hynek Schlawack/foo/bar') >>> p.name 'bar'
PATHLIB >>> p = Path() / "foo" / "bar" >>>
p.absolute() PosixPath('/Users/hynek/foo/bar') >>> p.absolute() WindowsPath('C:/Users/Hynek Schlawack/foo/bar') >>> p.name 'bar' >>> Path("README.md").read_text() ...
IPADDRESS
IPADDRESS >>> i = ipaddress.ip_address("::1") >>> i.exploded '0000:0000:0000:0000:0000:0000:0000:0001'
IPADDRESS >>> i = ipaddress.ip_address("::1") >>> i.exploded '0000:0000:0000:0000:0000:0000:0000:0001' >>> ipaddress.ip_address("10.23.45.56")
\ in ipaddress.ip_network("10.0.0.0/8") True
• /?a=fetch&content=<php>die(@md5(HelloThinkCMF))</php> • /wp-content/plugins/google-document-embedder/libs/pdf.php? fn=lol.pdf&file=../../../../wp-config.php • /wp-admin/admin-ajax.php?action=kbslider_show_image&img=../ wp-config.php
YARL
YARL >>> u = yarl.URL("https://hynek.me/articles/")
YARL >>> u = yarl.URL("https://hynek.me/articles/") >>> u.host 'hynek.me' >>> u.path
'/articles/'
YARL >>> u = yarl.URL("https://hynek.me/articles/") >>> u.host 'hynek.me' >>> u.path
'/articles/' >>> u / "speaking/" URL('https://hynek.me/articles/speaking/')
YARL >>> u = yarl.URL("https://hynek.me/articles/") >>> u.host 'hynek.me' >>> u.path
'/articles/' >>> u / "speaking/" URL('https://hynek.me/articles/speaking/') >>> u.with_path("about/") URL('https://hynek.me/about/')
>>> u = yarl.URL.build( scheme="redis", user="scott", password="tiger", host="redis.local", port=369, path="/1",
query={"socket_timeout": 42}) >>> u URL('redis://scott:
[email protected]
:369/1?socket_timeout=42')
>>> u = yarl.URL.build( scheme="redis", user="scott", password="tiger", host="redis.local", port=369, path="/1",
query={"socket_timeout": 42}) >>> u URL('redis://scott:
[email protected]
:369/1?socket_timeout=42') >>> redis.ConnectionPool.from_url(str(u))
None
def f(a=False, b=False, c=False): ... f(b=True)
def f(a=False, b=False, c=False): ... f(b=True) def f(what): ... f("b")
None
ENUM from enum import Enum class What(Enum): A = "a"
B = "b" C = "c"
ENUM from enum import Enum class What(Enum): A = "a"
B = "b" C = "c" f(What.A)
ENUM from enum import Enum class What(Enum): A = "a"
B = "b" C = "c" def f(what: What): ... f(What.D) f(What.A)
ENUM from enum import Enum class What(Enum): A = "a"
B = "b" C = "c" def f(what: What): ... f(What.D) f(What.A) error: "Type[What]" has no attribute "D"
@app.route("/") def view(): return { "foo": "bar" }
@app.route("/") def view(): return { "data": { "id": "some-id", "type":
"example", "attributes": { "foo": "bar" } } "links": "http://localhost/", }
@bp.route("/<int:id>", methods=["GET"]) def get_dns_record(id: int) -> APIResult: try: return APIResult(
get_uow().dns_records.get(id) ) except UnknownDNSRecordError: raise_not_found("DNS record", id)
@bp.route("/<int:id>", methods=["GET"]) def get_dns_record(id: int) -> APIResult: try: return APIResult(
get_uow().dns_records.get(id) ) except UnknownDNSRecordError: raise_not_found("DNS record", id)
@bp.route("/", methods=["POST"]) @validated_body def create_dns_record(ndr: CreateDNSRecord) -> APIResult: try: dr_id
= svc.create_record( get_uow(), ndr.domain, # ... ) except PlanError as e: raise APIError( id=error_ids.PLAN_NOT_SUFFICIENT, status="402", title=e.args[0], source={"pointer": "/data/attributes/domain"}, ) # ...
@bp.route("/", methods=["POST"]) @validated_body def create_dns_record(ndr: CreateDNSRecord) -> APIResult: try: dr_id
= svc.create_record( get_uow(), ndr.domain, # ... ) except PlanError as e: raise APIError( id=error_ids.PLAN_NOT_SUFFICIENT, status="402", title=e.args[0], source={"pointer": "/data/attributes/domain"}, ) # ...
@bp.route("/", methods=["POST"]) @validated_body def create_dns_record(ndr: CreateDNSRecord) -> APIResult: try: dr_id
= svc.create_record( get_uow(), ndr.domain, # ... ) except PlanError as e: raise APIError( id=error_ids.PLAN_NOT_SUFFICIENT, status="402", title=e.args[0], source={"pointer": "/data/attributes/domain"}, ) # ...
@bp.route("/", methods=["POST"]) @validated_body def create_dns_record(ndr: CreateDNSRecord) -> APIResult: try: dr_id
= svc.create_record( get_uow(), ndr.domain, # ... ) except PlanError as e: raise APIError( id=error_ids.PLAN_NOT_SUFFICIENT, status="402", title=e.args[0], source={"pointer": "/data/attributes/domain"}, ) # ...
Locked Un- locked
Locked Un- locked Start
Locked Un- locked Insert Coin Start
Locked Un- locked Insert Coin Push Start
Locked Un- locked Insert Coin Push Insert Coin Start
Locked Un- locked Push Insert Coin Push Insert Coin Start
Classes
None
None
None
None
“Dunder” double underscores: •__init__ •__eq__ •...
class Point(namedtuple('Point', ['x', 'y'])): __slots__ = () @property def hypot(self):
return (self.x ** 2 + self.y ** 2) ** 0.5 def __str__(self): return 'Point: x=%6.3f y=%6.3f hypot=%6.3f' % ( self.x, self.y, self.hypot)
class Point(namedtuple('Point', ['x', 'y'])): __slots__ = () @property def hypot(self):
return (self.x ** 2 + self.y ** 2) ** 0.5 def __str__(self): return 'Point: x=%6.3f y=%6.3f hypot=%6.3f' % ( self.x, self.y, self.hypot) >>> Point.__mro__ (<class '__main__.Point'>, <class '__main__.Point'>, <class 'tuple'>, <class 'object'>)
CHARACTERISTIC @attributes( ["a"], defaults={"a": 42} ) class C: pass
@attr.s class Point: x = attr.ib() y = attr.ib() @property
def hypot(self): return (self.x ** 2 + self.y ** 2) ** 0.5 def __str__(self): return 'Point: x=%6.3f y=%6.3f hypot=%6.3f' % ( self.x, self.y, self.hypot)
None
Dataclasses
@dataclasses.dataclass class Point: x: int y: int @attr.dataclass class Point:
x: int y: int
None
• 2.7
• 2.7 • __slots__
• 2.7 • __slots__ • types optional
• 2.7 • __slots__ • types optional • validators/converters
• 2.7 • __slots__ • types optional • validators/converters •
free to innovate
from attrs import define, field @define class Point3D: x: int
y: int z: int = field( validator=positive )
None
• embrace abstractions
• embrace abstractions • don’t be afraid of classes
• embrace abstractions • don’t be afraid of classes •
wear your masks
ox.cx/a @hynek hynek.me vrmd.de