Introduction to the five simple guidelines for building a python package

Source: Internet
Author: User
Tags define exception sprintf
It seems to be easy enough to create a package, which is to collect some modules in the file directory, plus a __init__.py file, right? It's easy to see that over time, with more and more modifications to the software package, a poorly designed package can have a cyclic dependency problem, or it may become non-portable and unreliable.
1. __init__.py only for import service

For a simple package, you may be tempted to throw tool methods, factory methods, and exception handling into __init__.py, and don't do that!

A well-structured __init__.py file serves only for a very important purpose: import from a submodule. Your __init__.py should look like this:

# order MATTERS Here--SOME MODULES is dependant on others# import order to consider--some modules will rely on additional from exceptions import Fsqerror, fsqenv Error, Fsqencodeerror,            fsqtimefmterror, Fsqmalformedentryerror,            fsqcoerceerror, Fsqenqueueerror, Fsqconfigerror,            fsqpatherror, Fsqinstallerror, Fsqcannotlockerror,            fsqworkitemerror, FSQTTLExpiredError,            Fsqmaxtrieserror, Fsqscanerror, Fsqdownerror,            Fsqdoneerror, Fsqfailerror, Fsqtriggerpullerror,            fsqhostserror, Fsqreenqueueerror, Fsqpusherror  # Constants  Relies On:exceptions, Internalimport constants # Const relies on:constants, exceptions, Internalfrom const Import const, Set_const # have tests # Path relies On:exceptions, constants, Internalimport path # has tests # lists relies On:pathfro M lists import hosts, queues # ...

2. Use __init__.py to restrict import order

    • Put the methods and classes in the scope of the package so that users do not need to drill down into the internal structure of the package to make your soft package easy to use.
    • As the only place to reconcile the import order.

If used properly, __init__.py can provide you with the flexibility to reorganize the internal package structure without worrying about the side effects of importing sub-modules internally or the order in which each module is imported. Because you are importing sub-modules in a specific order, your __init__.py should be easy to understand for his programmers and clearly represent all the features that the package can provide.

The document string, and the assignment of the __all__ property at the package level, should be the only code in __init__.py that is not relevant to the import module:

