1

I am trying to figure out how to put a define function inside a define function inside of a class. Python code of what I want to do:

class Guy():
    def move(self):
        def left(self):
            //compute
        def right(self):
            //compute
        def up(self):
            //compute
        def down(self):
            //compute

And then be able to call Guy.move.right() later on in the program. The interpreter gives me an error saying 'Function has no attribute right' or something like that. Is there any way to do this without having to bring my functions out of the move function and calling them Guy.right, Guy.left, etc.?

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
Elias Benevedes
  • 363
  • 1
  • 8
  • 26
  • 1
    Check out this stackoverflow post: http://stackoverflow.com/questions/1589058/nested-function-in-python – aw4lly Dec 05 '12 at 05:13

5 Answers5

2

Functions don't normally have fields and other functions that they expose to the outside scope. That's usually the job of objects. But you can do it with something like...

class Guy():
    class Move():
        def __init__(self):
            self.whatevs = "whatevs"
        def left(self):
            print("left")
            pass
            #compute
        def right(self):
            print("right")
            pass
            #compute
        def up(self):
            print("up")
            pass
            #compute
        def down(self):
            print("down")
            pass
            #compute

    def __init__(self):
        self.move = self.Move()

guy = Guy()
guy.move.left()

I am quite sure this isn't good design though. Is there a reason why you want to do guy.move.left()? Some idea of elegance, because it isn't in other ways, like in terms of being simple.

Ehtesh Choudhury
  • 7,452
  • 5
  • 42
  • 48
1

this is a bad way to code...

there is no way to call left function under Guy class since it is in the scope of move function, and unlike class, adding a function inside another function does not make it its attribute.

Until the inside function is a attribute of the outside function there is no way to call it using the name of the enclosing function

In case

def move():
    def left():

i.e. If there is only one function inside a function it is feasible to return left() from move function.

However in this case there are multiple functions inside move function scope.

You should look for something like a nested class and make move as a class rather than a function

avasal
  • 14,350
  • 4
  • 31
  • 47
  • Is there any way to make a function an attribute of the function enclosing it? – Elias Benevedes Dec 05 '12 at 05:33
  • @EliasBenevedes: i would advice you to move to a nested class approach but if you still want to go ahead with this approach, you can have a look at http://stackoverflow.com/questions/4273998/dynamically-calling-nested-functions-based-on-arguments – avasal Dec 05 '12 at 05:38
1

I would avoid nesting methods and functions.

Your move method will recompile those directional methods every time it is called and those directional methods can only be called from within move.

Perhaps you want a generic move method that takes a direction argument along with self?

def move(self, direction):
    if direction == "left":
        pass //do something
    //etc
Randall Hunt
  • 12,132
  • 6
  • 32
  • 42
0
class Guy():
    def move(self,dir):
       def left():
          print "left!"
       {'left':left}[dir]()

Guy().move("left")

would work although I dont see much use case for it ...

Joran Beasley
  • 110,522
  • 12
  • 160
  • 179
0

There is a way to accomplish something similar to the requirements of original code: Guy.move() will call move() function, and Guy.move.right(Guy()) will call move.right function. The only difference is that I had to pass self object to move.right explicitly.

I do not encourage anybody to take this route, more like 'what python can do' thing.

def to_attr(f):
    import inspect
    import new
    for c in f.func_code.co_consts:
        if inspect.iscode(c):
            g = new.function(c, globals())
            setattr(f, g.func_name, g)    

    return f

class Guy(object):
    @to_attr
    def move(self):
        def left(self):
            pass
        def right(self):
            print "Right"
        def up(self):
            pass
        def down(self):
            pass
        print "Move"

Guy.move.right(Guy())
Guy().move()

inspect code is borrowed from Introspecting a given function's nested (local) functions in Python

Community
  • 1
  • 1
Yevgen Yampolskiy
  • 7,022
  • 3
  • 26
  • 23