Python scope / namespace issue - python

I have two python modules:
//// funcs.py
from classes import *
def func():
d = D()
print "func"
if __name__ == "__main__":
c = C()
//// classes.py
from funcs import *
class C:
def __init__(self):
print "C class"
func()
class D:
def __init__(self):
print "D class"
Running funcs.py yields a NameError saying that "global name 'D' is not defined". However if I comment out the creation of the D() instance, everything works fine.
Why does this happen?
Thanks

This one works fine without complicating your code:
///funcs.py
import classes
def func():
d = classes.D()
print "func"
if __name__ == "__main__":
c = classes.C()
///classes.py
import funcs
class C:
def __init__(self):
print "C class"
funcs.func()
class D:
def __init__(self):
print "D class"
Sometimes it's much better to use simple import, than from ... import ....
There is quite good article on that:
http://effbot.org/zone/import-confusion.htm

The problem occurs due to the attempt to use a cyclically imported module during module initialization. To clarify, using the "from module use *" requires that a module be compiled. Instead if you switch to using "import module" in both cases, it should work fine.

Related

Python circular import when accessing method from class in separate module

I have two modules and each module contains a class. In each module I want to reference methods from the class in the other module. I have setup a small class to help wrap my head around the concept. I imported one module into the other module, but I am still getting a circular import error. To my understanding this is the proper way to do it, but I am still getting an error.
Here are my example classes:
a.py module:
import b
class A():
def __init__(self):
print("A has run")
def aa():
print("aa has run")
b.B.bb()
b.py module:
import a
class B():
def __init__(self):
print("B has run")
def bb():
print("bb has run")
# Run method from class in seperate module
a.A.aa()
Here is my error:
AttributeError: partially initialized module 'b' has no attribute 'B' (most likely due to a circular import)
If a.py is importing b.py and b.py is importing a.py, that's a circular import. Typically you want to restructure your code so that your modules do not need to import each other. Without seeing more about your actual use case, it's hard to give advice, but it could be something like this:
a.py module:
class A():
def __init__(self):
print("A has run")
def aa():
print("aa has run")
b.py module:
import a
class B():
def __init__(self):
print("B has run")
def bb():
print("bb has run")
# Run method from class in seperate module
a.A.aa()
c.py module
import b
b.B.bb()
You are right, that's due to circular import, and the reason is your import is at module level, instead if you exclude the module level import, you will not run in an issue, for example:
Modify your code like this:
class A():
def __init__(self):
print("A has run")
def aa():
print("aa has run")
if __name__ == '__main__':
import b
b.B.bb()
OUTPUT
bb has run
aa has run
Now, you'll no longer get the AttributeError because now the module b is not being imported at module level in module a.
Bit of a hack but the easiest (if hacky) way to get out of this is
class B():
def __init__(self):
print("B has run")
def bb():
print("bb has run")
import a # šŸ‘ˆimport on demand (each time)
# Run method from class in seperate module
a.A.aa()
A slightly better approach is to remember your import of a:
import b
class A():
def __init__(self):
print("A has run")
def aa():
print("aa has run")
print("running A")
b.B.bb()
b.B.bb()
class B():
def __init__(self):
print("B has run")
def bb():
print("bb has run")
#remember your import of a
a = getattr(B, "a", None)
if not a:
import a
B.a = a
# Run method from class in seperate module
a.A.aa()
You'll notice that "running A" only happens twice: once when you python a.py and then the first time b.B.bb() gets called and imports on demand.

how to import classes from one module and initialise and run it in django

How to import classes from all .py in a module with same structure and run by iterating over it. For Example,
module_one:
script_a:
class A:
def __init__(self,**kwargs):
code here
def run(self,**kwargs):
code here
def finish(self,**kwargs):
code here
script_b:
class B:
def __init__(self,**kwargs):
code here
def run(self,**kwargs):
code here
def finish(self,**kwargs):
code here
and so on ...
module_two:
script:
class Run:
def run_all(self,**kwargs):
for class in classes_from_module_one:
c = class()
c.run()
c.finish()
First of all, please note that module refers to python file, while to what you refer as module is usually called a package.
Now, for your problem, you could use some mixture of utilities found in pkgutil, importlib, and inspect or simple dir(). For example, using walk_modules and get_members:
# pack/mod_a.py
class A:
def __init__(self):
pass
def run(self):
print("A run!")
def finish(self):
print("A finished!")
# pack/mod_b.py
class B:
def __init__(self):
pass
def run(self):
print("B run!")
def finish(self):
print("B finished!")
# all.py
from importlib import import_module
from inspect import getmembers
from pkgutil import iter_modules
class Run:
def run_all(self, **kwargs):
modules = iter_modules(["pack"])
for module in modules:
members = getmembers(import_module(f"pack.{module[1]}"))
my_classes = [member for name, member in members if not name.startswith("_")]
for cls in my_classes:
c = cls()
c.run()
c.finish()
if __name__ == '__main__':
run = Run()
run.run_all()
The output is:
A run!
A finished!
B run!
B finished!
However for this solution you have to note, that getmembers will return all members of module - including built-ins, and imported entities to the modules - so you will have to implement your own check to properly filter-out those unwanted (see simple startswith in my example).