__all__ = [' Fsqerror ', ' fsqenverror ', ' fsqencodeerror ', ' fsqtimefmterror ',      ' fsqmalformedentryerror ', ' Fsqcoerceerror ', ' fsqenqueueerror ',      ' fsqconfigerror ', ' fsqcannotlock ', ' fsqworkitemerror ',      ' Fsqttlexpirederror ', ' fsqmaxtrieserror ', ' fsqscanerror ',      ' fsqdownerror ', ' fsqdoneerror ', ' fsqfailerror ', ' Fsqinstallerror ',      ' fsqtriggerpullerror ', ' fsqcannotlockerror ', ' fsqpatherror ',      ' path ', ' Constants ', ' Const ', ' set_const ', ' Down ', ' up ',      # ...     ]

3. Use a module to define all exceptions

You may have noticed that the first import statement in __init__.py imported all the exceptions from the exceptions.py submodule. From here, you will see that in most packages, exceptions are defined near the code that causes them. Although this can provide a high degree of integrity for a module, a sufficiently complex package can be problematic in the following two ways.

Usually a module/program needs to import a function from a submodule, use it to import the code and throw an exception. To catch exceptions and maintain a certain granularity, you need to import the modules you need, as well as the modules that define the exceptions (or worse, you want to import a series of exceptions). This series of derived import requirements is the originator of weaving an intricate network of imports into your package. The more times you use this method, the more interdependent and error-prone your packages become.
As the number of exceptions grows, it becomes increasingly difficult to find all the exceptions that a package can cause. Defining all exceptions in a single module provides a convenient place where programmers can review and determine what your package can do to trigger all potential error states.

You should define a base class for the exception of your package:

Class Apackageexception (Exception):  "root for Apackage Exceptions, only used to except any apackage error, never Rai Sed "  Pass

Then make sure that your package is in any error state and only throws the subclass exception of the base class exception, so that you can block all exceptions if you want to:

Try:  ' bunch of code from your package ' except apackageexception:  ' ' blanked condition to handle all errors from Your package "

For the general error state, there are some important exception handling already included in the standard library (for example, TypeError, ValueError, etc.)

Flexibility to define exception handling and maintain sufficient granularity:

# from Fsqclass fsqenverror (fsqerror):  "An error if something cannot is loaded from ENV, or Env have an invalid    V Alue '  Pass class Fsqencodeerror (fsqerror): ' An  error occured while encoding or decoding an argument '  pass# ... and or so more

Maintaining greater granularity in your exception handling allows programmers to include increasingly large, non-intrusive pieces of code in a try/except.

# thistry:  item = fsq.senqueue (' queue ', ' str ', ' arg ', ' arg ')  scanner = Fsq.scan (' queue ') except Fsqscanerror:  "Do something" except Fsqenqueueerror:  "do Something Else" "# Not Thistry:  item = Fsq.senqueue (' Queue ', ' str ', ' arg ', ' arg ') except Fsqenqueueerror:  ' do something Else ' try:  scanner = Fsq.scan (' queue ') Except Fsqscanerror:  ' do something ' # and definitely nottry:  item = fsq.senqueue (' queue ', ' str ', ' arg ', ' arg ')  Try:    scanner = Fsq.scan (' queue ')  except Fsqscanerror: ' Do    something ' ' except Fsqenqueueerror : ' Do  something Else '

Maintaining a high granularity in the definition of an exception reduces the complexity of error handling and allows you to separate normal execution instructions from error handling instructions, making your code more understandable and easier to maintain.
4. Only relative imports are made within the package

A simple mistake you see often in submodules is to use the name of the package to import the package.

# within a sub-modulefrom a_package import apackageerror

Doing so can result in two bad results:

    1. Sub-modules will only run correctly if the package is installed in PYTHONPATH.
    2. Sub-modules run correctly only if the name of the package is a_package.

Although the first one doesn't seem like a big problem, consider that if you have two directories under PYTHONPATH, there are two packages with the same name. Your submodule may eventually import another package, and you will inadvertently debug one or some of the unsuspecting programmers (or yourself) into the night.

# within a sub-module from. Import Fsqenqueueerror, Fsqcoerceerror, Fsqerror, Fsqreenqueueerror,       constants as _c, path as Fsq_path, construct,< C2/>hosts as fsq_hosts, fsqworkitemfrom internal import rationalize_file, Wrap_io_os_err, Fmt_time, Coerce_           Unicode, uid_gid# you can also use. /... etc. in Sub-packages.

5. Keep the module small in size

Your module should be relatively small. Remember that the programmer who uses your package will import it at the package scope, and you will use your __init__.py file as an organizational tool to expose a complete interface.

A good practice is that a module defines only one class, along with a number of help methods and factory methods to assist in building this module.

Class Apackageclass (object):  ' one class ' Def apackage_builder (how_many): For  I in range (How_many):    Yield Apackageclass ()

If your module exposes methods, divide some interdependent methods into a single module and move the non-dependent method into a separate module:

####### exposed METHODS ###### #def enqueue (Trg_queue, Item_f, *args, **kwargs): "Enqueue the contents of a file, or fil E-like object, File-descriptor or the contents of a file at an address (e.g. '/my/file ') queue with arbitrary argume NTS, Enqueue is to venqueue what printf are to vprintf "return Venqueue (Trg_queue, Item_f, args, **kwargs) def Senqueu E (Trg_queue, item_s, *args, **kwargs): ' Enqueue a string, or String-like object to queue with arbitrary arguments, s  Enqueue is to enqueue what sprintf are to printf, senqueue are to vsenqueue what sprintf are to vsprintf. "Return Vsenqueue (Trg_queue, item_s, args, **kwargs) def venqueue (Trg_queue, Item_f, args, User=none, Group=none, mode =none): "Enqueue the contents of a file, or File-like object, File-descriptor or the contents of a file at an addres s (e.g. '/my/file ') queue with a argument list, Venqueue is to enqueue what vprintf are to printf if entropy is pass Ed in, failure on duplicates is raisedTo the caller, if entropy are not passed in, Venqueue would increment entropy until it can create the queue item. ' # setup Defaults trg_fd = name = None # ...

The above example is fsq/enqueue.py, which exposes a series of methods to provide different interfaces for the same function (like the L oad/loads in Simplejson). While this example is intuitive enough to keep your module small, it requires some judgment, but a good rule is:

When you have questions, go ahead and create a new sub-module.

  • Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.