Communication between two Python files - python

I'm having a problem with importing files which can be simplified as this:
a.py:
import b
a = 0
b.foo()
b.py:
import a
def foo():
a.a=4
So, what I'm trying to do is: in file a.py call the function foo() from b.py which would then change the value of a variable that is in a.py. This is the error I get:
AttributeError: module 'b' has no attribute 'foo'
What am I doing wrong? What would be the proper way to do this?

your import is circular. you need to come up with a way of testing that with a non-circular import. e.g. create a new main file that you execute; import a.a and b.foo there:
main.py
from b import foo
import a
a.a = 7
foo()
a.py
a = 0
b.py
import a
def foo():
a.a=4

First and foremost thing is making circular import, and fixing it is not a good idea.
But try to do small change in your code and solve.
a.py:
from b import foo
a = 0
foo()
print a
b.py:
def foo():
import a as filea
filea.a=4
when you run a.py, watch the print a, it is executing two times. You need to be at your own risk by fixing lot of such things.
Instead of doing all circus, better to avoid circular import.

Related

Python: What happens when I modify imported class?

I have written the following code to modify the behavior of a method of one class
import mymodule
mymodule.MyClass.f = mydecorator(mymodule.MyClass.f)
mymodule.MyClass.f(x) # call the modified function
This works for my purposes, but: what have I modified exactly? Is mymodule.MyClass a copy of the original class living inside the current module? Does it in any way affect the original class? How does import work exactly?
When you modify imported module, you modify the cached instance. Thus your changes will affect all other modules, which import the modified module.
https://docs.python.org/3/reference/import.html#the-module-cache
UPDATE:
You can test it.
change_sys.py:
import sys
# Let's change a module
sys.t = 3
main.py:
# the order of imported modules doesn't meter
# they both use cached sys
import sys
import change_sys
print(sys.t)
Output for python ./main.py:
3
It depends. In normal uses cases everything should be ok. But one can imagine special cases where it can lead to weird results:
a.py:
import c
x = c.C()
def disp():
return x.foo()
b.py:
import c
def change():
c.C.foo = (lambda self: "bar at " + str(self))
c.py:
class C:
def foo(self):
return "foo at " + str(self)
Now in top level script (or interactive interpretor) I write:
import a
import b
a.disp()
b.change()
a.disp()
Output will be:
'foo at <c.C object at 0x0000013E4A65D080>'
'bar at <c.C object at 0x0000013E4A65D080>'
It may be what you want, but the change has been done in b module and it does affect a module.

Getting list functions in file that imported a module

This is for a project I am working on to help my own workflow, and nothing that is for production. So I understand that what I am doing is probably definitely not the right thing to do, but I am curious if it is possible anyways.
I have some code like this:
A.py:
from B import *
def f1():
...
def f2():
...
...
Is there any way for module B, when imported, to get a list of the functions defined in the importer, A.py?
I thought about using the inspect module, to inspect the call stack. But I was unsure where the entry point would be, I assume it would be in the global scope of B.py. I am also unsure what the call stack looks like when importing a module.
Any help would be appreciated.
Thanks!
If you know what module you are going to import B.py in then you could have something like this:
A.py
import B
def f1():
return 1
def f2():
return 1
def f3():
return 1
if __name__=="__main__":
print temp.allF()
B.py
import inspect, A
def allF():
return inspect.getmembers(A, inspect.isfunction)
When you run A.py it will give you a list of functions.
I'm not sure if there is a way to access the script which imports a given module, but if this is possible then you could change B.py slightly to use this.

how do imports work for a module used as a singleton?

I'm confused about what happens if you tread a module as a singleton.
Say I have a module conf.py, that contains some configuration parameters which need to be accessed by multiple other files. In conf.py, I might have this piece of code (and nothing else):
myOption = 'foo' + 'bar'
If I now import it first in a.py, and then in b.py, my understanding is that the first time it is imported (in a.py), the string concatenation will be executed. But the second time it is imported (in b.py), conf.myOption already has its value, so no string concatenation will be executed. Is this correct?
If after doing these two imports, I then execute the following in b.py
conf.myOption = 'aDifferentFoobar'
then obviously b.py would now see this new value. Would a.py see the same value, or would it still see 'foobar'?
I believe (but correct me if I'm wrong) that imports are always referred to by reference, not by value? And I'm guessing that's what the above questions boil down to.
Try it and see:
mod.py:
def foo():
print("in foo()")
return "foo"
bar = foo()
opt = "initial"
b.py:
import mod
mod.opt = "changed"
a.py:
import mod
import b
print(mod.bar)
print(mod.opt)
Execute a.py:
$ python3.4 a.py
Output:
in foo()
foo
changed
We learn:
foo() is only executed once
mod.opt is changed by b.py
a.py sees the changed value of mod.opt
bonus: the order of imports in a.py does not matter

Calling isinstance in main Python module

There is a strange behavior of isinstance if used in __main__ space.
Consider the following code
a.py:
class A(object):
pass
if __name__ == "__main__":
from b import B
b = B()
print(isinstance(b, A))
b.py
from a import A
class B(A):
pass
main.py
from a import A
from b import B
b = B()
print(isinstance(b, A))
When I run main.py, I get True, as expected, but when I run a.py, I am getting False. It looks like the name of A is getting the prefix __main__ there.
How can I get a consistent behavior?
I need this trick with import of B in a.py to run doctest on file a.py.
WSo what happens when you run a.py is that Python reads a.py and executes it. While doing so, it imports module b, which imports module a, but it does not reuse the definitions from parsing it earlier. So now you have two copies of the definitions inside a.py, known as modules __main__ and a and thus different __main__.A and a.A.
In general you should avoid importing modules that you are executing as well. Rather you can create a new file for running doctests and use something like
import a
import doctest
doctest.testmod(a)
and remove the __main__ part from module a.
Chain of events:
The a.py script is called.
The class A statement is executed, creating A in the __main__
namespace.
b is imported.
In b.py a is imported.
The class A statement is executed, creating A in the a namespace.
This A in the a namespace has no relation to the A in the
__main__ namespace other than having been generated by the same
code. They are different objects.
I agree with Helmut that it is best to avoid such circular imports. However, if you wish to fix your code with minimal changes, you could do the following:
Let's rename b.py --> bmodule.py so we can distinguish b the module from b the variable (hopefully in your real code these names are already distinct):
class A(object):
pass
if __name__ == "__main__":
import bmodule
b = bmodule.B()
print(isinstance(b, bmodule.A))
prints
True

What happens when a module is imported in python

I've following use case:
a.py:
import b
import c
c.fun()
b.py:
def fun():
print 'b'
c.py:
def fun():
b.fun()
python a.py doesn't work. It fails with NameError: global name 'b' is not defined.
My understanding of import in python was that a name is added in sys.modules. If that is the case then c.py should also see module b. But apparently that is not the case. So can anyone explain what exactly happens when a module is imported.
Thanks.
The module c.py has to import b in order to get this working...
When importing a module then it is added to the globals-dictionary that is available in the current script's scope only (use "globals()" to print its content)
You have to add all modules which you want to use in that script.
Other way to pass that module in function argument and after that you can call that modules method.
The other way is to add it in _ _ builtins _ _ which is better explain in other post
You have added b and c to the a module, but but not to the c module. When you are inside a module, you can only see what has been added to it. b and c are added to sys.modules, but you haven't imported sys, and you aren't using sys.modules['b'].

Categories

Resources