As I try to use more and more functional programming (i.e. use classes less), I have noticed I start to use modules as classes:
#File foomod.py
foo = None
def get_foo():
global foo
if foo is None:
foo = 1 + 1
return foo
# main.py
import foomod
x = foomod.get_foo()
This might as well be
#File foo.py
class foo:
foo = None
#staticmethod
def get_foo(cls):
if cls.foo is None:
cls.foo = 1 + 1
return cls.foo
# main.py
from foo import Foo
x = Foo.get_foo()
Is there any reason to favour one over the other? E.g. speed or something else?
Related
Suppose I have some function A.foo() that instantiates and uses an instance of B, calling the member function bar on it.
How can I set return_value on a mocked instance of B when I'm testing my A class, given that I don't have access to the instance of B? Maybe some code would illustrate this better:
import unittest
import unittest.mock
import pandas
class A:
def foo(self):
b = B()
return b.bar()
class B:
def bar():
return 1
#unittest.mock.patch("__main__.B")
class MyTestCase(unittest.TestCase):
def test_case_1(self, MockB):
MockB.bar.return_value = 2
a = A()
self.assertEqual(a.foo(), 2)
test_case = MyTestCase()
test_case.test_case_1()
This fails with;
AssertionError: <MagicMock name='B().bar()' id='140542513129176'> != 2
Apparently the line MockB.bar.return_value = 2 didn't modify the return value of the method.
I think you are not initiating the MockB. You can directly mock "main.B.bar":
#unittest.mock.patch("__main__.B.bar")
class MyTestCase(unittest.TestCase):
def test_case_1(self, MockB):
MockB.return_value = 2
a = A()
self.assertEqual(a.foo(), 2)
You have just 1 mistake in your code. Replace this line:
MockB.bar.return_value = 2
To:
MockB.return_value.bar.return_value = 2
And it would work.
I assume the piece of code you pasted is just a toy example. If the class A and B lies on another file e.g. src/somedir/somefile.py, don't forget to patch the full path.
#unittest.mock.patch("src.somedir.somefile.B")
class MyTestCase(unittest.TestCase):
...
Update
To further expand on this, you can see some usage in the docs:
>>> class Class:
... def method(self):
... pass
...
>>> with patch('__main__.Class') as MockClass:
... instance = MockClass.return_value
... instance.method.return_value = 'foo'
... assert Class() is instance
... assert Class().method() == 'foo'
...
So in your case:
MockB.bar.return_value is like calling a static method e.g. print(MockB.bar())
MockB.return_value.bar.return_value is like calling a class/instance method e.g. print(MockB().bar())
To visualize this:
import unittest.mock
class SomeClass:
def method(self):
return 1
#unittest.mock.patch("__main__.SomeClass")
def test_mock(mock_class):
print(mock_class)
print(mock_class.return_value)
mock_class.method.return_value = -10
mock_class.return_value.method.return_value = -20
print(SomeClass.method())
print(SomeClass().method())
test_mock()
$ python3 test_src.py
<MagicMock name='SomeClass' id='140568144584128'>
<MagicMock name='SomeClass()' id='140568144785952'>
-10
-20
As you can see, mock_class.return_value is the one used for instance operations such as SomeClass().method().
You can solve this without mock.patch. Change the foo method to accept a factory for the dependency it should construct (DI).
class A:
def foo(self, b_factory: 'Callable[[], B]' = B):
b = b_factory()
return b.bar()
def normal_code():
a = A()
assert a.foo() == ...
def test():
dummy_b = ... # build a dummy object here however you like
a = A()
assert a.foo(b_factory=lambda: dummy_b) == 2
When you are debugging complex code, you sometimes need to transform:
def myfunction(self):
...
self.foo.bar = self.baz.bla
into
def myfunction(self):
...
self.foo.bar = self.baz.bla
print("myfunction", "self.foo.bar", self.foo.bar) # add this for debugging purposes
Is there a way (with a decorator or context manager or anything else) to automatically print the variable name and the value of the next line of code's assignement (and maybe also the current function)?
Example:
def myfunction(self):
...
with debug:
self.foo.bar = self.baz.bla
would output:
"myfunction self.foo.bar 123"
You can use the inspect module:
from inspect import currentframe
def f():
a = 5
debug_print("a")
def debug_print(var):
locals = currentframe().f_back.f_locals
print(f"{var} = {locals[var]}")
f()
See also here: Access parent namespace in python
I admit, it's only part of what you asked, but maybe a good start.
Edit: Ok what about this:
from inspect import currentframe, getsourcelines
class A:
def f(self):
self.b = 5
debug_print()
self.a = A()
self.a.a = 4
debug_print()
#staticmethod
def g():
A.c = 5
debug_print()
def debug_print():
frame = currentframe().f_back
locals = frame.f_locals
globals = frame.f_globals
source, start = getsourcelines(currentframe().f_back.f_code)
var_name = source[frame.f_lineno - 1 - start].split("=")[0]
tokens = var_name.strip().split(".")
var = locals.get(tokens[0], globals.get(tokens[0], None))
for t in tokens[1:]:
var = getattr(var, t)
print(f"{var_name} = {var}")
a = A()
a.f()
a.g()
At least now, it works with member attributes (including self), even nested. Also assignment of global variables, such as static attributes to the class.
Let's say I have a module named foo with a class Bar. Bar has a classwide counter attribute that allows me to track the order which instances were created. foo looks like this:
from itertools import count
class Bar:
class_count = count(0)
def __init__(self):
self.id = self.class_count.next()
Now I have a test file where I am testing the various functionalities of Bar. I am unsure of how to test this id attribute, because the other unittests are creating instances of Bar and so I don't know what the given id of a Bar instance should be. Furthermore, this behavior of my class means that my unittests are independent of each other, which is undesirable. How should I structure my unittests so the tests are independent of each other?
You could use setUp to safe the current count and then temporarily reset the count. Then with tearDown you restore the original state again:
from itertools import count
import unittest
class Bar:
class_count = count(0)
def __init__(self):
self.id = next(self.class_count)
class TestBar(unittest.TestCase):
def setUp(self):
self.nxtcount = next(Bar.class_count) # safe current state
Bar.class_count = count(0) # reset to 0
def tearDown(self):
Bar.class_count = count(self.nxtcount) # reset to old state
def teststh1(self):
x = Bar()
self.assertEqual(x.id, 0)
def teststh2(self):
x1 = Bar()
x2 = Bar()
x3 = Bar()
self.assertEqual(x1.id, 0)
self.assertEqual(x2.id, 1)
self.assertEqual(x3.id, 2)
This makes sure every test method will start with a Bar.class_count of 0.
I would stub out Bar to bypass the constructor.
class BarStub(Bar):
def __init__(self):
self.class_count = None
self.id = None
Now you can test like this:
class TestBar(...):
def setUp(...)
...
self.bar = BarStub()
def test_foo_should_blah_when_blah(self):
with mock.patch.object(self.bar, 'count_class', side_effect=[...]) as mock_count:
actual = self.bar.unit_under_test(...)
mock_count.assert_called_with([...])
If we have something like:
foo.py
from bar import bar
class foo:
global black;
black = True;
bar = bar()
bar.speak()
f = foo()
bar.py
class bar:
def speak():
if black:
print "blaaack!"
else:
print "whitttte!"
when we run
python foo.py
we get
NameError: global name 'black' is not defined
What's the best practise for doing something like this?
Should I pass it in the method?
Have the bar class have a parent variable?
For context, in practise the black global is for a debugging step.
In Python, globals are specific to a module. So the global in your foo.py is not accessible in your bar.py--not the way you have it written at least.
If you want every instance of foo to have its own value of black, then use an instance variable as Ivelin has shown. If you want every instance of foo to share the same value of black use a class variable.
Using an instance variable:
# foo.py
from bar import bar
class foo:
# Python "constructor"..
def __init__(self):
# Define the instance variables
self.bar = bar()
# Make bar talk
self.bar.speak()
# Create a function for making this foo's bar speak whenever we want
def bar_speak(self):
self.bar.speak()
################################################################################
# bar.py
class bar:
# Python "constructor"..
def __init__(self):
# Define the instance variables
self.black = True
def speak(self):
if self.black:
print "blaaack!"
else:
print "whitttte!"
Playing with the code:
>>> f = foo()
blaaack!
>>> b = foo()
blaaack!
>>> b.bar.black = False
>>> b.bar_speak()
whitttte!
>>> f.bar_speak()
blaaack!
Using a class variable:
# foo.py
from bar import bar
class foo:
# Python "constructor"..
def __init__(self):
# Define the instance variables
self.bar = bar()
# Make bar talk
self.bar.speak()
# Create a function for making this foo's bar speak whenever we want
def bar_speak(self):
self.bar.speak()
################################################################################
# bar.py
class bar:
black = True
def speak():
if bar.black:
print "blaaack!"
else:
print "whitttte!"
Playing with the code:
>>> f = foo()
blaaack!
>>> b = foo()
blaaack!
>>> bar.black = False
>>> b.bar_speak()
whitttte!
>>> f.bar_speak()
whitttte!
Here is what I would do:
foo.py
from bar import bar
class foo:
bar = bar(black=True)
bar.speak()
f = foo()
bar.py
class bar:
def __init__(black):
self.black = black
def speak():
if self.black:
print "blaaack!"
else:
print "whitttte!”
here's a sample code:
def foo():
def bar():
foobar = 'foobaz'
foobar = 'foobar'
print foobar
bar()
print foobar
foo()
I want to change variable foobar inside foo by function bar. The code above will not work, since foobar inside bar is in separate namespace with foobar in foo. A simple workaround would be making a global foobar and have both foo and bar can access it, but I hope there would be simpler workarounds.
On python 3.x you can use nonlocal and for python 2.x try using function attributes:
def foo():
def bar():
foo.foobar = 'foobaz' #change the function attribute
foo.foobar = 'foobar' #declare as function attribute
print foo.foobar
bar()
print foo.foobar
foo()
output:
foobar
foobaz
You are looking for the nonlocal keyword, which exists in 3.x.
def f():
x = None
def g():
nonlocal x
x = 1
If you are stuck in 2.x, you can do it by having a list or similar mutable data container and accessing that as a work around.
def f():
x = [None]
def g():
x[0] = 1
This works as variables do fall into scope, but won't leak out of scope. With mutable objects, we can change them inside the scope, and those changes propagate out.
Not possible in python 2.7. In python 3:
def foo():
def bar():
nonlocal foobar
foobar = 'foobaz'
foobar = 'foobar'
print foobar
bar()
print foobar
foo()
In 2.x, you can do:
def foo():
foobar = []
def bar():
foobar[0] = 'foobaz'
foobar[0] = 'foobar'
print foobar[0]
bar()
print foobar[0]
foo()
def foo():
def bar():
foobar = 'foobaz'
return foobar
foobar = 'foobar'
print foobar
foobar = bar()
print foobar
foo()
Even though functions are already first class objects in Python, you can create your own "functor" or function object something like this:
class Foo(object):
def bar(self):
self.foobar = 'foobaz'
def __call__(self):
self.foobar = 'foobar'
print self.foobar
self.bar()
print self.foobar
foo = Foo()
foo()