You probably already understand that when importing a module, the interpreter creates a new namespace and executes the code of this module with the new namespace, both local and global namespace. When the code completes execution, the module name (or the name specified in any as clause) is bound to the module object just created in the import namespace.
__init__.py in the package performs the same function. A package that has a structure is written as a directory, which can also contain modules (regular .py files) and subdirectories (which must also contain the __init__.py file) for any sub_packages. When a package is imported, a new namespace is created and the __init__.py package is executed with this namespace as a local and global namespace. Therefore, in order to answer your problem, we can disable your file by omitting the top-level package, which will never be considered by the interpreter when test.py starts as a program. Then it will look like this:
test.py subpackage/ __init__.py hello_world.py
Now subpackage no longer a subpackage since we removed the containing package as non-essential. Focusing on why the name do_something undefined might help. test.py does not contain an import, and so it is not clear how you expect do_something get a value. You can get it to work using empty subpackage/__init__.py and then test.py can read
from subpackage.hello_world import do_something do_something()
Alternatively, you can use subpackage/__init__.py , which reads
from hello_world import do_something
which sets the do_something function inside the subpackage namespace when importing a package. Then use test.py , which imports the function from the package, for example:
from subpackage import do_something do_something()
The ultimate alternative with the same __init__.py is to use test.py , which simply imports the (sub) package and then uses the relative name to access the required function:
import subpackage subpackage.do_something()
to access it in your local namespace
With empty __init__.py this can also be achieved by reading test.py
import subpackage.hello_world subpackage.hello_world.do_something()
or even
from subpackage.hello_world import do_something do_something()
Ultimately, the best tool to help you understand is a clear understanding of how imports work and how its various forms have an impact on the imported namespace.