Why do I have to import a library twice in Python (IDLE and the imported file)? - python-3.x

I am running Python 3.7.6 shell and have the library numpy installed correctly.
In my shell I type:
import numpy as np
and can use numpy however I desire. I then proceed to import 'my_lib.py' which contains:
def softmax(x):
e_x = np.exp(x - np.max(x))
return e_x / e_x.sum(axis=0)
In my shell I can call the function softmax(x) but I immediately get the error
NameError: name 'np' is not defined
My hypothesis here would be I've imported numpy into 'shell scope' and i've also imported softmax(x) into 'shell scope' so everything should be happy. To fix this problem I have to add
import numpy as np
into 'my_lib.py'.
How come I have to import numpy twice?

The code in each module can only use identifiers (names) that have be defined in or imported into that module. The global dict in each module only contains names global to that module. It might better be called the module dict or modular dict, but the name goes back to when there were no modules in computing.
You might benefit from reading https://docs.python.org/3/tutorial/modules.html and probably elsewhere in the tutorial.
(None of this has anything to do with the editor you use to write code or the IDE or shell you use to pass code to Python.)

Related

inspect.py file in folder makes importing pandas not work anymore

I am sorry if this is a silly question but I came across a wierd behaviour. I have a folder with some files, one of them named inspect.py
However, if I change the name inspect.py to somethingelse.py, importing pandas starts working.
I would really like to understand why this is. I assume it has something to do with the module called inspect which (I THINK??) comes by default installed.
Can anyone help me understand this, please?
Looking a np.ma.core.py I see
import builtins
import inspect
import operator
import warnings
import textwrap
import re
These are all base Python modules. Your local inspect.py gets imported instead, which messes with the importing the rest of np.ma.core, and numpy in turn. And pandas depends on numpy.

Python: how to write a function which depends on external modules

If we write a function which depends on some packages / modules, do we need to import all the modules from within function? Or do we somehow (how?) check for dependencies and raise an error / warning? How to do it in efficient manner as the function might be called many-many times? And how do we deal with aliases? I mean if the code that calls the function has imported a required package but used an alias, e.g. import numpy as np, how do we access it from within the function?
So looking at your comment I would suggest you have answered your own question. You understand that you don’t expect the user to know about a function’s module dependencies.
You say you want to have this function in a module - let’s call it my_module for now.
So you have a file my_module.py:
#Add any imports code in this module relies on
import os
import numpy as np
def my_numpy_func(arg1, arg2):
#function code using numpy e.g.
my_arr = np.array(arg1)
#etc etc
return result
def some_other_func():
#blah blah blah
Now anyone who wants to use your function can simply write from my_module import my_numpy_func and not have to worry about loading the dependencies.
Note: this doesn’t have anything to do with ensuring that a user actually has required non-standard packages installed on their machine. For example if they have not installed numpy they will get an ImportError when they try to import your function.
If you want to distribute your code and make it so that users don’t need to worry about that, then you probably need to make your code a package that makes the dependencies a requirement on installation.

NameError: name 'log10' is not defined in function called in script

Why log10() is failing to be recognized when called within a function definition in another script? I'm running Python3 in Anaconda (Jupyter and Spyder).
I've had success with log10() in Jupyter (oddly without even calling "import math"). I've had success with defining functions in a .py file and calling those functions within a separate script. I should be able to perform a simple log10.
I created a new function (in Spyder) and saved it in a file "test_log10.py":
def test_log10(input):
import math
return math.log10(input)
In a separate script (Jupyter notebook) I run :
import test_log10
test_log10.test_log10(10)
I get the following error:
"NameError: name 'log10' is not defined"
What am I missing?
Since I'm not using the environment of Jupyther and alike, I don't know how to correct it in these system, perhaps there is some configuration file over there,check the documentation.
But exactly on the issue, when this happens its because python has not "linked" well something at the import, so I suggest a workaround with the libs in the next way:
import numpy as np
import math
and when you are using functions from math, simply add the np. before, i.e.:
return math.log10(input)
to
return np.math.log10(input)
Exactly I don't know why the mismatch, but this worked for me.

import module with name same as built-in module in python 3

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:
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?
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().
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')
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
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()

Why don't I need to import sys?

I have 2 python scripts, both utilizing sys.stdout, sys.exit(), etc. In one script, PyCharm highlights "import sys" as gray, (meaning it is never used), and if I remove the import statement, the program works just fine, including sys.stdout and sys.exit().
However, the second module does not highlight "import sys" as gray, and if I try to run it without that statement, I get an error on the first occurrence of sys.stdout:
NameError: name 'sys' is not defined
I have looked up the official documentation for sys, which says
"This module provides access to some variables used or maintained by the interpreter and to functions that interact strongly with the interpreter. It is always available."
Yet, most guides or instructions on how to use sys tell you to import.
So, do I have to import it or not? Why does one program need to, but not the other?
Possibly important differences between the two programs:
One program has a main function, and imports the other program. This is the one that does not need to import sys. Perhaps it inherently imports sys when it imports the other one as a module?
It seems that the first script does not just import the second script; it imports * from it, like this:
in module_1:
from module_2 import *
And in module_2:
import sys
This causes module_1 to import sys, indirectly. If I change
from module_2 import *
to
import module_2
then it no longer works.

Resources