__import__ and name is not found error in python

When a.py has this code:
class A():
def __init__(self):
print 'hi'
I use class A with this code:
import a
b = a.A()
I need to do the same thing with __import__, and I tried this page:Why does Python's __import__ require fromlist?
__import__("a", fromlist=[])
#import a
b = a.A()
However, I got name 'a' is not defined error. What might be wrong?
__import__ returns a module. You need to bind the result to a name:
a = __import__("a")
a.A()

How does name resolution work when classes are derived across modules?

Classes B and C both derive from base class A, and neither override A's method test(). B is defined in the same module as A; C is defined in a separate module. How is it that calling B.test() prints "hello", but calling C.test() fails? Shouldn't either invocation end up executing A.test() and therefore be able to resolve the symbol "message" in mod1's namespace?
I'd also gratefully receive hints on where this behaviour is documented as I've been unable to turn up anything. How are names resolved when C.test() is called, and can "message" be injected into one of the namespaces somehow?
FWIW, the reason I haven't used an instance variable (e.g. set A.message = "hello") is because I'm wanting to access a "global" singleton object and don't want to have an explicit referent to it in every other object.
mod1.py:
import mod2
class A(object):
def test(self):
print message
class B(A):
pass
if __name__ == "__main__":
message = "hello"
A().test()
B().test()
mod2.C().test()
mod2.py:
import mod1
class C(mod1.A):
pass
output is:
$ python mod1.py
hello
hello
Traceback (most recent call last):
File "mod1.py", line 14, in <module>
mod2.C().test()
File "mod1.py", line 5, in test
print message
NameError: global name 'message' is not defined
Many thanks!
EOL is correct, moving the "main" part of the program into a new file mod3.py does indeed make things work.
http://bytebaker.com/2008/07/30/python-namespaces/ further clarifies the issue.
In my original question, it turns out that the variable message ist stored in the __main__ module namespace because mod1.py is being run as a script. mod2 imports mod1, but it gets a separate mod1 namespace, where the variable message does not exist. The following code snippet demonstrates more clearly as it writes message into mod1's namespace (not that I'd recommend this be done in real life), causing the expected behaviour.
import sys
class A(object):
def test(self):
print message
class B(A):
pass
if __name__ == "__main__":
import mod2
message = "hello"
sys.modules["mod1"].message = message
A().test()
B().test()
mod2.C().test()
I think the best real-world fix is to move the "main" part of the program into a separate module, as EOL implies, or do:
class A(object):
def test(self):
print message
class B(A):
pass
def main():
global message
message = "hello"
A().test()
B().test()
# resolve circular import by importing in local scope
import mod2
mod2.C().test()
if __name__ == "__main__":
# break into mod1 namespace from __main__ namespace
import mod1
mod1.main()
Could you use a class attribute instead of a global? The following works
import mod2
class A(object):
message = "Hello" # Class attribute (not duplicated in instances)
def test(self):
print self.message # Class A attribute can be overridden by subclasses
class B(A):
pass
if __name__ == "__main__":
A().test()
B().test()
mod2.C().test()
Not using globals is cleaner: in the code above, message is explicitly attached to the class it is used in.
That said, I am also very curious as to why the global message is not found by mod2.C().test().
Things work as expected, though, if the cross-importing is removed (no main program in mod1.py, and no import mod2): importing mod1 and mod2 from mod3.py, doing mod1.message = "Hello" there and mod2.C().test() works. I am therefore wondering if the problem is not related to cross-importingā€¦

How do I get the current file, current class, and current method with Python?

Name of the file from where code is running
Name of the class from where code is running
Name of the method (attribute of the class) where code is running
Here is an example of each:
from inspect import stack
class Foo:
def __init__(self):
print __file__
print self.__class__.__name__
print stack()[0][3]
f = Foo()
import sys
class A:
def __init__(self):
print __file__
print self.__class__.__name__
print sys._getframe().f_code.co_name
a = A()
self.__class__.__name__ # name of class i'm in
for the rest the sys and trace modules
http://docs.python.org/library/sys.html
http://docs.python.org/library/trace.html
Some more info:
https://mail.python.org/pipermail/python-list/2001-August/096499.html
and
http://www.dalkescientific.com/writings/diary/archive/2005/04/20/tracing_python_code.html
did you want it for error reporting because the traceback module can handle that:
http://docs.python.org/library/traceback.html
Be very careful. Consider:
class A:
pass
B = A
b = B()
What is the 'class name' of b here? Is it A, or B? Why?
The point is, you shouldn't need to know or care. An object is what it is: its name is very rarely useful.

Categories