Upgrade to Pro — share decks privately, control downloads, hide ads and more …

AST as Black Magic

AST as Black Magic

PyCon APAC 2023 - Unconference Track 2 4:35 pm

Takumi Sueda

October 27, 2023
Tweet

More Decks by Takumi Sueda

Other Decks in Technology

Transcript

  1. PyCon APAC
    2
    0 2
    3

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

    View full-size slide

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

    View full-size slide

  3. 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

    View full-size slide

  4. 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

    View full-size slide

  5. 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

    View full-size slide

  6. Additional simple example of AST black magic
    7

    View full-size slide

  7. 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


    View full-size slide

  8. • ast.NodeTransformer


    • ast.parse()


    • inspect.getsource()
    10

    View full-size slide

  9. 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"

    View full-size slide

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

    View full-size slide