24

How can I set a class variable from inside a function inside another function?

var.py

class A:
    def __init__(self):
        self.a = 1
        self.b = 2
        self.c = 3
    def seta(self):
        def afunction():
            self.a = 4
        afunction()
    def geta(self):
        return self.a

run.py

cA = A()
print cA.a
cA.seta()
print cA.a
print cA.geta()

python run.py

1
1
1

why does a not equal 4 and how can I make it equal 4?

Edit:

Thanks everyone - sorry, I just saw now. I accidentally was off by a _ in one of my names.... so my scope is actually all ok.

2
  • 6
    You didn't even called afunction() in your code. Commented Jan 16, 2013 at 21:37
  • 37
    You shouldn't change your code to the answer. It is unhelpful, if we have to look through revisions to see what question was answered. Commented Dec 2, 2015 at 15:36

5 Answers 5

27

The problem is that there are multiple self variables. The argument passed into your inner function overwrites the scope of the outer.

You can overcome this by removing the self parameter from the inner function, and making sure you call that function in some way.

class A:
    def __init__(self):
        self.a = 1
        self.b = 2
        self.c = 3
    def seta(self):
        def afunction():  # no self here
            self.a = 4
        afunction()       # have to call the function
    def geta(self):
        return self.a
Sign up to request clarification or add additional context in comments.

Comments

5

As others have mentioned, afunction is never called. You could do something like this:

class A:
    def __init__(self):
        self.a = 1

    def seta(self):
        def afunction(self):
            self.a = 4
        afunction(self)

    def geta(self):
        return self.a

a = A()
print a.a
a.seta()
print a.a

Here we actually call afunction and explicitly pass it self, but this is a rather silly way to set the attribute a -- especially when we can do it explicitly without the need for getters or setters: a.a = 4

Or you could return the function:

def seta(self):
    def afunction(): #Don't need to pass `self`.  It gets picked up from the closure
        self.a = 4
    return afunction

and then in the code:

a = A()
a.seta()()  #the first call returns the `afunction`, the second actually calls it.

Comments

1

Inside seta, you define a function

    def afunction(self):
        self.a = 4

...that would set self.a to 4 if it would ever be called. But it's not called anywhere, so a is unchanged.

Comments

-1

As several others have said, you need to actually call functiona at some point. Comments won't let me type this intelligably so here's an answer:

def seta(self):
    def functiona(self):  #defined
        self.a = 4
    functiona()           #called

2 Comments

This should not work. At least in Python 3, you will get an error missing 1 required positional argument: 'self'. You will need to call functiona(self) but still this solution is redundant of defining nested function.
You didn't notice that this was defining something in the scope of a class in the original question.
-1

How can you make it equate to 4:

class A:
    def __init__(self):
        self.a = 1
        self.b = 2
        self.c = 3
    def seta(self):
        ##def afunction(self): (remove this)
        self.a = 4 
    def geta(self):
        return self.a

Tricky part: Why does is not equate to 4...

Currently a is set to 4 only via "afunction". Since afunction is never called it never executes.. The seta has "afunction" nested inside but not called... similar to member variables within a classs.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.