Вызовите вложенную функцию в Python

У меня есть метод, который я разбил на более мелкие вложенные функции, чтобы разбить базу кода:

def foo(x,y):
    def do_this(x,y):
        pass
    def do_that(x,y):
        pass
    do_this(x,y)
    do_that(x,y)
    return

Есть ли способ запустить одну из вложенных функций самостоятельно. например:

foo.do_this(x,y)

EDIT:

Я пытаюсь настроить кеширование на веб-сервере, который я создал с помощью pyramid_breaker

def getThis(request):
    def invalidate_data(getData,'long_term',search_term):
         region_invalidate(getData,'long_term',search_term)
    @cached_region('long_term')
    def getData(search_term):
         return response
    search_term = request.matchdict['searchterm']
    return getData(search_term)

Это мое понимание может быть неточным:

Теперь причина в том, что пространство имен, используемое декоратором для создания ключа кеша, генерируется из функции и аргументов. Поэтому вы не можете просто поставить декоратор на getThis, поскольку переменная запроса уникальна, а кеш бесполезен. Поэтому я создал внутреннюю функцию, которая имеет повторяющиеся аргументы (search_term).

Однако для недействительности кеша (то есть обновления) функция недействительности требует, чтобы область знаний о функции getData была также вложенной. Поэтому мне нужно вызвать вложенную функцию. Вы замечательные люди дали понять, что это невозможно, так кто-то может объяснить, как я могу сделать это с другой структурой?

Ответ 1

Я предполагаю, что do_this и do_that на самом деле зависят от некоторого аргумента foo, так как иначе вы могли бы просто вывести их из foo и вызвать их напрямую.

Я предлагаю переделать все это как класс. Что-то вроде этого:

class Foo(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def do_this(self):
        pass

    def do_that(self):
        pass

    def __call__(self):
        self.do_this()
        self.do_that()

foo = Foo(x, y)
foo()
foo.do_this()

Ответ 2

Эти предыдущие ответы, говорящие вам, что вы не можете сделать это, конечно же, неверны. Это python, вы можете делать практически все, что захотите, используя магию магического кода.

Мы можем извлечь первую константу из кода функции foo, это будет функция do_this. Затем мы можем использовать этот код для создания новой функции.

см. https://docs.python.org/2/library/new.html для получения дополнительной информации о новых и https://docs.python.org/2/library/inspect.html для получения дополнительной информации о том, как добраться до внутреннего код.

Предупреждение: не потому, что вы МОЖЕТЕ сделать это, вы ДОЛЖНЫ сделать это, переосмыслить способ структурирования ваших функций - это путь, но если вы хотите быстрый и грязный хак, который, вероятно, сломается в будущем, вот вам:

import new
myfoo = new.function(foo.func_code.co_consts[1],{}) 
myfoo(x,y) # hooray we have a new function that does what I want

ОБНОВЛЕНИЕ: в python3 вы можете использовать модуль types с foo.__code__:

import types
myfoo = types.FunctionType(foo.__code__.co_consts[1], {})
myfoo()  # behaves like it is do_this()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: do_this() missing 2 required positional arguments: 'x' and 'y'

Ответ 3

Нет, нет. Поскольку вы можете обращаться к переменным во внешней области изнутри вложенной функции:

def foo(x,y):
    def do_this(z):
        print(x,y,z)
    # ...

нет способа вызвать do_this, предоставляя привязку для x и y.

Если вы должны вызвать do_this из другого места, просто сделайте его функцией верхнего уровня на том же уровне, что и foo.

Ответ 4

Есть, вы должны сделать их как атрибут объекта функции. Но это будет работать только после первого вызова foo.

def foo(x,y):
    def do_this(x,y):
        pass
    def do_that(x,y):
        pass
    do_this(x,y)
    do_that(x,y)
    foo.do_this = do_this
    foo.do_that = do_that
    return

>>> foo.do_this(1, 2)
AttributeError: 'function' object has no attribute 'do_this'
>>> foo(1, 2)
>>> foo.do_this(1, 2)
>>>

Ответ 5

Нет (кроме того, что тыкаешь в закрытых объектах, что здесь полный избыток). Если вам это нужно, используйте класс.

class foo(object):
    def do_this(self, x, y):
       ...
    def do_that(self, x, y):
       ...
    def do_other_stuff(self, x, y):
       # or __call__, possibly

Или просто поместите эти функции во внешнюю область, так как вы все равно передаете все как аргументы:

def foo(x, y):
    do_this(x, y)
    do_that(x, y)

def do_this(x, y):
    ...

def do_that(x, y):
    ...

Ответ 6

Вы можете попробовать так:

def a(x, y):
    name = 'Michael'
    a.name = name

    a.z = z = x * y
    #a.z = z

def b():
    def give_me_price(f,g):
        price = f * g
        return price

    def two(j,k):
        surname = 'Jordan' # without return surname give None

    # two = two('arg1', 'arg2')
    # b.blabla = two

    one = give_me_price(5, 10)
    b.halabala = one

    print(a.name) # ;)

x = 20
y = 30

a(x,y) # IMPORTANT! first you must run function
print(a.z)
print(a.name * 5)

print('-'*12)
b() # IMPORTANT! first you must run function
print('price is: ' + str(b.give_me_price(5, 25)))
# print(b.blabla)

Ответ 7

Все говорят вам, что это невозможно, хотя на самом деле это очень возможно, проблема в том, что обычно такие вещи не очень хорошо документированы. Я принял это как вызов, и мне удалось создать простую утилиту, которая раскрывает все внутренние функции функции. Прямо сейчас это ограничено, потому что оно работает только для внутренних функций без параметров, но может быть расширено для поддержки параметров.

def a():
    def b():
        print('i have executed b()')
    def c():
        print('i have executed c()')

def expose(src):
    name_outer = src.__code__.co_name
    code = src.__code__
    for const in code.co_consts:

        if const != None and type(const).__name__ == 'code':
            name_inner = const.co_name
            #exec(const)
            exec('{}._{} = {}'.format(name_outer, name_inner, 'const'))
            exec('{}.{} = lambda: exec({})'.format(name_outer, name_inner, name_outer + '._' + name_inner))


expose(a)
a.b()
a.c()

По сути, каждая функция Python имеет поле __code__, которое хорошо содержит код, в простейшей форме вы можете выполнить этот __code__ следующим образом exec (.__ code__), если ваша функция a, но вы не сможете предоставить аргументы. Эти объекты кода также содержат информацию о константах, в этих константах вы также найдете внутренние функции. Сейчас дело только в исправлении обезьян. Если вы хотите выполнять функции с аргументами, все становится немного сложнее, я недостаточно исследовал, но одно наивное решение - получить текст исходного кода объекта кода, используя библиотеку inspect, и поработать над этим с помощью eval.

Редактировать: ой и кстати не делайте этого, делайте это только если вам абсолютно необходимо.

Ответ 8

import types
myfoo = types.FunctionType(foo.__code__.co_consts[1], {})
myfoo()  # behaves like it is do_this()

Это работает довольно хорошо, но если do_this использует переменные, которые не передаются непосредственно ему, это завершается ошибкой: "TypeError: arg 5 (closure) должно быть кортежем".

У кого-нибудь есть предложение, как мы можем предоставить недостающие аргументы?