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
190
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
300
On the Meaning of Version Numbers
hynek
0
320
Maintaining a Python Project When It’s Not Your Job
hynek
1
2.4k
How to Write Deployment-friendly Applications
hynek
0
2.5k
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.4k
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
The Implementations of Advanced LR Parser Algorithm
junk0612
1
1.1k
Road to RubyKaigi: Making Tinny Chiptunes with Ruby
makicamel
4
520
読書シェア会 vol.4 『ダイナミックリチーミング 第2版』
kotaro666
0
110
API for docs
soutaro
3
1.5k
設計の本質:コード、システム、そして組織へ / The Essence of Design: To Code, Systems, and Organizations
nrslib
10
3.6k
Contribute to Comunities | React Tokyo Meetup #4 LT
sasagar
0
580
eBPF超入門「o11yに使える」とは (20250424_eBPF_o11y)
thousanda
1
100
エンジニアが挑む、限界までの越境
nealle
1
290
2ヶ月で生産性2倍、お買い物アプリ「カウシェ」4チーム同時改善の取り組み
ike002jp
1
110
Amazon CloudWatchの地味だけど強力な機能紹介!
itotsum
0
210
State of Namespace
tagomoris
5
2.2k
七輪ライブラリー: Claude AI で作る Next.js アプリ
suneo3476
1
150
Featured
See All Featured
Speed Design
sergeychernyshev
29
920
Why You Should Never Use an ORM
jnunemaker
PRO
56
9.3k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
29
9.4k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
30
2.3k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.2k
Fashionably flexible responsive web design (full day workshop)
malarkey
407
66k
Raft: Consensus for Rubyists
vanstee
137
6.9k
Statistics for Hackers
jakevdp
798
220k
What’s in a name? Adding method to the madness
productmarketing
PRO
22
3.4k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
12k
Practical Orchestrator
shlominoach
187
11k
The Pragmatic Product Professional
lauravandoore
33
6.6k
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:tiger@redis.local: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:tiger@redis.local: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