Анализ вложенных (локальных) функций данной функции в Python - PullRequest
5 голосов
/ 05 августа 2009

С учетом функции

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

но я не могу понять, как получить действительные объекты вызываемой функции. Это вообще возможно?

Спасибо за вашу помощь,

Will.

Ответы [ 4 ]

4 голосов
/ 06 августа 2009

Вы достаточно близки к этому - просто отсутствует 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 :].

Но какого чёрта? Разве не легче использовать класс? В любом случае, экземпляр выглядит как вызов функции.

2 голосов
/ 05 августа 2009

Вы можете использовать exec для запуска объектов кода. Например, если вы определили f как указано выше, то

exec(f.func_code.co_consts[3])

даст

get

как вывод.

2 голосов
/ 05 августа 2009

Вы можете возвращать функции, как и любой другой объект в Python:

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


get, post = f()

Надеюсь, это поможет!

Обратите внимание, что если вы хотите использовать переменные 'x' и 'y' в get () или post (), вы должны сделать их списком.

Если вы делаете что-то вроде этого:

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 будут ссылаться на список 'x', отличный от get2 и post2.

1 голос
/ 06 августа 2009

Объекты внутренней функции не существуют до выполнения функции 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

в) Поискайте в localals () и отфильтруйте функцию с помощью inspect.isfunction. (обычно не очень хорошая идея)

...