Simple cross import in python - python

I want to separate code in different class and put them to different files. However those class are dependent on each other.
main.py:
from lib import A, B
def main():
a = A()
b = B()
a.hello()
b.hello()
if __name__ == '__main__':
main()
lib/_init_.py:
from a import A
from b import B
lib/a.py:
import lib.B
class A():
def __init__(self):
print "A"
def hello(self):
print "hello A"
b = B()
lib/b.py:
import lib.A
class B():
def __init__(self):
print "B"
def hello(self):
print "hello B"
a = A()
Is it possible to do that in Python?
EDIT:
I get this error message:
pydev debugger: starting
Traceback (most recent call last):
File "eclipse-python/plugins/org.python.pydev_2.7.1.2012100913/pysrc/pydevd.py", line 1397, in <module>
debugger.run(setup['file'], None, None)
File "eclipse-python/plugins/org.python.pydev_2.7.1.2012100913/pysrc/pydevd.py", line 1090, in run
pydev_imports.execfile(file, globals, locals) #execute the script
File "main.py", line 2, in <module>
from lib import A, B
File "lib/__init__.py", line 1, in <module>
from a import A
File "lib/a.py", line 1, in <module>
import lib.B
ImportError: No module named B

Instead of importing the modules on top, you could import the other module within the hello function.
class B():
def __init__(self):
print "B"
def hello(self):
from lib import A
print "hello B"
a = A()

When you have two classes depending on each other usually means that either they really belong to the same module or that you have a too tight coupling that should be resolved using dependency injection.
Now there are indeed a couple corner cases where importing from within the function is the "least worst" solution but that's still something you should avoid as much as possible.

Your main problem is that you're trying to import a class, but using syntax that only works to import a module. Specifically, import lib.A is never going to work if A is a class defined in module lib.a (and imported into the top-level namespace of lib).
What I suggest is that you avoid using the from _ import _ syntax unless you really need it. That makes the dependencies much easier to resolve:
lib/a.py:
import lib.b # note, we're not importing the class B, just the module b!
class A():
def foo(self):
return lib.b.B() # use the class later, with a qualified name
lib/b.py:
import lib.a # again, just import the module, not the class
class B():
def foo(self):
return lib.a.A() # use another qualified name reference
lib/__init__.py:
from a import A # these imports are fine, since the sub-modules don't rely on them
from b import B # they can be the public API for the A and B classes
You could also use relative module imports if you don't want a and b to be dependent on the name of their package lib.
This is sure to work because neither class A or B actually requires the other to exist yet in order to be defined. It's only after they're imported that instances of A need to know about the class B (and vise versa).
If one of the classes inherited from the other, or otherwise used an instance of the other at top level, you'd need to be more careful about which module was loaded up first, or it might still break.

If you want to import it only once you can import it in the constructor of the class and make the variable global:
class B():
def __init__(self):
global A
from lib import A
print "B"
def hello(self):
print "hello B"
a = A()
This would import A into a global variable and make it accessible form within the module.

Related

Python pass variable to imported module at "compilation" time

I'm trying to create an object from a custom class with a decorator in it.
Then I need to use the decorator of that object to create a bunch of functions in a different file.
I found the solution of using builtins online but it feels a bit hacky and makes my lsp spit out a bunch of errors.
I'm wondering if anyone knows a better solution.
This is my file structure:
main.py
mylib
├── A.py
└── B.py
main.py
import builtins
from mylib.A import A
a = A("This is printing in the decorator")
builtins.FOO = a
import mylib.B as B
B.foo()
B.poo()
A.py
class A:
def __init__(self, _message):
self.message = _message
def our_decorator(self, func):
def function_wrapper():
print(self.message)
func()
return function_wrapper
B.py
import builtins
#builtins.FOO.our_decorator
def foo():
print("foo")
#builtins.FOO.our_decorator
def poo():
print("poo")
I don't want to change the file structure if it can be avoided.
Using builtins to have a magically created decorator is indeed hacky.
An alternative would be to patch the functions in B from main. It is slightly cleaner (and linters should not complain) because the B module has no longer to be aware of the decorator:
main.py:
from mylib.A import A
a = A()
import mylib.B as B
# decorate here the functions of the B module
B.foo = a.our_decorator(B.foo)
B.poo = a.our_decorator(B.poo)
B.foo()
B.poo()
A.py is unchanged...
B.py:
def foo():
print("foo")
def poo():
print("poo")
As only one version of a module exists in a process, you can even use the functions of B from a third module, provided:
either it is imported after the decoration
or it only imports the module name (import mylib.B as B) and not directly the functions (from mylib.B import foo)

How to import a class from another file which is importing first class for [duplicate]

