Skip to content Skip to sidebar Skip to footer

Calling A Function From Inside A Sub-package The Correct Way In Python

I have been trying to understand how to properly call a function from inside a subpackage in python. I wanted to be able to call the function the way I call, for example, function

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: dateis 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 osos.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 allowimport 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:

  1. Implicit relative imports are deprecated: write from . import pack1 instead of just import pack1 in sandbox/__init__.py, for instance.
  2. The from plane import plane (or from .plane import plane, following the above point) is problematic because it overwrites the reference to the module plane.py with a reference to the function. Instead:
    1. Define the user-visible entry points (like plane()) directly in their package's __init__.py, importing internal functions from private modules as needed, or
    2. Rename the module (to plane_module.py or so) to avoid the collision.
  3. 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.

  4. 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 (like plane).

    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"