开发者

How does import keyword in python actually work?

Let's say I have 3 files:

a.py

from d import d

开发者_开发百科class a:
    def type(self):
        return "a"
    def test(self):
        try:
            x = b()
        except:
            print "EXCEPT IN A"
            from b import b
            x = b()
        return x.type()

b.py

import sys

class b:
    def __init__(self):
        if "a" not in sys.modules:
            print "Importing a!"
            from a import a
        pass
    def type(self):
        return "b"
    def test(self):
        for modules in sys.modules:
            print modules
        x = a()
        return x.type()

c.py

from b import b
import sys

x = b()
print x.test()

and run python c.py

Python comes back complaining:

NameError: global name 'a' is not defined

But, a IS in sys.modules:

copy_reg
sre_compile
locale
_sre
functools
encodings
site
__builtin__
operator
__main__
types
encodings.encodings
abc
errno
encodings.codecs
sre_constants
re
_abcoll
ntpath
_codecs
nt
_warnings
genericpath
stat
zipimport
encodings.__builtin__
warnings
UserDict
encodings.cp1252
sys
a
codecs
os.path
_functools
_locale
b
d
signal
linecache
encodings.aliases
exceptions
sre_parse
os

And I can alter b.py such that:

x = a()

changes to

x = sys.modules["a"].a()

And python will happily run that.

A couple questions arise from this:

Why does python say it doesn't know what a is, when it is in sys.modules?

Is using sys.modules a "proper" way to access class and function definitions?

What is the "right" way to import modules?

ie from module import x

or

import module


I guess it's a problem of scoping, if you import a module in your constructor you can only use it in your constructor, after the import statement.


According to the Python documentation,

Import statements are executed in two steps: (1) find a module, and initialize it if necessary; (2) define a name or names in the local namespace (of the scope where the import statement occurs).

So the problem is that even though module a has been imported, the name a has only been bound in the scope of the b.__init__ method, not the entire scope of b.py. So in the b.test method, there is no such name a, and so you get a NameError.

You might want to read this article on importing Python modules, as it helps to explain best practices for working with imports.


In your case, a is in sys.modules.. but not everything in sys.modules is in b's scope. If you want to use re, you'd have to import that as well.

Conditional importing is occasionally acceptable, but this isn't one of those occasions. For one thing, the circular dependency between a and b in this case is unfortunate, and should be avoided (lots of patterns for doing so in Fowler's Refactoring).. That said, there's no need to conditionally import here.

b ought to simply import a. What were you trying to avoid by not importing it directly at the top of the file?


It is bad style to conditionally import code modules based on program logic. A name should always mean the same thing everywhere in your code. Think about how confusing this would be to debug:

if (something)
  from office import desk
else
  from home import desk

... somewhere later in the code...
desk()

Even if you don't have scoping issues (which you most likely will have), it's still confusing.

Put all your import statements at the top of your file. That's where other coders will look for them.

As far as whether to use "from foo import bar" verses just "import foo", the tradeoff is more typing (having to type "foo.bar()" or just type "bar()") verses clearness and specificity. If you want your code to be really readable and unambiguous, just say "import foo" and fully specify the call everywhere. Remember, it's much harder to read code than it is to write it.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