How to pass variable value through classes in different files? - python

I have this problem.
I need to pass an "a" variable processed in an execute () method in a class A
To an execute () method located in a class B in a different file.
below my code:
fileA.py
a = 0
class A:
def execute(self):
global a
a = 10
fileB.py
from fileA import A
class B:
def execute(self):
b = a
print (b)
main.py
from fileA import A
from fileB import B
if __name__== "__main__":
first = A()
first.execute()
second = B()
second.execute()
If i try this i get an error:
AttributeError: type object 'A' has no attribute 'a'
How can I make that the value of the variable "a" (elaborated in method of class A) is also seen inside a method of class B ?
Thanks in advance

You'd better do something like this:
fileA.py
class A():
def __init__(self, a=0):
self.a = a
def execute(self):
self.a = 10
fileB.py
class B():
def __init__(self, class_a, b=0):
self.class_a = class_a
self.b = b
def execute(self):
self.b = self.class_a.a
print(self.b)
main.py
from fileA import A
from fileB import B
if __name__== "__main__":
first = A()
first.execute()
second = B(first)
second.execute()
you can skip the init part for self.a and self.b but it's much better to keep it

Use composition.
In module_a:
class A:
a = 0
def set_a(self):
self.a = 10
In module_b:
from module_a import A
class B:
a = A()
def execute(self):
print(a.a)
if __name__ == "__main__":
b = B()
b.a.set_a()
b.execute()

I think that there is a misunderstanding about global and import.
import is reponsible for 2 different things:
the module is loaded into the sys.modules list and executed
the identifiers are made available in current scope
global only says that the referenced variables should be searched only in module scope and skip any local scope.
Now what happens.
fileA declares a class (A) and a variable (a). And class A only contains an execute method and no other attribute. A.execute just happens to set the value of the module level a variable.
fileB imports the class A from fileA, but not the module level variable a. But it uses a variable a in the B.execute method, while it has never been declared neither in module scope nor in local one, hence the error.
How to fix:
At the simplest level, you could import into fileB module the variable a (that you use) instead of the class A that you do not:
fileB.py
from fileA import a
class B:
def execute(self):
b = a
print (b)

Related

How does one use pytest monkeypatch to patch a class

I would like to use [pytest monkeypatch][1] to mock a class which is imported
into a separate module. Is this actually possible, and if so how does one do it? It seems like I have not seen an example for this exact situation. Suppose you have app with and imported class A in something.py
from something import A #Class is imported
class B :
def __init__(self) :
self.instance = A() #class instance is created
def f(self, value) :
return self.instance.g(value)
inside my test.py I want to mock A inside B
from something import B
#this is where I would mock A such that
def mock_A :
def g(self, value) :
return 2*value
#Then I would call B
c = B()
print(c.g(2)) #would be 4
I see how monkeypatch can be used to patch instances of classes, but how is it done for classes that have not yet been instantiated? Is it possible? Thanks!
[1]: https://docs.pytest.org/en/latest/monkeypatch.html
tested this, works for me:
def test_thing(monkeypatch):
def patched_g(self, value):
return value * 2
monkeypatch.setattr(A, 'g', patched_g)
b = B()
assert b.f(2) == 4

Python namespace and global variable between files

I have 2 differents files. The first one, defines a lot of class:
# File 1:
class Class1:
class Class2:
#...
Those classes uses some variables that are define as global.
# File 1:
class Class1:
def __init__(self, var1):
global glob_variable_1
# Other stuff
class Class2:
#...
In the file 2, I import all the class from the first file and then use them. In this main part of this file, I define the global variables.
# File 2
from File1 import Class1, Class2
if __name__ == '__main__':
global glob_variable_1
glob_variable_1 = 10
# Other stuff
Class1(var1)
I get the error NameError: name 'glob_variable_1' is not defined.. I suppose
it's a problem of namespace and scope, but I don't really understand how it works. Can someone give me a hand? Thanks.
You have two glob_variable_1 names, one in each namespace and you must decide which one to use:
# File 1:
# defined here, outside the class
glob_variable_1 = None
class Class1:
def __init__(self, var1):
global glob_variable_1
glob_variable_1 = 42
# Other stuff
class Class2:
pass
with:
# File 2
from File1 import Class1, Class2
import File1
if __name__ == '__main__':
global glob_variable_1
# Other stuff
var1 = 1234
obj = Class1(var1)
glob_variable_1 = 666
print(glob_variable_1)
print(File1.glob_variable_1)
Gives:
666
42
Far better than using a global variable across modules is to use a function to set/get in a class or a file.

Python inheritance: modify a parent class of an object

I need/want to modify a parent class and have problems with proper import. The child object still uses the "old" version of the class.
File A (some lib which I do not want to modify directly):
class A(object):
def __init__(self):
self.contentA = "42"
print("A.__init__() ausgeführt")
def m(self):
print("A.m() aufgerufen")
class B(A):
def __init__(self):
#A.__init__(self)
super().__init__()
self.contentB = "43"
print("B.__init__() ausgeführt")
def m(self):
#A.m(self)
super().m()
print("B.m() aufgerufen")
File B:
import somelib as demo
class A(demo.A):
def __init__(self):
super().__init__()
def f(self):
'''
new function for A!
'''
print("A.f():", self.contentA)
if __name__ == "__main__":
b = demo.B()
b.m()
print("b.contentB: " + str(b.contentB))
print("b.contentA: " + str(b.contentA))
b.f() # not found!
The newly added function f() is not found. How do I have to do this correctly?
Just because your class is also called A this doesn't mean that it will overwrite a previously defined class A in another module. Even if it would, the class B would not depend on it automatically.
Your problem is likely better solved by writing your inherited class B in this module, but if you really want to modify the parent class you can:
import somelib as demo
def f(self):
'''
new function for A!
'''
print("A.f():", self.contentA)
demo.A.f = f # assign f to the f attribute of A
if __name__ == "__main__":
b = demo.B()
b.m()
print("b.contentB: " + str(b.contentB))
print("b.contentA: " + str(b.contentA))
b.f() # found!
Your best bet is probably monkey patching, e.g.:
import somelib as demo
def f(self):
'''
new function for A!
'''
print("A.f():", self.contentA)
demo.A.f = f
if __name__ == "__main__":
b = demo.B()
b.m()
print("b.contentB: " + str(b.contentB))
print("b.contentA: " + str(b.contentA))
b.f() # should now be found!

Make Python module classes able to be called from a separate class

I currently have a module, my_module, which contains classes.py:
from . import config
class Class1:
#staticmethod
def method_one(x)
return x + config.constant
#staticmethod
def method_two(y)
return x - config.constant
My problem is that I want to be able to have multiple instances of the module with different values for config.constant. Ideally, I'd have a new class called MyClass where the constant would be an instance variable, so that this would work:
instance1 = MyClass(5)
instance1.Class1.method_one(5) # 10
instance2 = MyClass(0)
instance2.Class1.method_one(5) # 5
Is there a way to do this without modifying the classes which are in my_module?
Make it a staticmethod.
class MyClass(object):
#staticmethod
def my_method(num):
return num + num
Then you can use it from another file by doing(assuming the file is my_module.py:
import my_module
my_module.MyClass.my_method(2)
>>>4
my_module.py
def __init__(self, constant):
self.constant = constant
def my_method(self, num):
return self.constant + num
some_other_file.py
import my_module
MyClass = type('MyClass', (), my_module.__dict__)
my_instance = MyClass(3)
my_instance.my_method(4)
>>> 7

How do I access inherited variables from another module when they are changed in parent?

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?
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()
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.
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.)
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

Categories

Resources