Calling A Function From Inside A Sub-package The Correct Way In Python
Solution 1:
What you did certainly works, although there are several worthwhile changes to make.
First, a note about importing from packages: importing a module is semantically distinct from accessing something in a module, even though from xml import sax
and from datetime import date
are syntactically equivalent. It's impossible to import only part of a module, so that
import datetime
datetime.date.today() # OK: date is a class
is guaranteed to work. However, it is possible to import a package but not the modules it contains. This is a good thing for efficiency, but it does mean that
import xml
xml.sax.parse(...) # AttributeError: 'module' object has no attribute 'sax'
is an error. Unfortunately, such errors often go uncaught because some other code has already imported sax
, making it available to any other code that imports xml
. (The word "from" in from xml import sax
is referring to the complete package on disk, not the module object xml
— on which it stores the new module as an attribute!)
As an aside, note that your example of os.path
is an abberation: writing
import os
os.path.isfile(...)
works, but only because os.path
is not actually a module but an alias for one of posixpath
, ntpath
, etc. (It then gets installed in sys.modules
to allow import os.path
as if it were a normal module.)
As such, for a package there is a set of public modules that the user must be aware of (because they must be imported by name to be available); the rest are internal modules that the package loads itself when necessary. If a package contains no public modules, it is irrelevant to the user that it is a package (for example, importlib
with its one public function is actually implemented as a package for forward compatibility with Python 3).
Now for the suggestions:
- Implicit relative imports are deprecated: write
from . import pack1
instead of justimport pack1
insandbox/__init__.py
, for instance. - The
from plane import plane
(orfrom .plane import plane
, following the above point) is problematic because it overwrites the reference to the moduleplane.py
with a reference to the function. Instead:- Define the user-visible entry points (like
plane()
) directly in their package's__init__.py
, importing internal functions from private modules as needed, or - Rename the module (to
plane_module.py
or so) to avoid the collision.
- Define the user-visible entry points (like
However, it's not generally a good idea to have a package automatically import its public modules anyway: it forces the client to pay for loading unused parts of the package, and it blurs the distinction between public modules and simple nested names. Instead, write client code like
import sandbox.pack1.fly print sandbox.pack1.fly.plane(3) # the same line you had
or
from sandbox.pack1 import fly print fly.plane(3)
if you want to avoid repeating
sandbox.pack1
.It is often suggested that
__init__.py
be entirely empty, and in Python 3.3 it became possible to define packages without any__init__.py
at all (which by necessity "makes it empty"). This policy does more than the "no automatic import" suggestion in that it precludes loading things from private modules (likeplane
).There are sometimes good reasons to have a non-empty
__init__.py
; for example, it allows reorganzing an existing module into a package without breaking its clients. I personally see no reason to especially restrict its contents; for further discussion see What is __init__.py for?.
Solution 2:
The init.py file makes a folder as a package so that you can import it to python prompt. If you just want to call the function "plane" from your file plane.py, add the absolute path of plane.py file to your PYTHONPATH and call the funtion as shown below.
>>> import sys
>>> sys.path.append("D:\\sandbox\\pack1\\fly")
>>> import plane
>>> print plane.__doc__
plane module
>>> print plane.plane(3)
7
If you want all the packages under "sandbox" folder to be used in your script just add the absolute path of "sandbox" folder to your PYTHONPATH and call the funtion as shown below.
>>> import sys
>>> sys.path.append("D:\\")
>>> from sandbox.pack1.fly import plane
>>> print plane.plane(3)
7
You can also import the "plane.py" module and call the function "plane" as shown below:
>>> import sys
>>> sys.path.append("D:\\")
>>> import sandbox.pack1.fly.plane
>>> print sandbox.pack1.fly.plane.plane(3)
7
Post a Comment for "Calling A Function From Inside A Sub-package The Correct Way In Python"