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
200
Classy Abstractions @ Python Web Conf
Hynek Schlawack
June 18, 2020
Tweet
Share
More Decks by Hynek Schlawack
See All by Hynek Schlawack
Design Pressure
hynek
0
1.5k
Subclassing, Composition, Python, and You
hynek
3
350
On the Meaning of Version Numbers
hynek
0
340
Maintaining a Python Project When It’s Not Your Job
hynek
1
2.4k
How to Write Deployment-friendly Applications
hynek
0
2.6k
Solid Snakes or: How to Take 5 Weeks of Vacation
hynek
2
5.8k
Get Instrumented: How Prometheus Can Unify Your Metrics
hynek
4
11k
Beyond grep – PyCon JP
hynek
1
3.5k
Beyond grep – EuroPython Edition
hynek
1
10k
Other Decks in Programming
See All in Programming
設計やレビューに悩んでいるPHPerに贈る、クリーンなオブジェクト設計の指針たち
panda_program
6
1.9k
CursorはMCPを使った方が良いぞ
taigakono
1
240
Is Xcode slowly dying out in 2025?
uetyo
1
260
Blazing Fast UI Development with Compose Hot Reload (droidcon New York 2025)
zsmb
1
280
Deep Dive into ~/.claude/projects
hiragram
12
2.4k
今ならAmazon ECSのサービス間通信をどう選ぶか / Selection of ECS Interservice Communication 2025
tkikuc
21
3.9k
A2A プロトコルを試してみる
azukiazusa1
2
1.3k
ペアプロ × 生成AI 現場での実践と課題について / generative-ai-in-pair-programming
codmoninc
1
15k
WindowInsetsだってテストしたい
ryunen344
1
240
datadog dash 2025 LLM observability for reliability and stability
ivry_presentationmaterials
0
460
明示と暗黙 ー PHPとGoの インターフェイスの違いを知る
shimabox
2
480
ruby.wasmで多人数リアルタイム通信ゲームを作ろう
lnit
3
440
Featured
See All Featured
Practical Orchestrator
shlominoach
188
11k
Raft: Consensus for Rubyists
vanstee
140
7k
GitHub's CSS Performance
jonrohan
1031
460k
GraphQLの誤解/rethinking-graphql
sonatard
71
11k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
46
9.6k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.4k
Fantastic passwords and where to find them - at NoRuKo
philnash
51
3.3k
StorybookのUI Testing Handbookを読んだ
zakiyama
30
5.9k
Product Roadmaps are Hard
iamctodd
PRO
54
11k
Optimising Largest Contentful Paint
csswizardry
37
3.3k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
20
1.3k
Producing Creativity
orderedlist
PRO
346
40k
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