Slide 1

Slide 1 text

PyCon APAC 2 0 2 3 Unconference Track 2 , starts at 4 : 35 pm AST as Black Magic Takumi Sueda @puhitaku

Slide 2

Slide 2 text

defer.py 2

Slide 3

Slide 3 text

defer.py github.com/dankeyy/defer.py 3

Slide 4

Slide 4 text

from defer import defers @defers def func(): print(1) defer: print(3) print(2) func() defer.py Deferring a function call as seen in Go ... but Python can do it too with AST magic 4 1 2 3 Code Output

Slide 5

Slide 5 text

from defer import defers @defers def func(): print(1) defer: print(3) print(2) func() defer.py This highlighted line (mis)uses "Variable annotations" proposed in PEP 52 6 . Variable annotations can accept arbitrary expression as the annotation. @defers decorater replaces the annotation line to a deferred func call. 5

Slide 6

Slide 6 text

defer.py Possible usage of defer.py 6 def func(): with foo() as a: with bar() as b: with baz() as c: . .. @defers def func(): a = foo() defer: a.close() b = bar() defer: b.close() c = baz() defer: c.close() ... You can turn this ... ... into this

Slide 7

Slide 7 text

Additional simple example of AST black magic 7

Slide 8

Slide 8 text

defer.py A totally valid Python script and the output 8 @conversationize def foo(): Alice: "Hi there" Bob: "Ayo, sup" Xzibit: "Yo dawg, I heard you like Python so I put Python in yo Python so you can eval while you eval" Alice says: Hi there Bob says: Ayo, sup Xzibit says: Yo dawg, I heard you like Python so I put Python in yo Python so you can eval while you eval

Slide 9

Slide 9 text

How? 9

Slide 10

Slide 10 text

• ast.NodeTransformer • ast.parse() • inspect.getsource() 10

Slide 11

Slide 11 text

import ast import inspect def conversationize(f): class Transformer(ast.NodeTransformer): def visit_AnnAssign(self, node): print(f'{node.target.id} says: {node.annotation.value}') def wrapper(): tree = ast.parse(inspect.getsource(f)) assert len(tree.body) == 1 and isinstance(tree.body[0], ast.FunctionDef), "should be a function" Transformer().visit(tree.body[0]) return wrapper @conversationize def foo(): Alice: "Hi there" 11 The implementation of the example decorator "conversationize"

Slide 12

Slide 12 text

Have fun ... with a enough care of readability! 12