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
200
On the Meaning of Version Numbers
hynek
0
280
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
のびしろを広げる巻き込まれ力:偶然を活かすキャリアの作り方/oso2024
takahashiikki
1
410
詳細解説! ArrayListの仕組みと実装
yujisoftware
0
480
Vue3の一歩踏み込んだパフォーマンスチューニング2024
hal_spidernight
3
3.1k
讓數據說話:用 Python、Prometheus 和 Grafana 講故事
eddie
0
350
Outline View in SwiftUI
1024jp
1
110
hotwire_or_react
harunatsujita
8
4k
EventSourcingの理想と現実
wenas
6
2.1k
WEBエンジニア向けAI活用入門
sutetotanuki
0
300
Identifying User Idenity
moro
6
7.8k
Server Driven Compose With Firebase
skydoves
0
390
Webの技術スタックで マルチプラットフォームアプリ開発を可能にするElixirDesktopの紹介
thehaigo
2
910
C#/.NETのこれまでのふりかえり
tomokusaba
1
150
Featured
See All Featured
Why You Should Never Use an ORM
jnunemaker
PRO
53
9k
jQuery: Nuts, Bolts and Bling
dougneiner
61
7.5k
Bootstrapping a Software Product
garrettdimon
PRO
305
110k
Producing Creativity
orderedlist
PRO
341
39k
Documentation Writing (for coders)
carmenintech
65
4.4k
The World Runs on Bad Software
bkeepers
PRO
65
11k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
246
1.3M
Done Done
chrislema
181
16k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
191
16k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
92
16k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
7
150
Fantastic passwords and where to find them - at NoRuKo
philnash
50
2.8k
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