import module with name same as built-in module in python 3
Asked Answered
C

3

6

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().

Charactery answered 9/2, 2019 at 0:31 Comment(0)
T
5

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')
Terrilynterrine answered 9/2, 2019 at 1:4 Comment(1)
It's not my current code. In fact the same name is not math.py. Someone write a long code using python2 and at that time there is no such module.Charactery
R
0

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
Reduplicative answered 9/2, 2019 at 1:57 Comment(1)
Thank you. 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().Charactery
K
0

According to official docs: https://docs.python.org/3/library/imp.html

imp will be removed in version 3.12

Deprecated since version 3.4, will be removed in version 3.12: The imp module is deprecated in favor of importlib.

From imp approach (Deprecated):

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

To importlib approach with the minimum code 'impact' would be:

def load_module(name, path):
    from importlib import util as importlib_util
    module_spec = importlib_util.spec_from_file_location(name, path)
    module = importlib_util.module_from_spec(module_spec)
    module_spec.loader.exec_module(module)
    return module

m = load_module('math', './math.py')
m.foo()
Korey answered 25/11, 2022 at 3:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.