Namespaces with Module Imports

后端 未结 5 1238
Happy的楠姐
Happy的楠姐 2020-11-27 18:06

I am learning Python and am still a beginner, although I have been studying it for about a year now. I am trying to write a module of functions which is called within a main

相关标签:
5条回答
  • 2020-11-27 18:26

    As the traceback shows, the problem isn't in main.py, but in module1.py:

    Traceback (most recent call last):
      File "Z:\Python\main.py", line 10, in <module>
        module1.cool()
      File "Z:\Python\module1.py", line 3, in cool
        print pi
    NameError: global name 'pi' is not defined
    

    In other words, in module1, there is no global name pi, because you haven't imported it there. When you do from math import * in main.py, that just imports everything from the math module's namespace into the main module's namespace, not into every module's namespace.

    I think the key thing you're missing here is that each module has its own "global" namespace. This can be a bit confusing at first, because in languages like C, there's a single global namespace shared by all extern variables and functions. But once you get past that assumption, the Python way makes perfect sense.

    So, if you want to use pi from module1, you have to do the from math import * in module1.py. (Or you could find some other way to inject it—for example, module1.py could do from main import *, or main.py could do module1.pi = pi, etc. Or you could cram pi into the magic builtins/__builtin__ module, or use various other tricks. But the obvious solution is to do the import where you want it imported.)


    As a side note, you usually don't want to do from foo import * anywhere except the interactive interpreter or, occasionally, the top-level script. There are exceptions (e.g., a few modules are explicitly designed to be used that way), but the rule of thumb is to either import foo or use a limited from foo import bar, baz.

    0 讨论(0)
  • 2020-11-27 18:30

    "Explicit is better than implicit" is a design decision that was made by the creators of Python (launch python and run import this).

    Therefore, when you run module1.cool(), Python will not look for the undefined pi in the main module.


    You'll have to import the math module in explicitly whenever you want to use it - that's just how Python works.

    Also, you should avoid from X import *-style imports, that's bad practice too. Here, you could do: from math import pi.

    0 讨论(0)
  • 2020-11-27 18:30

    Inside the module you could simply define from math import pi, which would only import pi from math but not the entire math module.

    0 讨论(0)
  • 2020-11-27 18:50

    The simple approach of exec (python 3) or execfile (python 2) as mentioned in the comments by @abarnert may be useful for some workflows. All that is needed is to replace the import line with:

    exec( open("module1.py").read() )       # python 3
    

    and then you can simply call the function with cool() rather than module1.cool(). Within cool(), the variable pi will behave like a global, as the OP had originally expected.

    In a nutshell, this is simply hiding a function definition that would otherwise appear at the top of your main program and has both advantages and disadvantages. For large projects with multiple modules and imports, using exec (instead of a proper namespaces) is probably a mistake as you don't generally want to keep too many things within a single global namespace.

    But for simple cases (like using Python as a shell script) exec gives you a simple and concise way to hide shared functions while letting them share the global namespace. Just note that in this case you might want to give extra thought to how you name your functions (e.g. use v1_cool and v2_cool to keep track of different versions since you can't do v1.cool and v2.cool).

    One less obvious disadvantage of using exec here is that errors in the executed code may not display the line number of the error although you can work around this: how to get the line number of an error from exec or execfile in Python

    0 讨论(0)
  • 2020-11-27 18:52

    As others have said, there isn't actually a global pi in your module1. A good solution for you is this, which only imports pi once from math and explicitly ensures that the pi you're getting is the one from module1:

    main.py:

    import module1
    
    def wow():
        print module1.pi
    
    wow()
    module1.cool()
    

    module1.py:

    from math import pi
    
    def cool():
        print pi
    
    0 讨论(0)
提交回复
热议问题