Scope of Python Class Variable? - python

Are class variables essentially global variables?
Consider this example, in bar.py:
class Bar(object):
b = {}
then in foo.py:
def foo1():
import bar
bar.Bar.b["key"] = "foo1"
def foo2():
import bar
print bar.Bar.b.get("key", "foo2")
foo1()
foo2()
The "key" value is persistently "foo1."
For my purposes this seems like a global variable. But why isn't the class variable being reset or deleted between the calls to foo1 and foo2?

It's a class attribute. In your case, the dict is bound to the class Bar. Everytime you import bar, you get the same class bar.Bar (after all, it is in the bar's global namespace), and consequentially, you get the same dict bar.Bar.b.
If you want each Bar instance to have a different dict, you need to make an instance:
class Bar(object):
def __init__(self):
self.b = {}
And then:
def foo1():
import bar
bar.Bar().b["key"] = "foo1"
def foo2():
import bar
print bar.Bar().b.get("key", "foo2")
foo1()
foo2()
As far as why the module bar isn't being garbage collected, when you import something, python stores a reference to that module (see sys.modules). The next time you import that module, python picks out the proper item from sys.modules and gives you a reference to it. There are a few reasons for this.
Efficiency -- Why re-evaluate code you've already evaluated?
Sane behavior
Imagine a module with a special value:
# mod.py
CONSTANT = object()
now you want to use that in foo.py and bar.py.
# bar.py
import mod
def bar():
return mod.CONSTANT
# foo.py
import mod
import bar
if bar.bar() is mod.CONSTANT:
do_something()
If the import wasn't cached, then mod.CONSTANT could be different in foo and in bar which would be very surprising.

Related

Monkey patch an object from another module in Python

I've a class, say foo, in module 1.
class foo():
def __init__(var1, var2):
self.var1 = var1
self.var2 = var2
def method1(self):
pass
def method2(self):
pass
foo_ = foo("blah", "blah")
The foo_ object is widely used in various modules across the code base. I've to write a test for a method in module 2 which uses the foo_ object.
Module 2:
from module1 import foo_
import module3
def blah():
foo_.method1()
module3.random_method()
return blah
The random_method in module 3 also imports and calls another method of foo_. I've a dummy foo_ object in my test module.The test is for the blah method. Here's what I've so far.
Test Module:
from module1 import foo
from module2 import blah
#pytest.fixture()
def dummy_foo_():
var1 = 'blah'
var2 = 'blah'
return foo(var1,var2)
def test_blah(dummy_foo_):
assert blah() == 'blah'
Is there a way I can get the test_blah to work where the blah method would use the dummy foo_ object instead of the one imported in the module 1?
You can use mock.patch to temporarily patch module1.foo_ with dummy_foo_ by using it as a context manager
from mock import patch
def test_blah(dummy_foo_):
with patch('module1.foo_', dummy_foo_) as mock:
assert blah() == 'blah'

Python Class variable not keeping value

I declared a class with a class variable.
Module name my_moudle_1.py
For example:
class my_class:
my_dict={}#The class variable
def __init__(self):
return
In a different module - my_moudle_2.py i wrote:
from my_moudle_1 import my_class
Inside this module there is a class. In the class method i wrote:
my_class.my_dict['123']=5
In third module - my_moudle_3.py i wrote again:
from my_moudle_1 import my_class
When i am checking the my_dict variable value in the instance of my_class, i get
that the value is {}.
How can i update in a different module the class variable and use it
inside an instance in a different file?
Thanks
That shouldn't be the case. I can't reproduce this problem:
mymod.py
class my_class:
my_dict = {}
def __init__(self):
return
my_class.my_dict['foo'] = 'bar'
mymod2.py
from mymod import my_class
my_class.my_dict['greeting'] = 'Hello'
testapp.py
from mymod import my_class
import mymod2 # will modify my_dict as a side effect
my_class.my_dict['barq'] = 'foo'
print(my_class.my_dict)
$ python3 testapp.py
{'foo': 'bar', 'greeting': 'Hello', 'barq': 'foo'}
$

Monkey patching a class in a function that is called from a child method (Python)

Let's say I have this situation:
module2.py
class Bar:
def bar():
a = 5
# do stuff
Messages.show("Done")
module1.py
import module2
class Foo:
def __init__(self):
self.bar = module2.Bar()
def foo(self):
self.bar.bar()
I want to test the method Foo.foo(), but I want to ignore Messages.show("Done), ie I want calls to the Messages.show function to be done on a mock object. If foo was calling Messages.show directly, I could use monkeypatch on foo to mock the Messages class. But now, I'm calling a class from another module and I don't know how to specify that Messages.show calls should not be done ( the reason being that they access the Gui and that doesn't work in a test environment). Let's assume I cannot modify module2.py.
Just override what module2 thinks Messages is:
import module2
module2.Messages = ...

Call undefined method from module

I have a module where I want to call a method not defined in that module. Is it possible?
#module
def foo():
print bar()
#main
from foo import foo
def bar():
return "Foo bar"
def main():
foo.foo()
No, you cannot. Python looks up undefined names in the same module a function is defined in.
You'll have to pass in a function reference instead:
def foo(func):
print func()
then in main:
def main():
foo.foo(bar)
You could add the function from one module to the other, but passing it as a callback is probably neater. It depends on the situation.
#module
def foo(bar):
print bar()
#main
from foo import foo
def bar():
return "Foo bar"
def main():
foo(bar)

import class defined in same module file?

I have a module file called mymodule.py, which contains the following code:
class foo:
def __init__(self):
self.foo = 1
class bar:
import foo
def __init__(self):
self.bar = foo().foo
The __init__.py file in the same directory has
from mymodule import foo
From a script in the same directory, I have the following code:
from mymodule import bar
When I try to run bar(), I get the error that No module named foo. How can I create an instance of foo in bar when they are defined within the same module file?
Classes are imported with module name first. However, you don't need to import classes in mymodule from within mymodule, just use it.
Meaning: remove the import foo line
You do not need to import an object defined in the same module:
class foo:
def __init__(self):
self.foo = 1
class bar:
def __init__(self):
self.bar = foo().foo
The import statement is intended for objects defined in other files only; you import the names defined in another python file into the current module.

Categories