I want to separate code in different class and put them to different files. However those class are dependent on each other.
main.py:
from lib import A, B
def main():
a = A()
b = B()
a.hello()
b.hello()
if __name__ == '__main__':
main()
lib/_init_.py:
from a import A
from b import B
lib/a.py:
import lib.B
class A():
def __init__(self):
print "A"
def hello(self):
print "hello A"
b = B()
lib/b.py:
import lib.A
class B():
def __init__(self):
print "B"
def hello(self):
print "hello B"
a = A()
Is it possible to do that in Python?
EDIT:
I get this error message:
pydev debugger: starting
Traceback (most recent call last):
File "eclipse-python/plugins/org.python.pydev_2.7.1.2012100913/pysrc/pydevd.py", line 1397, in <module>
debugger.run(setup['file'], None, None)
File "eclipse-python/plugins/org.python.pydev_2.7.1.2012100913/pysrc/pydevd.py", line 1090, in run
pydev_imports.execfile(file, globals, locals) #execute the script
File "main.py", line 2, in <module>
from lib import A, B
File "lib/__init__.py", line 1, in <module>
from a import A
File "lib/a.py", line 1, in <module>
import lib.B
ImportError: No module named B
Instead of importing the modules on top, you could import the other module within the hello function.
class B():
def __init__(self):
print "B"
def hello(self):
from lib import A
print "hello B"
a = A()
When you have two classes depending on each other usually means that either they really belong to the same module or that you have a too tight coupling that should be resolved using dependency injection.
Now there are indeed a couple corner cases where importing from within the function is the "least worst" solution but that's still something you should avoid as much as possible.
Your main problem is that you're trying to import a class, but using syntax that only works to import a module. Specifically, import lib.A is never going to work if A is a class defined in module lib.a (and imported into the top-level namespace of lib).
What I suggest is that you avoid using the from _ import _ syntax unless you really need it. That makes the dependencies much easier to resolve:
lib/a.py:
import lib.b # note, we're not importing the class B, just the module b!
class A():
def foo(self):
return lib.b.B() # use the class later, with a qualified name
lib/b.py:
import lib.a # again, just import the module, not the class
class B():
def foo(self):
return lib.a.A() # use another qualified name reference
lib/__init__.py:
from a import A # these imports are fine, since the sub-modules don't rely on them
from b import B # they can be the public API for the A and B classes
You could also use relative module imports if you don't want a and b to be dependent on the name of their package lib.
This is sure to work because neither class A or B actually requires the other to exist yet in order to be defined. It's only after they're imported that instances of A need to know about the class B (and vise versa).
If one of the classes inherited from the other, or otherwise used an instance of the other at top level, you'd need to be more careful about which module was loaded up first, or it might still break.
If you want to import it only once you can import it in the constructor of the class and make the variable global:
class B():
def __init__(self):
global A
from lib import A
print "B"
def hello(self):
print "hello B"
a = A()
This would import A into a global variable and make it accessible form within the module.

Subclass __init__ not seeing superclass conditonally-imported module

I have a conditional import in a self-initialized instance of a superclass, but subclass cannot see the module (python 2.7):
class A(object):
def __init__(self, arg1):
self.attr1 = self.method1(arg1)
def method1(self, arg1):
if arg1 == 'foo':
import amodule
return amodule.method1()
else:
return 'not a dependency on foo'
class B(A):
def __init__(self, arg1):
super(B, self).__init__(arg1)
if arg1 == 'foo':
self.attr2 = self.method2(self.attr1)
def method2(self, attr1):
return amodule.method2()
if __name__=='__main__':
b = B("foo")
print b.attr2
This throws NameError: global name 'amodule' is not defined. a = A("foo") works just fine
Shouldn't the super call have executed import amodule in this case? (And using import should have put the module into globals?)
Doesn't import add /amodule/ to the global namespace of the currently
executing module? (__main__)?
No, the module is added to sys.modules but if it was imported locally then you won't have any references to it anymore. i.e the name amodule is now gone.
You could still access the module using sys.modules:
def method2(self, attr1):
import sys
return sys.modules['amodule'].method2()
Or you could import it using import amodule again and it will be picked up from sys.modules.
# Here b.py contains
# print('Module b was imported')
def func1():
print('inside func1')
import b
def func2():
print('inside func2')
import sys
print(sys.modules['b'])
import b
def func3():
print('inside func3')
import b
import sys
print('Deleted b')
del sys.modules['b']
import b
func1()
print()
func2()
print()
func3()
Demo:
inside func1
Module b was imported
inside func2
<module 'b' from '/Users/ashwini/py/b.py'>
inside func3
Deleted b
Module b was imported
Try putting import amodule on the first line of the program.
The reason is that amodule is imported in method1, method2 does not have access.
If you follow your code, you would see you don't reach method1().
When you create the object
b = B(foo)
You go through A.init() becuase the call for super(). However, your init of class A() doesn't include any import statements. Then the A.__init__ part is done, and you continue with B.__init__(). The next command is a call to amodule object, which wasn't imported at all.
You can add an helper method, which checks if the arg equals 'Foo' and if so import the module. Then add a call to this function in A.__init__() function.
On another note, __init__() job is to initialize variables. It shouldn't return anything.

