Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python scope inside a nested function inside a class?

Tags:

python

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.

like image 536
Eiyrioü von Kauyf Avatar asked Jan 16 '13 21:01

Eiyrioü von Kauyf


People also ask

Can scopes be nested in Python?

A function defined inside another function is called a nested function. Nested functions can access variables of the enclosing scope. In Python, these non-local variables are read-only by default and we must declare them explicitly as non-local (using nonlocal keyword) in order to modify them.

What is the scope of a nested function?

The scope of a nested function is inside the enclosing function, i.e. inside one of the constituent blocks of that function, which means that it is invisible outside that block and also outside the enclosing function. A nested function can access other local functions, variables, constants, types, classes, etc.

Are nested functions Pythonic?

Inner functions, also known as nested functions, are functions that you define inside other functions. In Python, this kind of function has direct access to variables and names defined in the enclosing function.

Can I define a function inside a function Python?

A function which is defined inside another function is known as inner function or nested functio n. Nested functions are able to access variables of the enclosing scope. Inner functions are used so that they can be protected from everything happening outside the function.


3 Answers

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
like image 185
jimbo Avatar answered Oct 20 '22 02:10

jimbo


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.
like image 5
mgilson Avatar answered Oct 20 '22 00:10

mgilson


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.

like image 1
Anton Kovalenko Avatar answered Oct 20 '22 00:10

Anton Kovalenko