4

I have a file a.py

avariable = None

class a():

  def method(self):
    global avariable
    avariable = 100
    print "variable is", avariable

and a file b.py

from a import *

class b(a,):

  def mymethod(self):
    a().method()
    print "avariable is " , avariable

if __name__ == '__main__':
  b().mymethod()

File b imports everything from a and also inherits from a. a's method is called and the avariable is change to 100 but when I print avariable in b the value is None. How to I use in class b the variable avariable that a class changed?

Output:

>python b.py 
variable is 100
avariable is  None

Clarification

It's crucial for me to use

from a import *

because I have already code in class b that calls methods of class a using the syntax

self.method()

and that cannot change.

i.e.

from a import *
class b(a):

  def mymethod(self):
    self.method()
    print "avariable is " , avariable

if __name__ == '__main__':
  b().mymethod()

So is there a way to access the variable avariable in a without prefixing in any way the avariable?

Adam
  • 15,537
  • 2
  • 42
  • 63
user847988
  • 984
  • 1
  • 16
  • 30
  • 1
    Why that `class b(a,):`? Any specific reason for the comma? – Alfe Oct 14 '13 at 10:57
  • 1
    Concerning your clarification: ``self.method()`` will work regardless of how you import ``a``. – fjarri Oct 14 '13 at 11:41
  • @Bogdan,thanks i didn't know that. But still can I use avariable without prefixing it? – user847988 Oct 14 '13 at 12:29
  • Not if it is something immutable. You can wrap your value in some class and modify it through a method instead of an assignment, if you really want this behavior. But, again, it is a really bad practice (and using ``from x import *`` is usually discouraged as well). – fjarri Oct 14 '13 at 12:35

4 Answers4

4

a.py

avariable = None

class a():

    def method(self):
        global avariable
        avariable = 100
        print "variable is", avariable

b.py

import a


class b(a.a):
    def mymethod(self):
        a.a().method()
        print "avariable is ", a.avariable


if __name__ == '__main__':
    print a.avariable
    b().mymethod()
    b().mymethod()

Output:

None
variable is 100
avariable is  100
variable is 100
avariable is  100

You get None all the time because once you import avariable you keep it in your own file, but what a.py is changing, is the avariable variable in its own file (or more appropriately, its own global namespace), and thus, you can see no change.

But in the example above, you can see the changes. This is because, we are importing the a module itself, and thus accessing all its objects (everything in Python is an object). And thus, when we call a.avariable we are actually calling the avriable variable in a's global namespace.

EDIT

The code below will still produce the same output.

import a


class b(a.a):
    def mymethod(self):
        self.method()
        print "avariable is ", a.avariable


if __name__ == '__main__':
    print a.avariable
    b().mymethod()
    b().mymethod()
Games Brainiac
  • 80,178
  • 33
  • 141
  • 199
1

First, inheritance has nothing to do with it, and only complicates your example. You could have demonstrated your point with only a single function in a.py.

Anyway, when you write from a import *, Python goes over all public variables in a, and updates the dictionary of the module b as (very simplified):

import a
for name in a.__dict__:
    locals()[name] = a.__dict__[name]

So the contents of avariable just gets copied, and when you print it in b.py, you are printing a different variable (you can check it by printing the ids too).

To do what you want your b.py has to look like

import a

class b(a.a,):

  def mymethod(self):
    a.a().method()
    print "avariable is " , a.avariable

if __name__ == '__main__':
  b().mymethod()

so that you are actually accessing the same avariable.

But having said that, it is an absolutely terrible practice. Non-constant global variables in modules can lead to all sorts of weird and hard to detect bugs.

fjarri
  • 9,546
  • 39
  • 49
1

Global variables in a module are global to that module only, not in the imported module.

So, when you call a().method() in b.py, global avariable actually modifies the a's avariable not b.

i.e You can't access a's global namespace by using global in b.py.


Example:

a.py

x = 'a'
def func():
    global x
    print x

b.py:

from a import *
x = 'b'           #override `x` imported from `a`
func()            #call to func() prints 'a' not 'b'
print x           #prints 'b'

The call to func() actually access a's x not the current x so it prints 'a' and print x in b.py prints 'b' as expected.

Output:

a
b

Read: Python - Visibility of global variables from imported modules


Instead of using global variables you can use class attributes:

a.py

class a(object):
    variable = None
    def method(self):
        a.avariable = 100 #modification to `a`'s attribute will be seen in `b()`
        print "variable is", a.avariable

b.py

from a import *

class b(a):
    def mymethod(self):
        a().method()
        print "avariable is " , self.avariable

if __name__ == '__main__':
    b().mymethod()

output:

variable is 100
avariable is  100
Community
  • 1
  • 1
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
1

By importing a module defining a variable directly (as is avariable in module a in your example), you will get a second variable in your importing module. The two variables are not the same (a.avariable is not b.avariable).

You can access the other module's variable by using more qualified naming schemes (as displayed in the answer of @Games Brainiac).

The keyword global declares a variable as module-global. Python has no concept of truly global variables which are the same for each module. (Correct me if I'm wrong here but I never found such a thing yet.)

Alfe
  • 56,346
  • 20
  • 107
  • 159