17

Python noob here. How do I get hold of the 'inner' function within the 'fib' function?

from time import sleep

class Fibonacci(object):

    def __init__(self, a, b, limit=50):
        self.a = a
        self.b = b
        self.limit = limit

    def fib(self):

        while self.a < self.limit:
            c = self.a + self.b
            sleep(1)
            print self.a,
            self.b = self.a
            self.a = c

        def inner(self):
            print 'Damn it! Just print already!'


j = Fibonacci(0,1,2)
j.fib()

## This doesn't work. Gives an "AttibuteError: 'function' object has no attribute 'inner'"
j.fib.inner()
7
  • You could call inner() from within the definition of fib(), but not from outside of it. What are you trying to do? Commented Aug 14, 2011 at 0:43
  • 1
    My Python is rusty, but I'm pretty sure you can't access inner from outside of fib, without changing how inner is defined. Commented Aug 14, 2011 at 0:44
  • I figured since i can access fib inside Fibonacci(yeah, i know it's a class and not a function) with a dot operator, I should be able to access a function inside another function like that. Oh well Commented Aug 14, 2011 at 0:53
  • @seykom Nope. No more than it is possible to access inner after inner = "fubar". Commented Aug 14, 2011 at 0:56
  • 1
    seykom, You need to accept answers to more of your questions. Click the check mark next to the answer that helped you the most. You should do this for your old questions as well as for new ones. Commented Aug 14, 2011 at 1:29

5 Answers 5

21

You cannot, not unless fib returns inner somehow. inner is essentially a local variable inside the scope of fib and you can't access a function's locals from outside of it. (That wouldn't even make sense, since the locals don't exist except when the function is running. Think about it -- would it make sense to access fib's c variable from outside of the function?)

Sign up to request clarification or add additional context in comments.

Comments

11

Do not use the following.

[...]
>>> j = Fibonacci(0,1,2) 
>>> j.fib()
0 1 1
>>> # dark magic begins!
>>> import new
>>> new.function(j.fib.im_func.func_code.co_consts[2],{})(None)
Damn it! Just print already!

You can tell simply by looking at it that it's not really Python, and for that matter it isn't really calling the "inner" function itself, it's simply creating a new function like it. I also didn't bother setting the globals 'correctly', because this is a terrible thing to do in the first place..

[I should mention that the point of the above is to note that the idea that you can't access internals from outside isn't strictly true, though it's almost never a good idea. Exceptions include interpreter-level code inspections, etc.]

Unclean! Unclean!

5 Comments

Of course, in the general case you'll need to use the disassembler and/or a considerable amount of brainpower and/or trial and error to figure out the right index into co_consts...
You should use types.FunctionType :)
Thanks! While a terrible thing to do when you control the code yourself, it can be helpful for debugging someone else's function.
Do not use the following ... unless you write inspection of code.
In fact very insecure (as said by the author himself), but he won points for his boldness and mastery. You never know when you're going to need something especially when you're dealing with legacy and third-party code. 😉
6
from time import sleep

class Fibonacci(object):

    def __init__(self, a, b, limit=50):
        self.a = a
        self.b = b
        self.limit = limit

    def fib(self):

        while self.a < self.limit:
            c = self.a + self.b
            sleep(1)
            print self.a,
            self.b = self.a
            self.a = c

        def inner(self):
            print 'Damn it! Just print already!'
        Fibonacci.fib.inner = inner

    fib.inner = None

This code snippet will allow you to use inner.

Comments

6

The below seems to achieve what you want

from types import CodeType, FunctionType

def find_nested_func(parent, child_name):
    """ Return the function named <child_name> that is defined inside
        a <parent> function
        Returns None if nonexistent
    """
    consts = parent.func_code.co_consts
    for item in consts:
        if isinstance(item, CodeType) and item.co_name==child_name:
            return FunctionType(item, globals())

1 Comment

Please update the code for python 3.x support
2

As stated by some of the other readers, it's a problem of scope. FWIW, this works by returning the inner function:

from time import sleep

class Fibonacci(object):

    def __init__(self, a, b, limit=50):
        self.a = a
        self.b = b
        self.limit = limit

    def fib(self):

        while self.a < self.limit:
            c = self.a + self.b
            sleep(1)
            print self.a,
            self.b = self.a
            self.a = c

        def inner():
            print 'Damn it! Just print already!'

        return inner


j = Fibonacci(0,1,2)
j.fib()()

For reference, here's a good intro to python's scoping:

Short Description of the Scoping Rules?

4 Comments

Thanks. Why is there no need for self in inner
Because inner isn't a method of a class instance.
Because inner is not being called on the object (j) anymore, inner is being returned as a stand alone function. In other words, inner is not a method of the Fibonacci class it's just a stand alone function.
Thanks for the help and the above link

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.