-2

I have a class and am trying to create a function inside of a function in the class. My code is this:

class example:
    def __init__(self):
        self.points = 0
    def operations(self):
        def add(self):
            self.points += 1
        def subtract(self):
            self.points -= 1
    def display(self):
        print(self.points)

obj = example()
obj.display()
obj.operations.add()

I get the output 0 and then get the error:

obj.operations.add()
AttributeError: 'function' object has no attribute 'add'

I have tried many other ways to solve this but none have worked. Please answer if you know how to fix this error.

-Thanks

Nic
  • 1,549
  • 2
  • 13
  • 13
  • What exactly are you trying to do? You can define functions inside of functions but they will not be available through `function1.function2`. Especially they don't even exist as long as you don't execute the function (and if you don't "save" the functions afterwards they will cease to exist). – syntonym Jun 07 '16 at 10:13
  • 1
    Functions inside functions are *locals*, just like any other variable in a function. They only exist for the duration of a function call, and not outside that call. Did you want to namespace these functions for some reason? – Martijn Pieters Jun 07 '16 at 10:13
  • @MartijnPieters The reason why I have a function inside A function is that In my actual program, I have lots of programs and I'm a person who likes to keep things neat. – Nic Jun 07 '16 at 10:17
  • 1
    @Nic: This is not making it neater. Deviating from common practices makes your code harder to maintain, for example. Functions can't be used to create an additional namespace, at any rate. – Martijn Pieters Jun 07 '16 at 10:19
  • What else except `operations` are you going to implement on that object? – Jasper Jun 07 '16 at 10:20
  • @MartijnPieters So, is it better of I just have all my functions all straight in the class and not try to have functions inside functions? – Nic Jun 07 '16 at 10:21
  • @Jasper I have moving functions in my class (def move_left ect.) and some other things. I was hoping I could have obj.movement.move_left. – Nic Jun 07 '16 at 10:24
  • @Nic instead of a function you could place an inner class. But I don't think that it would make it any cleaner but quite the opposite. – syntonym Jun 07 '16 at 10:28
  • @syntonym I could use an inner class although I would need to be able to pass self through the class. If you know how to create an inner class and pass self through, then please provide an answer. – Nic Jun 07 '16 at 10:30
  • @Nic: prefix your operation functions if you have to; `instance.operations_add` and `instance.operations_subtract`. You can have a simple object that you create as an attribute that knows how to [bind methods to the original instance](https://docs.python.org/2/howto/descriptor.html) but that's a lot of extra work and will only serve to obfuscate your code. – Martijn Pieters Jun 07 '16 at 10:55
  • Do you see the redundancy in `obj.operations.add()` and `obj.movement.move_left()`? There is no need to state that `add` is an operation or `move_left` a movement. – Jasper Jun 07 '16 at 14:29

1 Answers1

-2

you can try returning functions from the function then use them something like this -

class example:
    def __init__(self):
        self.points = 0
    def operations(self):
        def add():
            print "add is called"
            self.points += 1
        def subtract():
            self.points -= 1
        return [add, subtract]
    def display(self):
        print(self.points)

obj = example()
obj.display()
obj.operations()[0]()
obj.display()

If you specifically want to do it with obj.operations.add() you can try aggregation in this way (it involves the usage of class variable, if that's alright with you)

class example:
    points = 0
    def __init__(self):
        example.points = 0
        self.operations = Operations(self)

    def display(self):
        print(self.points)

class Operations(example):
    def __init__(self, ex):
        self.points = ex.points

    def add(self):
        print "add is called"
        example.points += 1
    def subtract(self):
        example.points -= 1

obj = example()
obj.display()
obj.operations.add()
obj.display()
obj.operations.subtract()
obj.display()

hope it may help !

sumit
  • 3,210
  • 1
  • 19
  • 37
  • I would still like to go "obj.operations.add()". But still, your way works and I'll use that way if I cant find any other way. Thanks! – Nic Jun 07 '16 at 10:15
  • if you return a named tuple you could get obj.operations().add. And if operations is a property, which returns a named tuple you would have obj.operations.add. But... don't do that. – syntonym Jun 07 '16 at 10:29
  • The class example worked! Thanks! – Nic Jun 07 '16 at 10:34
  • The class example uses *class attributes*. Yes, it happens to work, but as soon as you use more than one instance you'll see shared data. Store the `example` instance in the `Operations` instance and reference `self.example.points` instead. – Martijn Pieters Jun 07 '16 at 10:57
  • @MartijnPieters Could you provide an example? – Nic Jun 08 '16 at 05:36
  • @Nic try creating another `example()` object; `obj1` and `obj2` then play with one and call `display` on the other. – Martijn Pieters Jun 08 '16 at 08:52