Created
October 16, 2014 04:59
-
-
Save PuercoPop/28bdc9e55c0678ed9484 to your computer and use it in GitHub Desktop.
iPython Notebook para el sgte Python Meetup
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"metadata": { | |
"name": "" | |
}, | |
"nbformat": 3, | |
"nbformat_minor": 0, | |
"worksheets": [ | |
{ | |
"cells": [ | |
{ | |
"cell_type": "heading", | |
"level": 2, | |
"metadata": {}, | |
"source": [ | |
"Preludio" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"\u00bfQu\u00e9 es un _Abstract Syntax Tree_ **(AST)**?\n", | |
"\n", | |
"Es una **Estructura de Datos** que **representa** al **c\u00f3digo** de un programa. Son usados com\u00fanmente en herramientas de analysis est\u00e1tico y en el _backend_ de un compilador.\n", | |
"\n", | |
"Python nos da un [m\u00f3dulo](https://docs.python.org/2/library/ast.html) para interactuar con el." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"import ast" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [], | |
"prompt_number": 10 | |
}, | |
{ | |
"cell_type": "heading", | |
"level": 2, | |
"metadata": {}, | |
"source": [ | |
"Ejemplos" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"e = ast.parse(\"1 + 2\", mode=\"eval\")\n", | |
"e" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 24, | |
"text": [ | |
"<_ast.Expression at 0x1b0ca50>" | |
] | |
} | |
], | |
"prompt_number": 24 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"e.body" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 29, | |
"text": [ | |
"<_ast.BinOp at 0x1b0cad0>" | |
] | |
} | |
], | |
"prompt_number": 29 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"e.body.op" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 30, | |
"text": [ | |
"<_ast.Add at 0x10a0910>" | |
] | |
} | |
], | |
"prompt_number": 30 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"e.body.left" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 31, | |
"text": [ | |
"<_ast.Num at 0x1b0cb10>" | |
] | |
} | |
], | |
"prompt_number": 31 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"e.body.left.n" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 32, | |
"text": [ | |
"1" | |
] | |
} | |
], | |
"prompt_number": 32 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"code = \"\"\"\n", | |
"def add1(x):\n", | |
" return x + 1\n", | |
"\"\"\"\n", | |
"e = ast.parse(code) # Parse returns a Module object\n", | |
"e = e.body[0]\n", | |
"e" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 101, | |
"text": [ | |
"<_ast.FunctionDef at 0x1b26890>" | |
] | |
} | |
], | |
"prompt_number": 101 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"e.name" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 50, | |
"text": [ | |
"'add1'" | |
] | |
} | |
], | |
"prompt_number": 50 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"e.args" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 51, | |
"text": [ | |
"<_ast.arguments at 0x1b1d8d0>" | |
] | |
} | |
], | |
"prompt_number": 51 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"e.args.args" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 52, | |
"text": [ | |
"[<_ast.Name at 0x1b1d910>]" | |
] | |
} | |
], | |
"prompt_number": 52 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"e.args.args[0].id" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 55, | |
"text": [ | |
"'x'" | |
] | |
} | |
], | |
"prompt_number": 55 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"e.body" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 57, | |
"text": [ | |
"[<_ast.Return at 0x1b1d950>]" | |
] | |
} | |
], | |
"prompt_number": 57 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"e.body[0].value" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 59, | |
"text": [ | |
"<_ast.BinOp at 0x1b1d990>" | |
] | |
} | |
], | |
"prompt_number": 59 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"ast.dump(e)" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 102, | |
"text": [ | |
"\"FunctionDef(name='add1', args=arguments(args=[Name(id='x', ctx=Param())], vararg=None, kwarg=None, defaults=[]), body=[Return(value=BinOp(left=Name(id='x', ctx=Load()), op=Add(), right=Num(n=1)))], decorator_list=[])\"" | |
] | |
} | |
], | |
"prompt_number": 102 | |
}, | |
{ | |
"cell_type": "heading", | |
"level": 2, | |
"metadata": {}, | |
"source": [ | |
"Problema" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Pepit O. \u2661 la brevedad por sobre la facilidad de razonamiento y correcci\u00f3n. Ergo escribe c\u00f3digo como el siguiente por mas de las advertencias de Pepit A. Puede manejar las complicaciones, total es un Real Programmer\u2122" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"def _push(elem, xs=[]):\n", | |
" xs.append(elem)\n", | |
" return xs" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [], | |
"prompt_number": 65 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"x1 = _push(0)\n", | |
"x1" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 66, | |
"text": [ | |
"[0]" | |
] | |
} | |
], | |
"prompt_number": 66 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"x2 = _push(1, _push(2, _push(3)))\n", | |
"x2" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 68, | |
"text": [ | |
"[0, 3, 2, 1]" | |
] | |
} | |
], | |
"prompt_number": 68 | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"en vez" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"def __push(elem, xs=None):\n", | |
" if xs is None:\n", | |
" xs = []\n", | |
" xs.append(elem)\n", | |
" return xs" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [], | |
"prompt_number": 71 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"x1 = __push(0)\n", | |
"x1" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 73, | |
"text": [ | |
"[0]" | |
] | |
} | |
], | |
"prompt_number": 73 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"x2 = __push(1, __push(2, __push(3)))\n", | |
"x2" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 75, | |
"text": [ | |
"[3, 2, 1]" | |
] | |
} | |
], | |
"prompt_number": 75 | |
}, | |
{ | |
"cell_type": "heading", | |
"level": 2, | |
"metadata": {}, | |
"source": [ | |
"Soluci\u00f3n" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Rescribir el AST para detectar el anti-patr\u00f3n y cambiarlo por el c\u00f3digo correcto sin herir los sentimientos de Pepit O." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"bad_code = \"\"\"def push(elem, xs=[]):\n", | |
" xs.append(elem)\n", | |
" return xs\n", | |
"\n", | |
"x1 = push(5)\n", | |
"print \"x1 = push(5)\"\n", | |
"print \"x1:\", x1\n", | |
"x2 = push(7)\n", | |
"print \"x2 = push(7)\"\n", | |
"print \"x2:\", x2\"\"\"\n", | |
"\n", | |
"c = ast.parse(bad_code)\n", | |
"c.body\n" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 124, | |
"text": [ | |
"[<_ast.FunctionDef at 0x1c0d850>,\n", | |
" <_ast.Assign at 0x1c0da50>,\n", | |
" <_ast.Print at 0x1c0dcd0>,\n", | |
" <_ast.Print at 0x1c0dd90>,\n", | |
" <_ast.Assign at 0x1c0dd50>,\n", | |
" <_ast.Print at 0x1c0df50>,\n", | |
" <_ast.Print at 0x1c0dfd0>]" | |
] | |
} | |
], | |
"prompt_number": 124 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"good_code = \"\"\"\n", | |
"def push(elem, xs=None):\n", | |
" if xs is None:\n", | |
" xs = []\n", | |
" xs.append(elem)\n", | |
" return xs\"\"\"" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [], | |
"prompt_number": 99 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"# Ad-hoc\n", | |
"class DetectArgList(ast.NodeVisitor):\n", | |
" def visit_FunctionDef(self, node):\n", | |
" if isinstance(node.args.defaults[0], ast.List):\n", | |
" print \"Danger Will Robison\"\n", | |
" else:\n", | |
" print \"What a Wonderful world\"\n", | |
"DetectArgList().visit(ast.parse(bad_code))" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"Danger Will Robison\n" | |
] | |
} | |
], | |
"prompt_number": 110 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"DetectArgList().visit(ast.parse(good_code))" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"What a Wonderful world\n" | |
] | |
} | |
], | |
"prompt_number": 115 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"# Proper\n", | |
"class DetectArgList(ast.NodeVisitor):\n", | |
" def visit_FunctionDef(self, node):\n", | |
" if reduce(lambda x, y: x or y, [ isinstance(x, ast.List) for x in node.args.defaults ]):\n", | |
" print \"Danger Will Robison\"\n", | |
" else:\n", | |
" print \"What a Wonderful world\"" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [], | |
"prompt_number": 114 | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Una vez detectado el anti-patr\u00f3n hay que cambiar el default por None e insertar la inicializaci\u00f3n condicional" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"# Ad-Hoc\n", | |
"class FixList(ast.NodeTransformer):\n", | |
" def visit_FunctionDef(self, node):\n", | |
" if any([ isinstance(x, ast.List) for x in node.args.defaults ]):\n", | |
" node.args.defaults[0] = ast.Name('None', ast.Load())\n", | |
" arg_name = node.args.args[-1].id\n", | |
" fix = ast.parse(\"if {name} is None:\\n {name} = []\".format(name=arg_name)).body[0]\n", | |
" node.body.insert(0, fix)\n", | |
" return ast.fix_missing_locations(node)\n", | |
" else:\n", | |
" return node" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [], | |
"prompt_number": 136 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"# Proper\n", | |
"class FixList(ast.NodeTransformer):\n", | |
" def visit_FunctionDef(self, node):\n", | |
" for index, default_arg in enumerate(node.args.defaults):\n", | |
" if isinstance(default_arg, ast.List):\n", | |
" node.args.defaults[index] = ast.Name('None', ast.Load())\n", | |
" arg_name = node.args.args[-1 - index].id\n", | |
" fix = ast.parse(\"if {name} is None:\\n {name} = []\".format(name=arg_name)).body[0]\n", | |
" node.body.insert(0, fix)\n", | |
" return ast.fix_missing_locations(node)" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [], | |
"prompt_number": 167 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"exec(compile(ast.parse(bad_code), filename=\"\", mode=\"exec\"))" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"x1 = push(5)\n", | |
"x1: [5]\n", | |
"x2 = push(7)\n", | |
"x2: [5, 7]\n" | |
] | |
} | |
], | |
"prompt_number": 128 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"exec(compile(FixList().visit(ast.parse(bad_code)), filename=\"\", mode=\"exec\"))" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"x1 = push(5)\n", | |
"x1: [5]\n", | |
"x2 = push(7)\n", | |
"x2: [7]\n" | |
] | |
} | |
], | |
"prompt_number": 148 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"badder_code = \"\"\"\n", | |
"def push(elem, xs=[], ys=[]):\n", | |
" xs.append(elem)\n", | |
" ys.insert(0, elem)\n", | |
" return xs, ys\n", | |
"\n", | |
"x1, y1 = push(5)\n", | |
"print \"x1, y1 = push(5)\"\n", | |
"print \"x1:\", x1, \" y1:\", y1\n", | |
"x2, y2 = push(7)\n", | |
"print \"x2, y2 = push(7)\"\n", | |
"print \"x2:\", x2, \" y2:\", y2\n", | |
"\"\"\"\n", | |
"exec(compile(FixList().visit(ast.parse(badder_code)), filename=\"\", mode=\"exec\"))" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"x1, y1 = push(5)\n", | |
"x1: [5] y1: [5]\n", | |
"x2, y2 = push(7)\n", | |
"x2: [7] y2: [7]\n" | |
] | |
} | |
], | |
"prompt_number": 168 | |
}, | |
{ | |
"cell_type": "heading", | |
"level": 1, | |
"metadata": {}, | |
"source": [ | |
"Enlaces de Inter\u00e9s" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"- [Racket Optimization Coach](http://www.ccs.neu.edu/home/stamourv/papers/optimization-coaching.pdf), revisa tus types declaration y te da sugerencias sobre como hacerlas m\u00e1s precisas y permitir que el compilador genere c\u00f3digo m\u00e1s eficiente.\n", | |
"- [MacroPy](https://github.com/lihaoyi/macropy), agrega una etapa adicional de 'macroe-expansi\u00f3n' para agregar transformaciones sint\u00e1cticas a Python (Macros).\n", | |
"- [Hylang](http://docs.hylang.org/en/latest/), un Clojure-inspired Lisp que compila al Python AST." | |
] | |
} | |
], | |
"metadata": {} | |
} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment