How to create a function object from an ast.FunctionDef node?
Asked Answered
T

2

8

I am trying to understand the process by which python code gets executed. Suppose the source has a function definition. Using ast.parse(), I parse it into an ast, which will contain an instance of the FunctionDef node class. This node instance is not a callable and is not the same as the function object. How can the function object, with all its dunder attributes, be created from this ast?

Trevethick answered 13/2, 2018 at 5:10 Comment(3)
I want to know how to create the function object from the ast, if it is not the same as an ast node?Trevethick
Right from the top of the ast module documentation: "An abstract syntax tree can be compiled into a Python code object using the built-in compile() function."Laaspere
That gives me a code object which is not the same as a function object. I think I would need to further execute that code object with exec() to create the actual function object.Trevethick
T
18

You can't (as far as I know) compile an arbitrary individual AST node like a FunctionDef. What you can do is compile the entire code snippet as a module, exec it in a provided namespace, and then access its contents, including the function. Here's an example:

import ast

txt = """
def foo(x, y=2):
    z = x*y + 3
    print("z is", z)
    return z**2
"""

tree = ast.parse(txt, mode='exec')
code = compile(tree, filename='blah', mode='exec')
namespace = {}
exec(code, namespace)

Now namespace is the equivalent of the __dict__ of a module containing the given code. You can access and call the function:

>>> namespace['foo']
<function foo at 0x00000000023A2B70>
>>> namespace['foo'](2, 3)
z is 9
81

Note that if this is all you want to do, there's no need to use ast at all. You can just compile the source string directly with compile(tree, filename='blah', mode='exec'). And in fact there's no need to even involve compile, since you can just exec the source string directly with exec(txt, namespace). If your goal is just to get the final function object out, you don't really need access to the internal parse and compile steps; just exec the whole thing in a namespace and then grab the function from there.

Thermomotor answered 13/2, 2018 at 6:3 Comment(3)
This is the answer I was expecting. Thanks for making it clear. What happened to the output of the print in your example function?Trevethick
@debashish: Oops, I accidentally trimmed it out when formatting the output. I edited my example to include it, and make the print a bit more informative so the connection is more clear.Thermomotor
So this essentially shows how to parse a string (or template file) with python ast, compile it and then call a function within that ast.</SEO because I couldn't find this as easily as I wanted to ;)>Matthews
L
0

In case the function is under a class, below code will help - import ast

txt = """
class MyClass():
  def foo(x, y=2):
      z = x*y + 3
      print("z is", z)
      return z**2
"""

tree = ast.parse(txt, mode='exec')
code = compile(tree, filename='blah', mode='exec')
namespace = {}
exec(code, namespace)
val = "foo"
dict_item = namespace["MyClass"].__dict__.items()
for x,y in list(dict_item):
  if val == x:
    print(x)
    print(y)
    print(type(x))
    print(type(y))
Lifesize answered 1/10, 2020 at 0:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.