简体   繁体   中英

Call Nested Function in Python

I have a method that i have broken into smaller nested functions to break up the code base:

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

Is there a way to run one of the nested functions by itself. eg:

foo.do_this(x,y)

EDIT:

I am trying to setup caching on a web server i have built using 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)

This is my understanding may not be accurate:

Now the reason i have this is that the namespace used by the decorator to create the cache key is genereated from the function and the arguements. You can't therefore just put the decorator on getThis as the request variable is unique-ish and the cache is useless. So i created the inner function which has repeatable args (search_term).

However to invalidate the cache (ie refresh), the invalidation function requires scope to know of the 'getData' function so also needs to be nested. Therefore i need to call the nested function. You wonderful people have made it clear its not possible so is someone able to explain how i might do it with a different structure?

I assume do_this and do_that are actually dependent on some argument of foo , since otherwise you could just move them out of foo and call them directly.

I suggest reworking the whole thing as a class. Something like this:

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()

These previous answers, telling you that you can not do this, are of course wrong. This is python, you can do almost anything you want using some magic code magic.

We can take the first constant out of foo's function code, this will be the do_this function. We can then use this code to create a new function with it.

see https://docs.python.org/2/library/new.html for more info on new and https://docs.python.org/2/library/inspect.html for more info on how to get to internal code.

Warning: it's not because you CAN do this that you SHOULD do this , rethinking the way you have your functions structured is the way to go, but if you want a quick and dirty hack that will probably break in the future, here you go:

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

UPDATE: in python3 you can use the types module with 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'

There is, you have to make them as an attribute of the function object. But this will work only after the first call of 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)
>>>

No (apart from poking around in closure objects, which is complete overkill here). If you need that, use a class.

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

Or just put those functions in the outer scope, since you're passing everything as arguments anyway:

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

def do_this(x, y):
    ...

def do_that(x, y):
    ...

No, there is not. Since you may access variables in an outer scope from within a nested function:

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

there is no way to call do_this while providing a binding for x and y .

If you must call do_this from elsewhere, simply make it a top level function at the same level as foo .

You can try this way:

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)

This is how I did it.

CODE

def getMessage(a="", b="", c=""):
    def getErrorMessage(aa, bb):
        return "Error Message with/without params: {}{}".format(aa, bb)

    def getSuccessMessage(bb, cc):
        return "Success Message with/without params:  {}{}".format(bb, cc)

    def getWarningMessage(aa, cc):
        return "Warning Message with/without params:  {}{}".format(aa, cc)

    return {
        "getErrorMessage": getErrorMessage(a, b),
        "getSuccessMessage": getSuccessMessage(b, c),
        "getWarningMessage": getWarningMessage(a, c),
    }


a = "hello"
b = " World"
c = "!"
print(getMessage(a, b)["getErrorMessage"])
print(getMessage(b=b, c=c)["getSuccessMessage"])
print(getMessage(a=a, c=c)["getWarningMessage"])
print(getMessage(c=c)["getWarningMessage"])

OUTPUT

Error Message with/without params: hello World
Success Message with/without params:   World!
Warning Message with/without params:  hello!
Warning Message with/without params:  !

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM