{"id":341,"date":"2021-04-01T19:59:23","date_gmt":"2021-04-01T19:59:23","guid":{"rendered":"https:\/\/andrejacobs.org\/?p=341"},"modified":"2022-04-11T20:22:59","modified_gmt":"2022-04-11T20:22:59","slug":"100-days-of-learning-day-24-wrapping-up-on-the-python-importing-process","status":"publish","type":"post","link":"https:\/\/andrejacobs.org\/100-days-challenge\/100-days-of-learning-day-24-wrapping-up-on-the-python-importing-process\/","title":{"rendered":"100 Days of Learning: Day 24 \u2013 Wrapping up on the Python importing process"},"content":{"rendered":"\n
Photo by Boitumelo Phetla<\/a> on Unsplash<\/a><\/p>\n\n\n\n Here is my Log book<\/a>.<\/p>\n Code for today<\/a>.<\/p>\n The Definitive Guide to Python import Statements<\/a> has a neat little bit of code that will show you all the modules that you can import. For my exploration I will wrap this into a function.<\/p>\n Edit example.py and add the following function<\/p>\n Note that with a relative import you can only go up the chain to the directory containing the script but not including that directory. You will get Let’s explore this. I have created a new package2.subpackage2.subzero.py.<\/p>\n So package2.subpackage2.subzero is able to use an absolute import to import the function say_hello from package1.hello. This is because the If you try to do a relative import by walking up the directory tree using …, then you will get the ImportError mentioned earlier.<\/p>\n Key points:<\/strong><\/p>\n The Definitive Guide to Python import Statements<\/a> has a very good example under "Case 2" of where you run different modules as scripts and thus RealPython.com<\/a> has a really good tutorial about the different ways of importing. Well worth the read. There is also this more advanced tutorial<\/a>.<\/p>\n How do check if a module has been imported or not? SO post<\/a><\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":" Photo by Boitumelo Phetla on Unsplash […]<\/p>\nA handy function<\/h2>\n
def all_available_modules(search_path = ['.']):\n import pkgutil\n all_modules = [x[1] for x in pkgutil.iter_modules(path=search_path)]\n print('All available modules:')\n print(all_modules)\n...\nif __name__ == '__main__':\n\t...\n\tall_available_modules()\n<\/code><\/pre>\n
# The file tree at the moment\nproject\n \u251c\u2500\u2500 example.py\n \u251c\u2500\u2500 module1.py\n \u251c\u2500\u2500 package1\n \u2502\u00a0\u00a0 \u251c\u2500\u2500 __init__.py\n \u2502\u00a0\u00a0 \u2514\u2500\u2500 hello.py\n \u2514\u2500\u2500 time.py\n\n# Run example.py\n$ python example.py\n...\nAll available modules:\n['example', 'module1', 'package1', 'time']\n\n# Modify the call to be this and then run it again:\nall_available_modules(None)\n\n...\nAll available modules:\n['example', 'module1', 'package1', 'time', '__future__', '_aix_support',\n '_bootlocale', '_bootsubprocess', '_collections_abc', '_compat_pickle',\n '_compression', '_markupbase', '_osx_support', '_py_abc', '_pydecimal',\n '_pyio', '_sitebuiltins', '_strptime', '_sysconfigdata__darwin_darwin',\n '_threading_local', '_weakrefset', 'abc', 'aifc', 'antigravity', 'argparse',\n 'ast', 'asynchat', 'asyncio', 'asyncore', 'base64', 'bdb', 'binhex',\n... # and the list goes on and on\n<\/code><\/pre>\n
What is the difference between absolute and relative imports?<\/h2>\n
\n
from .module\/package import abc<\/code> Where each
.<\/code> represents a directory up the chain.\nFor example "from ..abc import xyz" would look for a module named "abc" in the parent directory of the current module.<\/li>\n<\/ul>\n
ImportError: attempted relative import beyond top-level package<\/code> if you try.<\/p>\n
project\n \u251c\u2500\u2500 example.py\n \u251c\u2500\u2500 module1.py\n \u251c\u2500\u2500 package1\n \u2502\u00a0\u00a0 \u251c\u2500\u2500 __init__.py\n \u2502\u00a0\u00a0 \u2514\u2500\u2500 hello.py\n \u251c\u2500\u2500 package2\n \u2502\u00a0\u00a0 \u2514\u2500\u2500 subpackage2\n \u2502\u00a0\u00a0 \u2514\u2500\u2500 subzero.py\n \u2514\u2500\u2500 time.py\n<\/code><\/pre>\n
# hello.py (inside package1)\n# Added the following function\ndef say_hello(name):\n print(f'Hello {name}!')\n<\/code><\/pre>\n
# subzero.py\nimport sys\nprint(f'{__name__} sys.path: {sys.path}')\n\n# This will throw ImportError: attempted relative import beyond top-level package\n#from ...package1.hello import say_hello\n\nprint('subzero.py will import package1\/hello.py absolutely')\nfrom package1.hello import say_hello\n\nsay_hello('subzero')\n<\/code><\/pre>\n
$ python example.py\nsubzero.py will import package1\/hello.py absolutely\nHello subzero!\n<\/code><\/pre>\n
sys.path[0]<\/code> is set to the directory that contains the script being run, which in this case is project.<\/p>\n
\n
from abc import x, y, z<\/code> . It also makes it clear to other people where things came from.<\/li>\n<\/ul>\n
Wrapping up<\/h2>\n
sys.path<\/code> will change and you will run into issues. I have personally hit this issue a couple of times now and after my learning the past 3 days I now understand why this fails.<\/p>\n