Do not see module imports at top level of Python package - python

Consider the following python package structure
working_directory/
-- test_run.py
-- mypackge/
---- __init__.py
---- file1.py
---- file2.py
and say inside file1.py I have defined a function, func1() and I've also imported some functions from numpy with something like from numpy import array. Now I want to import and use mypackage from test_run.py without seeing these numpy functions in the namespace. I want to import it using import mypackage as mp and see
mp.file1.func1()
mp.file2.func2()
etc
I don't want to see mp.file1.array(). How can I do it?

One possibility would be to use underscores:
from numpy import array as _array.
Although this doesn't prohibit people from accessing mp.file1._array it is a general considered that variables beginning with underscores are 'private'.
AFAIK, there is no simple way to disallow access to any variable in python. (one way would be to make it properties of a class, see: https://docs.python.org/3/library/functions.html#property)

Related

Multi layer package in python

I have a python package with packages in it. This explanation seems strange, so I'll include my package's structure:
package\_
__init__.py
subpackage1\_
__init__.py
file1.py
subpackage2\_
__init__.py
file2.py
(I'm simplifying it for easier understanding).
The __init__.py on the top level looks like this:
__all__ = ["subpackage1", "subpackage2"]
And, for some reason, when importing the package, it dosen't recognise anythong from file1.py or file2.py. Any ideas how to fix it?
If you need more details, here's the project on github: https://github.com/Retr0MrWave/mathModule
. The directory I called package is mathmodule_pkg in the actual project
Filling the __all__ field with names does not make imports possible, it merely serves as a hint of what you mean to make importable. This hint is picked up by star-imports to restrict what is imported, and IDEs like pycharm also use it to get an idea of what is and isn't exposed - but that's about it.
If you want to enable top-level imports of your nested classes and functions, you need to
import them into the top-level __init__.py
bind them to names that can be used for the import
optionally, reference said names in __all__ to make the API nice and obvious
Using the project you're referencing as an example, this is what it would look like:
mathmodule_pkg/__init__.py
import mathmodule_pkg.calculus.DerrivativeAndIntegral #1
integral = mathmodule_pkg.calculus.DerrivativeAndIntegral.integral #2
__all__ = ['integral'] # 3
Using the very common form of from some.package import some_name we can combine steps 1 and 2 and reduce the potential for bugs when re-binding the name:
from mathmodule_pkg.calculus.DerrivativeAndIntegral import integral # 1 and 2
__all__ = ['integral'] # 3
Using either form, after installing your package the following will be possible:
>>> from mathmodule_pkg import integral
>>> integral(...)

Import specific names only

I have the following package structure:
analysis/
__init__.py
main.py
utils/
__init__.py
myzip.py
myzip.py contains the following:
import pandas
def save():
...
def load():
...
In my main.py script I do:
from utils import myzip
and when I type myzip.<TAB> or do dir(myzip) the imported pandas appears as well. Can I avoid showing the pandas imported in the submodule? Is there a best practice for importing third party modules?
I tried adding the following to analysis/utils/__init__.py:
from utils.myzip import save, load
but it still shows pandas when I dir(myzip) form main.py.
Looking at from sklearn import cluster they manage to achieve this, without showing all the numpy imports they have e.g. in cluster/k_means_.py
As described in this question, you can import the modules with an alias that begins with an underscore (e.g., import pandas as _pandas). The name will still be available as myzip._pandas, but IPython tab-completion will not autocomplete it (unless you explicitly type the underscore first). Also, it will not be imported if you do from myzip import *, although you shouldn't do that anyway.
However, as mentioned in this other question, the better "solution" is to just not worry about it. If someone does import myzip, it does no harm for them to be able to access myzip.pandas; it's not like they couldn't import pandas themselves anyway. Also, there is no risk of a name conflict in this situation, since pandas is namespaced under your module. The only way a name conflict could arise is if your module itself used the name pandas for two different things (e.g., defining a global variable called pandas in addition to the imported module); but this is a problem internal to your module, regardless of whether pandas is externally accessible.
A name conflict can arise if someone has their own variable called pandas and then does from myzip import *, but star import is discouraged for precisely that reason, and the names of imported modules are no different than other names in this regard. For instance, someone doing from myzip import * could face a conflict with the names save or load. There's no use in worrying specifically about imported module names when it comes to star-import name conflicts.
Also, it's worth noting that many widely-used libraries expose their own imports in this way, and it's not considered a problem. Pandas itself is an example:
>>> import pandas
>>> pandas.np
<module 'numpy' from '...'>
. . . so you are in good company if you just consider it a non-problem.
If moduleB is imported at the module-level of moduleA, then moduleB is part of the namespace of moduleA.
One way to hide it however would be to import it with an alias:
import pandas as _hidden_pandas
It would then appear as _hidden_pandas, hiding it to some extent.
The tab-completion would at least not find it.
A partial solution
Nest the submodule into a folder and import only the necessary methods in the __init__.py, that is:
analysis/
__init__.py
main.py
utils/
__init__.py
--> myzip/
__init__.py
myzip.py
where the myzip/__init__.py has:
from .myzip import load, save
then after from utils import myzip the dir(myzip) will list load, save and myzip, but not the pandas, which is hidden inside myzip.myzip.<TAB>.
Have not figured out how sklearn hide their third party modules.

Importing with dot notation

Can someone explain this to me?
When you import Tkinter.Messagebox what actually does this mean (Dot Notation)?
I know that you can import Tkinter but when you import Tkinter.Messagebox what actually is this? Is it a class inside a class?
I am new to Python and dot notation confuses me sometimes.
When you're putting that dot in your imports, you're referring to something inside the package/file you're importing from.
what you import can be a class, package or a file, each time you put a dot you ask something that is inside the instance before it.
parent/
__init__.py
file.py
one/
__init__.py
anotherfile.py
two/
__init__.py
three/
__init__.py
for example you have this, when you pass import parent.file you're actually importing another python module that may contain classes and variables, so to refer to a specific variable or class inside that file you do from parent.file import class for example.
this may go further, import a packaging inside another package or a class inside a file inside a package etc (like import parent.one.anotherfile)
For more info read Python documentation about this.
import a.b imports b into the namespace a, you can access it by a.b . Be aware that this only works if b is a module. (e.g. import urllib.request in Python 3)
from a import b however imports b into the current namespace, accessible by b. This works for classes, functions etc.
Be careful when using from - import:
from math import sqrt
from cmath import sqrt
Both statements import the function sqrt into the current namespace, however, the second import statement overrides the first one.

Python module: how to prevent importing modules called by the new module

I am new in Python and I am creating a module to re-use some code.
My module (impy.py) looks like this (it has one function so far)...
import numpy as np
def read_image(fname):
....
and it is stored in the following directory:
custom_modules/
__init.py__
impy.py
As you can see it uses the module numpy. The problem is that when I import it from another script, like this...
import custom_modules.impy as im
and I type im. I get the option of calling not only the function read_image() but also the module np.
How can I do to make it only available the functions I am writing in my module and not the modules that my module is calling (numpy in this case)?
Thank you very much for your help.
I've got a proposition, that could maybe answer the following concern: "I do not want to mess class/module attributes with class/module imports". Because, Idle also proposes access to imported modules within a class or module.
This simply consists in taking the conventional name that coders normally don't want to access and IDE not to propose: name starting with underscore. This is also known as "weak « internal use » indicator", as described in PEP 8 / Naming styles.
class C(object):
import numpy as _np # <-- here
def __init__(self):
# whatever we need
def do(self, arg):
# something useful
Now, in Idle, auto-completion will only propose do function; imported module is not proposed.
By the way, you should change the title of your question: you do not want to avoid imports of your imported modules (that would make them unusable), so it should rather be "how to prevent IDE to show imported modules of an imported module" or something similar.
You could import numpy inside your function
def read_image(fname):
import numpy as np
....
making it locally available to the read_image code, but not globally available.
Warning though, this might cause a performance hit (as numpy would be imported each time the code is run rather than just once on the initial import) - especially if you run read_image multiple times.
If you really want to hide it, then I suggest creating a new directory such that your structure looks like this:
custom_modules/
__init__.py
impy/
__init__.py
impy.py
and let the new impy/__init__.py contain
from impy import read_image
This way, you can control what ends up in the custom_modules.impy namespace.

Pulling python module up into package namespace

If I have a directory structure like this:
package/
__init__.py
functions.py #contains do()
classes.py #contains class A()
And I want to be able to call
import package as p
How do I make the contents of functions, classes, accessible as:
p.do()
p.A()
in stead of:
p.functions.do()
p.classes.A()
The subdivision in files is only there for convenience (allowing easier collaboration), but I'd prefer to have all the contents in the same namespace.
You could do this in __init__.py (because that's what you import when you import package):
from package.functions import *
from package.classes import *
However, import * is nearly always a bad idea and this isn't one of the exceptions. Instead, many packages explicitly import a limited set of commonly-used names - say,
from package.functions import do
from package.classes import A
This too allows accessing do or A directly, but it's not nearly as prone to name collisions and the other problems that come from import *.

Categories

Resources