python 3, can't understand import system - python-3.x

this is such a simple problem but I cant seem to find any direct explanation to this.
in module.py
def foo():
print("foo")
in main.py
import module
foo()
it will result in an error saying that foo is not defined? when i look for the answer online, I can't find anything surprisingly
I'm not planning to use things like
from x import y
just straight up the import system

When you import an external module, it generates a variable named module that contains all classes, functions and variables from the module. To acess 'foo' function you need to first acess the module:
module.foo()
To import 'foo' function you can import everything from the module, like this:
from module import *
Now you can simply do: foo()
You can also set a custom name to the module, like:
import module as M
And now you can run 'foo' like this:
M.foo()
PS: I'm not english native

The statement
import module
makes the name of module module available. So you can use module.foo().
If you want to call foo() without "qualifying" it:
from module import foo
or
from module import *
but that latter is bad idea because you are liable to import unexpected names, which may collide with other names you imported from other modules.

from model import foo
is the preferred way as in any kinds of
from model import *
you (and anyone ever working on that code) has no idea what has been imported. Could even lead to name conflicts.

Related

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

Make import module return a variable

I would like to make an imported module behave like an object, ie. an dictionary.
E.g.
import module
print(module['key'])
and in module.py
return {'key':'access'}
This is very easy for Class by inheriting from dict, but how do I do this on a module level?
In particular I want to dynamically built the dictionary in module and return it when module is imported.
I know that there are other solutions such as defining the dict as a var in the module workspace and accessing it via module.var, but I am interested if something like this is possible.
As you point out, you can do this with a class, but not with a module, as modules are not subscriptable.Now I'm not going to ask why you want to do this with an import, but it can be done.
What you do is create a class that does what you want, and then have the module replace itself with the class when imported. This is of course a 'bit of a hack' (tm). Here I'm using UserDict as it gives easy access to the dict via the class attr data, but you could do anything you like in this class:
# module.py
from collections import UserDict
import sys
import types
class ModuleDict(types.ModuleType, UserDict):
data = {'key': 'access}
sys.modules[__name__] = ModuleDict(__name__)
Then you can import the module and use it as desired:
# code.py
import module
print(module['key']
# access

questions about importing in python 3

i've seen plenty of importing questions but didn't find any that explained importing very "easily". there are are 3 types of importing that i know of, and none of them seem to do what i'm looking for or would like to do. eg. main.py has def a() def b() class c() and def d() and lets say i have a start.py file.
main:
def a():
print("1")
def b():
print("2")
class c():
def__init__(self,name = "Rick")
self.name = name
def d():
print("4")
so now im my start.py file i want to import everything from them. what is the best way? i have tried using import main and i run into issues after creating an instance of class c [ ricky = c() ]that ricky isn't defined or accessing ricky.name it will say module ricky has no attribute name. so that doesn't seem to work. what is this even used for if you aren't importing the entire main.py file?
then there is from main import a, b, c, d that seems to work just fine, but there really has to be another way than having to import every single function, definition, variable, and everything.
third there is from main import * i'm not sure how this one works, i have read some on it mainly stating there should be an __ all __ = everything i want imported. but where do i put this. at the very top of the page inside my main.py? but there still should be a better way?
is my import main just not working correctly? or do i have to list everything i want to import either in a from main import statement or in an __ all __ list?
does importing carry over to another py file? eg. 1.py 2.py 3.py if inside 2.py i import 3.py correctly and everything works. in 1.py can i just import 2.py and it will import 3.py into 1.py from the import statement inside of 2.py? or do i have to import 2.py and 3.py again into 1.py?
the 3 main imports:
import (pythonfile) aka "module" using this will import all classes and functions to be used. does not import other imports. to call something in the imported module eg. modlue: MAIN, function: FUNC ... to call: MAIN.FUNC()
from module import FUNC, CLASS, .... when using this import you don't need to call it with the module. it is almost as if it is right infront of you eg.
module: MAIN, function: FUNC ..... to call: FUNC()
from module import * a combination of the previous two imports. will import everything from the module to be accessed without calling with the module extention. this form imports other imports as well. so if you have two modules that need to talk to eachother. using this will cause an error since you will be trying to import a module into another module then back into it's self again. A imported into B, A and B imported back into A. it doesn't work. so watch when using. May cause other importing errors of trying to import multiple modules that share imports. eg. importing A and B into C if A and B share D (pending for testing)
from MAIN import * call function: FUNC()
hope this helps other people out who are having issues understanding exactly how importing works and calling your functions/classes and what not.

does an imported function from a module could access class from this module?

I am a new comer when it comes to package and module to python.
I am trying to cut my script in several separate compartiment. to improve readability and maintenance.
My problem is the following:
I have a module which define a class and a function inside this module which instantiate this class.
module blast.py
class Blast():
blabla
def foo():
blast = Blast()
# do some stuff
this module is inside a package with a _ _init__.py file
__all__ = ["blast"]
I have a main script In which i want to use that function.
I import the module with
from package import blast
But To use that function I have to use the name space of the module ( at least my IDE say me that: pycharm)
blast.foo()
So does it works? does the function will see the class inside it module?
And more generally Could I import some function of my package inside my namespace. I though it was done this way and answer I got from internet doesn't really help me.
Yes, the function blast.foo() would know and find the class Blast.
Whenever you import a module, in part or in its entirety, the entire module is loaded - the way you import it merely decides on what classes and functions are available in the current scope, and in what way.
For example, if you call this:
from package.blast import foo
only the function foo() would be available, but the entire package read and loaded. if you were to try instantiate the class Blast by itself in the same script, this would not work.
By the way, you can make importing functions more convenient, if you customize __init__.py. In your case, if you were to edit it like so:
>>>__init__.py
from blast.py import Blast, foo
you can import both function and class like so:
from package import Blast, foo
The reason why you __all__ parameter does not work, is because it requires another import statement - mainly this:
from package import *
Calling this with your current __init__.py should work as expected.
Perhaps this post by Mike Grouchy is able to clarify things a bit more.

Mutual imports; difference between import's standart, "from" and "as" syntax

Given this simple folder structure
/main.py
/project/a.py
/project/b.py
main.py is executed by the python interpreter and contains a single line, import project.a.
a and b are modules, they need to import each other. A way to achieve this would be
import project.[a|b]
When working with deeper nested folder structures you don't want to write the entire path everytime you use a module e.g.
import project.foo.bar
project.foo.bar.set_flag(project.foo.bar.SUPER)
Both from project import [a|b] and import project.[a|b] as [a|b] result in an import error (when used in both, a and b).
What is different between the standart import syntax and the from or as syntax? Why is only the standart syntax working for mutual imports?
And more importantly, is there a simple and clean way to import modules that allows mutual imports and assigning shorter names to them (ideally the modules basename e.g. bar in the case of project.foo.bar)?
When you do either import project.a or from project import a, the following happens:
The module object for project.a is placed into sys.modules. This is a dictionary that maps each module name to its module object, so you'll have sys.modules = {..., 'p.a': <module 'p.a' from '.../project/a.py'>, ...}.
The code for the module is executed.
The a attribute is added to project.
Now, here is the difference between import project.a and from project import a:
import project.a just looks for sys.modules['project.a']. If it exists, it binds the name project using sys.modules['project'].
from project import a looks for sys.modules['project'] and then checks if the project module has an a attribute.
You can think of from project import a as an equivalent to the following two lines:
import project.a # not problematic
a = project.a # causes an error
That why you are seeing an exception only when doing from project import a: sys.modules['project.a'] exists, but project does not yet have a a attribute.
The quickest solution would be to simply avoid circular imports. But if you can't, then the usual strategies are:
Import as late as possible. Suppose that your a.py looks like this:
from project import b
def something():
return b.something_else()
Rewrite it as follows:
def something():
from project import b
return b.something_else()
Of course, you would have to repeat imports in all your functions.
Use lazy imports. Lazy imports are not standard feature of Python, but you can find many implementations around. They work by using the "import as late as possible" principle, but they add some syntactic sugar to let you write fewer code.
Cheat, and use sys.modules, like this:
import sys
import project.a
a = sys.modules['project.a']
Very un-pythonic, but works.
Obviously, whatever solution you choose, you won't be able to access the attributes from a or b until the modules have been fully loaded.

Resources