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
Boost Your Performance and Developer Productivity with Jakarta EE 11
ivargrimstad
0
390
Bedrock×MCPで社内ブログ執筆文化を育てたい!
har1101
6
1.2k
AIコーディングエージェントを 「使いこなす」ための実践知と現在地 in ログラス / How to Use AI Coding Agent in Loglass
rkaga
4
1k
SwiftUI API Design Lessons
niw
1
300
スモールスタートで始めるためのLambda×モノリス(Lambdalith)
akihisaikeda
2
300
ASP.NETアプリケーションのモダナイゼーションについて
tomokusaba
0
140
2ヶ月で生産性2倍、お買い物アプリ「カウシェ」4チーム同時改善の取り組み
ike002jp
1
100
The Implementations of Advanced LR Parser Algorithm
junk0612
1
860
Fiber Scheduler vs. General-Purpose Parallel Client
hayaokimura
1
210
Optimizing JRuby 10
headius
0
510
Make Parsers Compatible Using Automata Learning
makenowjust
2
5.8k
Vibe Coding の話をしよう
schroneko
12
3.3k
Featured
See All Featured
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
47
5.3k
Documentation Writing (for coders)
carmenintech
69
4.7k
Adopting Sorbet at Scale
ufuk
76
9.3k
Build The Right Thing And Hit Your Dates
maggiecrowley
35
2.7k
The Language of Interfaces
destraynor
157
25k
How GitHub (no longer) Works
holman
314
140k
Building a Scalable Design System with Sketch
lauravandoore
462
33k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
129
19k
Why You Should Never Use an ORM
jnunemaker
PRO
56
9.3k
Gamification - CAS2011
davidbonilla
81
5.2k
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
Building a Modern Day E-commerce SEO Strategy
aleyda
40
7.2k
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