import module with name same as built-in module in

2019-07-16 21:39发布

问题:

I meet a similar problem which can be simplified as following:

For example I have a file structure as following:

----folder
    ---- main.py
    ---- math.py

I define a function in math.py and I want to import this math.py in main.py .

The codes in math.py is following

# math.py
def f(x) :
    return x**3

If I write codes in main.py as following

# main.py
import math

def main() :
    print(math.f(3))

if __name__ == "__main__":
    main()

then it returns AttributeError: module 'math' has no attribute 'f'

If I write codes in main.py as following

# main.py
from . import math

def main() :
    print(math.f(3))

if __name__ == "__main__":
    main()

Then it returns ImportError: cannot import name 'math' from '__main__' (main.py)

My question:

  1. If I only want to import the module math.py in path folder which has the same name as build-in module, what should I do?

  2. If in the main.py I want to use both math.f(x) defined in my math.py and built-in math.acos(x), what should I do?

PS: I meet similar problem since I have a long codes written by someone ten years ago. At that time there is no built-in module with such name (In fact it's not math module. I just simplify the problem by above question). And the functions of this module have been used at many places. Therefore it's almost impossible to change module's name since if so I need to carefully change all sites module.function().

回答1:

It's pretty bad practice to name your modules after built-in modules. I'd recommend naming your math.py something else.

That being said, you could import it using the path with imp:

import imp
math = imp.load_source('math', './math.py')


回答2:

Dove into a bit of a rabbit hole but here we go. As a disclaimer, like Jack said naming modules after builtins is very bad practice, and this can more easily be accomplished using imp as he suggested.

The reason you're having problems come from the interaction of a few things. When you type

import math

What your python does is look at sys.path. It will check in all the locations in sys.path for a module named math, and import the first one it finds. In your case, it finds your local math module first. After the import is completed, it adds it to sys.modules, but we'll get back to that.

Since you want to use both, first you can import your local math as you have. I would suggest importing it as a different name to keep it separate.

from . import math as local_math

After that, we need to mess with our sys.path to find the builtin math

sys.path = sys.path[::-1]

This reverses the order of sys.path, meaning it will look in your local directory first instead of last.

Now you might think this was enough, but if you try to import math here, python will see it in sys.modules and not bother trying to import again, so first

del sys.modules['math']

Then we can import the default math module

import math

and finally clean up our sys.path

sys.path = sys.path[::-1]

now we have access to everything we need

>>>math.cos(10)
-0.8390715290764524
>>>local_math.f(10)
1000