I can not understand the system of imports. Why when I do:

import os.path 

is os.walk available to me in os , although I obviously don’t import os ? For some reason, with your package, such a trick does not roll. What makes this happen?

upd

I understand that import is importing into the module namespace. therefore defining the module 'myutils.py' c

 import requests 

in another module the following picture is obtained

 import myutils resp=myutils.requests.get('http://ya.ru') # работает resp2=requests.get('http://ya.ru') # NameError: name 'requests' is not defined 

Is there any feature in the import os mechanism in os.path? I understand that os.path is part of os, not 2 completely separate packages, but I want to understand exactly the mechanism.

3 answers 3

Import in Python combines two operations :

  1. find (load and initialize) module
  2. enter new names in the current environment (as assignment operation = )

At the search stage (item No. 1) —from the specification of the import structure :

This can be a submodule, eg foo.bar.baz . In this case, Python first tries to import foo , then foo.bar , and finally foo.bar.baz . ImportError is raised.

that is, import abc imports modules a , ab , abc and a more nested module cannot be imported successfully if the import is unsuccessful for any module above.

At the stage of naming (item number 2) :

If the module is not used for a module. The imported module must be accessed using its full name.

import abc in Python makes a name available in the current namespace (for example, in the global module namespace, which imports abc ) and assigns the attribute: ab and the attribute attribute: abc corresponding loaded modules (analog: a = sys.modules['a'] ; ab = sys.modules['a.b'] ; ..).

Although the question is with the podkha, because os not a Python package ( __path__ attribute is not set ) and os.path is a regular attribute (the same as os.walk ) with the difference that os.path is a module and os.py contains a hack : sys.modules['os.path'] = path (which allows the import os.path construction). import os itself already makes os.path available without import os.path .


To paraphrase a question using a more regular example:

Why when I do: import os.path import html.parser then os.walk html.escape is available to html.escape , which is in os html , although I obviously don’t import os html ?

import html.parser imports both html and (of course) html.parser modules, and since html/__init__.py (performed during the html import phase) defines the escape function, html.escape() also available as if we just executed import html .

For some reason, with your package, such a trick does not roll. What makes this happen?

If module.name doesn’t work after import module , it means that your module/__init__.py does not determine the name .

module.name : the module.name performance module.name not depend on __all__ . __all__ documents which names are public (formally names available from module import * ), so as not to add to each name that is not part of the interface, _ at the beginning (names like _name are excluded from the default from module import * ). But this does not prohibit an explicit call such as module._name (this should be avoided, but if you really want, then you can). Aside: do not use from module import * outside the REPL or outside the __init__.py file (an example of justified use: asyncio/__init__.py - asyncio provides a "flat" public interface (names are available directly as asyncio.name ), despite the fact that implementation is distributed across multiple nested modules).

  • I'm completely confused. According to your words, import os.path establishes os in the current namespace (according to the rule “makes the name 'a' available), and thus we see os, from where we reach path, which is part of os. But I tried the usual package and import ab does not make ac accessible (that is, as "a" is not installed in the namespace). Maybe because it is a package and there it looks for attributes in init .py. I went there to write __ all __ = ['c'] and that didn't help either. - vitidev
  • @vitidev is not “in my words,” but according to official documentation (see the explicit quotation in the answer — if you don’t understand, ask, I will translate literally) and the actual behavior of all known Python implementations. If something doesn’t work for you, then ask exactly this ( os.path is not a general rule (os is not a package) —a bad example). For clarity: if you have a package a and it has .b1 , .b2 , then import a.b1 not required to make a.b2 available. import a.b1 creates a in the current namespace (as if you executed import a so other attributes may be available besides a.b1) - jfs
  • I understand the quote, it's just that it is painfully foggy for a person who comes from other languages. It says about "the top-level module is inserted into the local namespace and becomes available through the name of the link," but it turned out that the code of this top module is executed (and even conditionally executed somewhere inside import a.b2 makes it available), and all works only for from..import * and during import a is not a descriptor of the available attributes. - vitidev
  • @vitidev I did not understand what you wrote (forget the word "link" especially if you did it in C ++, you learned Java — although the name in Python can be implemented in C in terms of a pointer, but the concept is much simpler), but I agree the quote is too dry (it is exact, which is good for reference documentation, but for the first acquaintance you can use a less formal language, so I didn’t literally translate, but just gave an example with abc). It looks like a problem that you need to forget some concepts that have no relation to Python (the situation is simpler if you have no problems with the usual assignment: a = mod ) ... - jfs
  • ... Update your question (or ask a new one if the problem is not related to the fact that import ab makes a name available) give a specific example of the expected behavior and what you get instead. - jfs

You can import mypackage.mymodule_XXX and use mypackage.mymodule_YYY only if you explicitly import mymodule_YYY in the __init__.py file of your package.

Suppose you have a package mypackage :

 `/mypackage/` __init__.py mymodule_XXX.py mymodule_YYY.py 

__init__.py:

 from . import mymodule_XXX from . import mymodule_YYY 

Then you can do what you want in your program:

 import mypackage.mymodule_XXX # здесь можно смело использовать mypackage.mymodule_YYY print(mypackage.mymodule_YYY) 

As for myutils . When importing a module, you simply enter the variable myutils in the namespace of your program, you do not enter the variable requests , so it is logical that it is not defined. The variable myutils , which is a module and has its own namespace, has a variable requests , so you can access it through myutils.requests .

  • The fact that by import mypackage.mymodule_XXX you recommend making implicitly accessible mypackage.mymodule_YYY is not a good idea. More expected options are when each module is separately imported (for example, import http.client , import http.server ) or when nested modules are implementation import http.server , and public functionality is available at the package level itself: import asyncio . It should be noted that http.server imports http.client inside should be considered as an implementation detail (if you use both modules in your code, then import both explicitly). - jfs
  • The fact that you see recommendations where they are not, in principle, is not normal. A more expected option is when the answer is first read, then analyzed, and only then, if necessary, commented. - Nikmoon
 print(len(globals()), globals().keys()) import os.path print(len(globals()), globals().keys()) 

when you import os.path, the os is actually imported, then apparently the path attribute is simply requested from os, the import is no longer happening

 8 dict_keys(['__name__', '__doc__', '__package__', '__cached__', '__spec__', '__builtins__', '__loader__', '__file__']) 9 dict_keys(['__name__', '__doc__', '__package__', '__cached__', '__spec__', 'os', '__builtins__', '__loader__', '__file__']) 

it will be correct from os import path

  • If I understand you correctly, then in addition to the package system described in the books (folder with init .py) + nested modules, there is another addressing system, when the module enters a different module in all (or without all , I can see inside os .py "import ntpath as path") and with such an import this module is executed (as if by itself being a replacement for init .py) - vitidev