Inheriting a class with the same name in Python

I am new in Python and I am trying to create two classes with the same name in two different source files. Let’s call them "Main.py" and "Extension.py". The class is "MyClass". MyClass in Extesntion.py is derived from MyClass in file Main.py. If it works then when I create an object myclass and I import Extension in my code, then I would have more functions in comparison with file Main.py.
File Main.py
class MyClass:
def __init__(self):
Initialize something
def foo1(self, a, b):
Do something
Then extension would be like this:
File Extensions.py
import Main
class MyClass(MyClass):
def __init__(self):
Initialize something
def foo2(self, a, b):
Do something
def foo3(self, a, b):
Do something
And then if I have code like this. I expect that I can't use foo2 and foo3.
import Main
myclass = MyClass()
myclass.foo1(a, b)
And finally if I have code like this. I expect that I use all the functions.
import Extension
myclass = MyClass()
myclass.foo1(a, b)
myclass.foo2(a, b)
myclass.foo3(a, b)
If you do
import main
you'll need to use main.MyClass to create an object from main.py.
Instead you can do
from main import MyClass
to have it available directly.
If you need two different classes with the same name, you can instead do
from main import MyClass as MainClass
and you'll have the class available under the name MainClass
Unless you do from Extension import *, you'll need to specify the module in order to access the class.
import Main
import Extension
foo = Main.MyClass()
bar = Extension.MyClass()
If you don't want to have to specify the module, then the only way to avoid a name collision is to import the class under a different name like so:
from Main import MyClass as ClassA
It's quite easy when you explicitly import the given name using the from {module} import {name} syntax.
File main.py
class MyClass:
def __init__(self):
pass
def foo1(self, a, b):
pass
File extensions.py
from main import MyClass
class MyClass(MyClass):
def __init__(self):
pass
def foo2(self, a, b):
pass
def foo3(self, a, b):
pass
File client_main.py
from main import MyClass
myinstance = MyClass()
myinstance.foo1(a, b)
File client_extensions.py
from extensions import MyClass
myinstance = MyClass()
myinstance.foo1(a, b)
myinstance.foo2(a, b)
myinstance.foo3(a, b)
Generally in this case, you would do an import as. This allows you to alias your import as a new name. So in the file where your second class is, import the first class as:
from main import MyClass as MainMyClass
Then when doing your inheritance, refer to MainMyClass:
class MyClass(MainMyClass):

Correct way to circular-import in package (for pep-0484)

I'm trying to figure out a (and the) way to correctly work with circular imports in python (3.4) packages. I fully understand that circular imports usually indicate a not-clean separation of code into modules, however annotating/type hinting with PEP-0484 will result in lots of circular imports in (I think) completely reasonable code. In this case also the usually suggested solution of putting imports in functions or at the bottom of a module, doesn't work.
Simple case (no package, no circular import):
[a.py]
import b
class A:
def __init__(self):
self.b = b.B(self)
def get_b():
return self.b
[b.py]
class B:
def __init__(self, parent):
self.parent = parent
[main.py]
import a
print(a.A())
Add PEP-0484 (no package, circular import, needs forward reference):
[a.py]
import b
class A:
def __init__(self):
self.b = b.B(self)
def get_b() -> b.B:
return self.b
[b.py]
import a
class B:
def __init__(self, parent: "a.A"):
self.parent = parent
[main.py]
import a
print(a.A())
So far, so good. However now I want to make this a package, and I can't get this to work.
[pack/__init__.py] (empty)
[pack/a.py]
from . import b
class A:
def __init__(self):
self.b = b.B(self)
def get_b() -> b.B:
return self.b
[pack/b.py]
from . import a
class B:
def __init__(self, parent: "a.A"):
self.parent = parent
[main.py]
from model import a
print(a.A())
The result for running python main.py is
Traceback (most recent call last):
File "main.py", line 1, in <module>
from model import a
File "/private/tmp/circ/model/a.py", line 1, in <module>
from . import b
File "/private/tmp/circ/model/b.py", line 1, in <module>
from . import a
ImportError: cannot import name 'a'
My questions:
I cannot understand why this fails with this error. As far as I understand from reading the import internals, the from . import a line in b.py should result in an empty module being imported, that only will get filled after module b is fully imported, which is fine.
What is the correct way to solve this? I need to refer to a in the module scope of b, and vice versa. No matter what combination of relative and absolute paths I try, importing both modules from the __init__.py file or even removing that file all together, I can't seem to make this run.

Categories

Resources