在Python中反思给定函数的嵌套(本地)函数

时间:2009-08-05 17:36:16

标签: python function introspection inspect

鉴于功能

def f():
    x, y = 1, 2 
    def get():
        print 'get'
    def post():
        print 'post'

我有办法以我可以调用它们的方式访问其本地get()和post()函数吗?我正在寻找一个可以使用上面定义的函数f()的函数:

>>> get, post = get_local_functions(f)
>>> get()
'get'

我可以访问像这样的本地函数的代码对象

import inspect
for c in f.func_code.co_consts:
    if inspect.iscode(c):
        print c.co_name, c

导致

get <code object get at 0x26e78 ...>
post <code object post at 0x269f8 ...>

但我无法弄清楚如何获取实际的可调用函数对象。这甚至可能吗?

感谢您的帮助,

威尔

4 个答案:

答案 0 :(得分:4)

你已经非常接近了 - 只是缺少new模块:

import inspect
import new

def f():
    x, y = 1, 2
    def get():
        print 'get'
    def post():
        print 'post'

for c in f.func_code.co_consts:
    if inspect.iscode(c):
        f = new.function(c, globals())
        print f # Here you have your function :].

但为什么麻烦呢?使用课程不是更容易吗?无论如何,实例化看起来像一个函数调用。

答案 1 :(得分:2)

您可以像在Python中的任何其他对象一样返回函数:

def f():
    x, y = 1, 2 
    def get():
        print 'get'
    def post():
        print 'post'
    return (get, post)


get, post = f()

希望这有帮助!

但请注意,如果要在get()或post()中使用'x'和'y'变量,则应将它们作为列表。

如果您这样做:

def f():
    x = [1]
    def get():
        print 'get', x[0]
        x[0] -= 1
    def post():
        print 'post', x[0]
        x[0] += 1
    return (get, post)

get1, post1 = f()
get2, post2 = f()

get1和post1将引用与get2和post2不同的“x”列表。

答案 2 :(得分:2)

您可以使用exec来运行代码对象。例如,如果你有如上定义的f,那么

exec(f.func_code.co_consts[3])

会给出

get

作为输出。

答案 3 :(得分:1)

在执行函数f()之前,内部函数对象不存在。如果你想得到它们,你必须自己构建它们。这绝对是不重要的,因为它们可能是从函数范围捕获变量的闭包,无论如何都需要在对象中进行调整,这些对象应该被视为解释器的实现细节。

如果您想以较少的重复收集功能,我建议采用以下方法之一:

a)只需将函数放在类定义中并返回对该类的引用。通过名称访问的相关函数的集合闻起来像一个类。

b)创建一个dict子类,它有一个注册函数的方法并将其用作装饰器。

这个代码看起来像这样:

class FunctionCollector(dict):
    def register(self, func):
        self[func.__name__] = func

def f():
    funcs = FunctionCollector()
    @funcs.register
    def get():
        return 'get'
    @funcs.register
    def put():
        return 'put'
    return funcs

c)在locals()中查找并使用inspect.isfunction过滤掉该函数。 (通常不是一个好主意)