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)
Related
with the code below when I run file a.py the output expectedly is "hello" and with file b.py I want to override bar() from a so I get a "Goodbye" as a result
My goal with this is to change a more complicated function alongside of a program while implementing simpler functions in the main program
I understand that classes would work if a.py contained a class the b imported but that is a fair bit of overhead to rework my code to be a class
file a.py:
def foo ():
print (bar())
def bar ():
return "hello"
if(__name__=='__main__'):
foo()
output
hello
file b.py:
from a import *
def bar():
return "Goodbye"
if(__name__=='__main__'):
foo()
output
hello
Class Implementation
file a_class.py
class a:
def foo (self):
print (self.bar())
def bar (self) -> str:
return "hello"
if(__name__=='__main__'):
a().foo()
output
hello
file b_class.py
from a_class import a
class b(a):
def bar (self) -> str:
return "Goodbye"
if(__name__=='__main__'):
b().foo()
output
Goodbye
edit* grammer
As everyone has mentioned my only options would be to change my code to Object Oriented or to duplicate all the dependent functions into the new module
If I have a class that contains a method, and I call that method from an instance, how do I get the specific instance it was called from?
e.g. I have a class:
class foo:
def __init__(self):
pass
def do_something(self):
bar()
I also have a function:
def bar():
print()
If i make an object, e.g. obj = foo(), and then i call obj.do_something(), How would i get obj from inside my bar() function?
Using the inspect module, you can get the caller frame and access its local variables, in particular the self argument representing the instance:
import inspect
def bar():
caller = inspect.stack()[1].frame
localvars = caller.f_locals
self = localvars['self']
I have been working with Python's unittest.mock library quite a bit, but right now I'm struggling with a use case that may not be approached correctly.
Consider a file mymodule/code.py containing the following snippet:
def sum():
pass
def mul():
pass
def div():
pass
def get_functions():
return [sum, mul, div]
def foo():
functions = get_functions()
for func in functions:
func()
I want to test the foo function, patching the sum function, and leaving mul and div as they are. This is what I tried initially:
class TestFoo(unittest.TestCase):
#mock.patch('mymodule.code.foo.sum')
def test_foo(foo_sum_mock):
foo()
foo_sum_mock.assert_called_once()
However, the patching approach illustrated above does not work. I believe that the sum function is patched correctly when loading mymodule.code.py, but redefined due to the def sum() block.
By reading the official documentation, I also tried to use the start and stop functions of the unittest.mock library as follows:
def test_foo():
patcher = mock.patch('module.code.sum')
mocked_sum_fun = patcher.start()
foo()
mocked_sum_fun.assert_called_once()
mock_sum_fun.stop()
This approach also did not work. I was hoping it would avoid the sum function override after the modules/code.py file gets loaded.
Is it possible to patch a local function such as sum? Or is moving the sum function to another file the only option for patching?
Many thanks in advance!
You can mock a function of same module using mock.patch and refering this module as __main__
code.py
from unittest.mock import patch
def sum():
print("called method sum")
pass
def call_sum():
sum()
def return_mock():
print("I'm a mocked method")
return True
with patch('__main__.sum', return_value=return_mock()) as mock_test:
call_sum()
mock_test.assert_called_once() # assure that mocked method was called, not original.
You could also use the path of lib (my_project.code.sum) instead of __main__.sum.
Generally speaking, you'd want to separate your test code from your production code:
code.py
def sum():
pass
def mul():
pass
def div():
pass
def get_functions():
return [sum, mul, div]
def foo():
functions = get_functions()
for func in functions:
func()
code_test.py
import unittest
import mock_test as mock
import code
class TestFoo(unittest.TestCase):
#mock.patch('code.sum')
def test_foo(self, sum_mock):
def new_sum_mock(*args, **kwargs):
# mock code here
pass
sum_mock.side_effect = new_sum_mock
code.foo()
sum_mock.assert_called_once()
But yes, you could place it all into one file:
code_test.py:
import unittest
import mock_test as mock
import code
def sum():
pass
def mul():
pass
def div():
pass
def get_functions():
return [sum, mul, div]
def foo():
functions = get_functions()
for func in functions:
func()
class TestFoo(unittest.TestCase):
#mock.patch('code_test.sum')
def test_foo(self, sum_mock):
def new_sum_mock(*args, **kwargs):
# mock code here
pass
sum_mock.side_effect = new_sum_mock
code.foo()
sum_mock.assert_called_once()
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.
I have a static class that has a method hello. I want to run the decorator method bar before hello. However, using the following code I always get a "name 'bar' is not defined" error. Does anyone know what's going on? Thanks!
class foo():
#staticmethod
#bar
def hello():
print "hello"
def bar(fn):
def wrapped():
print "bar"
return fn()
return wrapped
foo.hello()
Because it's not defined yet. Besides, that decorator shouldn't be a method at all.
def bar(fn):
# ...
class foo(object):
#staticmethod
#bar
def hello():
# ...
# ...
Also, don't use static methods, unless you really know what you're doing. Make it a free function instead.
You can just change your code to:
def bar(fn):
def wrapped():
print "bar"
return fn()
return wrapped
class foo():
#staticmethod
#bar
def hello():
print "hello"
foo.hello()
This happens because you have to define a function before you call it. This is a problem because this:
#bar
def hello():
print "hello"
is equivalent to:
def hello():
print "hello"
hello = bar(hello)
So you were trying to call the function before you defined it.