TongZZZ
TongZZZ

Reputation: 766

Python: update value of an instance and use it in a class from imported module

I have been studying Python for three months and now I have a question that I could not solve by using google, but luckily I am able to simplify it here:

I have a var_class module:

#var_class.py

class A(object):
    def __init__(self, x):
        self.x = x+2

zz = A(10)

class B():
    b = 0    
    def __init__(self):
        pass
    def update(self):
        B.b = zz.x

and in main program I have:

#main.py

from var_class import *

b_class = B()
b_class.b        # I get 0 as expected
zz = A(100)
b_class.update()
b_class.b        # Instead of 102, I get 12 unexpectedly

You see my goal is to change "zz" frequently for every data input and then update a class variable 'b', and the reason I wrote zz = A(10) in var_class.py is that otherwise when I import it, module 'var_class' is missing 'zz' in 'class B', it would give error "global name zz is not defined".

However, as I write it like this now, looks like the value '10' is stuck to the class, and I am not able to change it in the main program. Don't know how to overcome this. Thanks in advance for any help.

Answer:

alKid wrote the whole answer first, have to thanks to alexvassel and Mr. C too, would like to know if there is way to thanks them, others helped me with the knowledge, also appreciate a lot.

Upvotes: 0

Views: 5362

Answers (6)

aIKid
aIKid

Reputation: 28292

Easy understanding: You can't do that, you're inside var_class module, so zz is A(10).

How about passing zz as a parameter? Like this!

class A(object):
    def __init__(self, x):
        self.x = x+2

zz = A(10)

class B():
    b = 0    
    def __init__(self):
        pass
    def update(self, zz):
        B.b = zz.x

Hope this helps!

Upvotes: 1

Corley Brigman
Corley Brigman

Reputation: 12401

when you import a variable from a module, you get a copy of the variable, not the original. you need to write to the original directly.

from a.b import c
from a.b.c import var

a.b.c.var = 1

var = 2

a.b.c.var
1
var
2

Edit: So, more correctly, in python, there are objects in memory, and then there are names for the objects. When you import a module, you create two separate names, but they both point to the same object - i.e. they have a reference to the same object. It's very similar to the below code, which doesn't require any imports at all:

>>> a = 4
>>> b = a
>>> b
4
>>> a
4
>>> b = 'something different'
>>> b
'something different'
>>> a
4

Why did changing b not also change a? The sequence is like this: First, we create an object (the 4) and point the name 'a' at it. Then, we create a name 'b', and we point it at the same object. So, now looking up those names returns the same object. Now, we then go back and point the name 'b' at a different object, a string. The object 'a' is pointing to still exists, and has not changed.

New users more often trip up on this the other way, with objects like lists:

>>> a = [1,2,3,4,5]
>>> b = a
>>> b
[1,2,3,4,5]
>>> a
[1,2,3,4,5]
>>> b.append(6)
>>> b
[1,2,3,4,5,6]
>>> a
[1,2,3,4,5,6]
>>> b = b[1:3]
>>> b
[2,3]
>>> a
[1,2,3,4,5,6]

What's going on here? Well, first we create a list object, and then point the name 'a' at it. Then we create the name 'b' and point it to the same object. So, 'a' and 'b' both point to the same list. Then, we use the reference b to get the object and modify it. Note that we haven't changed what 'b' points to in this case - we grabbed the reference, and then modified the object it points to directly. So, in this case, both 'a' and 'b' will see the change - they both point to the modified object. Then, we extract a slice, and assign it to 'b'. Now, this actually creates a new object, and points 'b' at it - 'b' is no longer pointing to the original object. So now 'a' and 'b' point to different objects, and now updates to one are no longer reflected in the other.

The import case is just a special case of this.

Upvotes: 0

Mr. C
Mr. C

Reputation: 568

python runtime finds variables by namespace. Namespace is something like scope. When B.b = zz.x executes, the runtime first searches the local namespace(the function namespace -- update), it sees no zz. Then, it goes to the module space(var_class), well we get the variable and stop searching.

The python namespace search order:
1. local namespace, the function scope
2. global namespace, the module scope
3. built-in namespace

Better not use global variables around.

your code may like this:

class B():
b = 0    
def __init__(self):
    pass
def update(self, zz):
    B.b = zz.x

Upvotes: 1

Gray
Gray

Reputation: 297

maybe you can do this

class B():
    b = 0    
    def __init__(self):
        pass
    def update(self,value):
        self.b =self.b+value

Upvotes: -1

OBu
OBu

Reputation: 5177

That is a matter of scope! you are using zz = A(100) in your main.py. But when you call b_class.update(), b_class has to get "some2 variable called "zz" - and the one which is available is the one you defined in your class.py - and this one still has the value A(10)!!!

To work around this, you have different options.

  • The dirty hack (but closest to your solution) would be to define a global variable and use ist (google "python globals" for more info on this approach).
  • I would suggest passing A (or A.x) to your "update" method b_class.update(A.x). This avoids globals and is more readable. Of course, you'll have to adjust B.update for the new parameter.

Upvotes: 0

alexvassel
alexvassel

Reputation: 10740

When you do B.b = zz.x (update method) you are inside the module var_class, so zz is A(10)

Upvotes: 1

Related Questions