简体   繁体   中英

Problems in Python with difference between import module and from module import

I have had a problem with the difference between import module and from module import name1, name2 ... in Python. I am a newcomer (last week) to Python, using Python 3.6 on Windows-64.

In the Python Tutorial there is a short discussion of these two import approaches. It is stated that from module import * is not recommended because of the danger of polluting the current namespace. However, there is no indication that there is any material operational difference between import module and from module import name1, name2.. , with the implication that this is a matter of preference or convenience.

However, there seems to be a big difference in practice. Consider this module named ModuleA, defining a global variable and a function:

# ModuleA
iGlobalA = 0

def fA():
    iGlobalA += 1
    print( "MA: iGlobalA=", iGlobalA )

print( "Module A Initialised, iGlobalA=", iGlobalA )

Using import ModuleA creates a separate ModuleA namespace. Now the members of that module are available as public members of the namespace, like this:

import ModuleA as MA

def fX():
    print( "MX: Before, ModuleA.iGlobalA=", MA.iGlobalA )
    MA.fA()
    print( "MX: After 1, ModuleA.iGlobalA=", MA.iGlobalA )
    MA.fA()
    print( "MX: After 2, ModuleA.iGlobalA=", MA.iGlobalA )

fX()

This is the output:

MA: Initialised, iGlobalA= 100
MX: Before, ModuleA.iGlobalA= 100
MA: iGlobalA incremented to 101
MX: After 1, ModuleA.iGlobalA= 101
MA: iGlobalA incremented to 102
MX: After 2, ModuleA.iGlobalA= 102

which is exactly as expected. Contrast this with ModuleY which uses the form from ModuleA import fA, iGlobalA and then refers to these members of ModuleA without qualification:

# ModuleY
from ModuleA import fA, iGlobalA   

def fY():
    print( "MY: Before, ModuleA.iGlobalA=", iGlobalA )
    fA()
    print( "MY: After 1, ModuleA.iGlobalA=", iGlobalA )
    fA()
    print( "MY: After 2, ModuleA.iGlobalA=", iGlobalA )

fY()

In this case the output is:

MA: Initialised, iGlobalA= 100
MY: Before, ModuleA.iGlobalA= 100
MA: iGlobalA incremented to 101
MY: After 1, ModuleA.iGlobalA= 100
MA: iGlobalA incremented to 102
MY: After 2, ModuleA.iGlobalA= 100

In this case the global variable iGlobalA is imported as a copy from ModuleA after ModuleA is initialised, and becomes a completely separate variable from ModuleA.iGlobalA . It is also true that function fA is imported as a reference to the function in ModuleA as defined at the time of import - if the function is reassigned at some later point within ModuleA, then the reference to fA() in the importing module remains unchanged, pointing only to the function as originally imported.

I would have thought these differences between these import syntaxes should be more clearly stated in the documentation. It also means that someone designing a library module needs to specify how that module should be imported.

Edit - after comment by @abdullah-ahmed-ghaznavi These are my questions

  • Did I miss something in the documentation?
  • Is this behaviour the same across all platforms?
  • Is this the intended behaviour that can be relied upon in future?

In this case the global variable iGlobalA is imported as a copy from ModuleA

Nope. Just after from ModuleA import iGlobalA , both ModuleA.iGlobalA and ModuleY.iGlobalA point to the very same object - you can check this by printing id(iGlobalA) in both modules. Now while both names (initially) point to the same object, the names themselves are distinct - they live in different namespaces (one in ModuleA and the other in ModuleY ), so when fA() rebinds the name iGlobalA - which is really ModuleA.iGlobalA - only the name leaving in ModuleA is impacted (so at this point both names point to different objects).

On the other hand when in ModuleY you use the qualified name ModuleA.iGlobalA , you only have one single name, so when this name is rebound (in ModuleA ) by fA() you see the change in ModuleY , because you are really checking the same name .

Note that if instead of rebiding a name you had tried the same thing with mutating a mutable object (ie appending to a list, updating a dict etc) you wouldn't have noticed any difference in behaviour:

# ModuleA
iGlobalA = []

def fA():
    iGlobalA.append(1)
    print( "MA: iGlobalA=", iGlobalA )

print( "Module A Initialised, iGlobalA=", iGlobalA )

What you need to understand here is mainly what Python "variables" really are , and also that Python has no real global namespace ("global" really means "module level").

I would have thought these differences between these import syntaxes should be more clearly stated in the documentation.

Possibly yes. Note that there actually some documentation about the whole thing, cf https://docs.python.org/3/reference/simple_stmts.html#import and https://docs.python.org/3/reference/import.html , but you do indeed have to understand what "defines a name in the local namespace" and "a reference to that value is stored in the local namespace" really imply.

It also means that someone designing a library module needs to specify how that module should be imported.

The problem here is either that the lib is badly designed (and if it uses globals that way it is badly designed indeed) or (at least) that the name you tried to access is not (or should not be) part of the lib's API.

Did I miss something in the documentation?

Possibly too, I'm afraid I'm far too used to how this work to remember how I first learned it

Is this behaviour the same across all platforms? Is this the intended behaviour that can be relied upon in future?

Yes and yes. This is part of the language's specifications actually and changing it would break almost all existing code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM