Introduction to five simple principles for building a Python package

Source: Internet
Author: User
Tags define exception

Introduction to five simple principles for building a Python package

This article mainly introduces the five simple principles for building Python packages. As Github's open-source cooperation becomes increasingly popular today, building robust Python packages must be considered by developers, this article provides five suggestions. For more information, see

Creating a package seems simple enough, that is, collecting some modules in the file directory and adding a _ init _. py file, right? We can easily see that, over time, through more and more modifications to the software package, a poorly designed software package may have a circular dependency problem, or may become unportable and unreliable.

1. _ init _. py is only for the import Service

For a simple software package, you may not be able to throw the tool methods, factory methods, and exception handling methods into _ init _. py. Never do this!

A well-structured _ init _. py file serves only a very important purpose: to import data from sub-modules. Your _ init _. py should look like this:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26 # order matters here -- SOME MODULES ARE DEPENDANT ON OTHERS

# Import sequence considerations-some modules depend on others

From exceptions import FSQError, FSQEnvError, FSQEncodeError,

FSQTimeFmtError, FSQMalformedEntryError,

FSQCoerceError, FSQEnqueueError, FSQConfigError,

FSQPathError, FSQInstallError, FSQCannotLockError,

FSQWorkItemError, FSQTTLExpiredError,

FSQMaxTriesError, FSQScanError, FSQDownError,

FSQDoneError, FSQFailError, FSQTriggerPullError,

FSQHostsError, FSQReenqueueError, FSQPushError

# Constants relies on: exceptions, internal

Import constants

# Const relies on: constants, exceptions, internal

From const import const, set_const

# Has tests

# Path relies on: exceptions, constants, internal

Import path

# Has tests

# Lists relies on: path

From lists import hosts, queues

#...

2. Use _ init _. py to limit the import sequence.

Place methods and classes in the scope of a software package, so that you do not need to go deep into the internal structure of the software package, making your soft package easy to use.

It is the only place to reconcile the import order.

When used properly, __init _. py provides you with the flexibility to reorganize the internal package structure, without worrying about the side effects caused by the internal import of sub-modules or the import order of each module. Because you import sub-modules in a specific order, Your _ init __. py should be easy to understand for his programmers and can clearly express all the functions provided by the software package.

The document string and the value assigned to the _ all _ attribute at the software package layer should be the only code irrelevant to the import module in _ init _. py:

?

1

2

3

4

5

6

7

8

9

10 _ 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', 'drop', 'up ',

#...

]

3. Use a module to define all exceptions

You may have noticed that the first Import Statement in __init _. py imports all exceptions from the exceptions. py submodule. From here, you will see that in most software packages, exceptions are defined near the code that causes them. Although this can provide a high degree of integrity for a module, a software package that is complex enough may encounter problems in either of the following ways.

Generally, a module/program needs to import a function from a submodule, use it to import code and throw an exception. To capture exceptions and maintain a certain granularity, You need to import the required modules and define the exception modules (or worse, you need to import a series of exceptions ). The import requirements derived from this series are the beginning of a complicated network of imports in your software package. The more times you use this method, the more dependent your software package is, and the more error-prone it is.

As the number of exceptions increases, it is increasingly difficult to find all the exceptions that a software package may cause. Defining All exceptions in a single module provides a convenient place where programmers can review and determine all potential error states that your software package can cause.

You should define a base class for your software package exceptions:

?

1

2

3

4 class APackageException (Exception ):

'''Root for APackage Exceptions, only used to handle T any APackage error, never raised '''

Pass

Then make sure that your software package will only cause a subclass exception of this base class exception in any error state, so that if you need it, you can stop all exceptions:

?

1

2

3

4

5

6try:

'''Bunch of code from your package '''

Failed t APackageException:

'''Masked condition to handle all errors from your package '''

For general error states, some important exception handling methods have been included in the standard library (such as TypeError and ValueError)

Flexibly define Exception Handling and maintain sufficient granularity:

?

1

2

3

4

5

6

7

8

9

10

11

12

13 # from fsq

Class FSQEnvError (FSQError ):

'''An error if something cannot be loaded from env, or env has An invalid

Value '''

Pass

Class FSQEncodeError (FSQError ):

'''An error occured while encoding or decoding An argument '''

Pass

#... And 20 or so more

Maintaining a greater granularity in your exception handling helps programmers include increasingly large, non-interfering code segments in a try/try t.

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34 # this

Try:

Item = fsq. senqueue ('queue ', 'str', 'arg', 'arg ')

Queue = fsq. scan ('queue ')

Failed t FSQScanError:

'''Do something '''

Failed t FSQEnqueueError:

'''Do something else '''

# Not this

Try:

Item = fsq. senqueue ('queue ', 'str', 'arg', 'arg ')

Failed t FSQEnqueueError:

'''Do something else '''

Try:

Queue = fsq. scan ('queue ')

Failed t FSQScanError:

'''Do something '''

# And definitely not

Try:

Item = fsq. senqueue ('queue ', 'str', 'arg', 'arg ')

Try:

Queue = fsq. scan ('queue ')

Failed t FSQScanError:

'''Do something '''

Failed t FSQEnqueueError:

'''Do something else '''

Maintaining a high level of granularity in exception definition will reduce complicated error handling and allow you to separate normal execution and error handling commands, make your code easier to understand and maintain.

4. Only perform relative import within the package

A simple error that you often see in the sub-module is to use the package name to import the package.

?

1

2 # within a sub-module

From a_package import APackageError

This will lead to two bad results:

The sub-module can run correctly only when the software package is installed in PYTHONPATH.

The sub-module can run correctly only when the package name is a_package.

Although the first one does not seem to be a big problem, consider if you have two software packages with the same name in two directories under PYTHONPATH. Your sub-module may eventually Import another software package, and you will inadvertently debug one or some unguarded programmers (or yourself) late at night.

?

1

2

3

4

5

6

7 # within a sub-module

From. import FSQEnqueueError, FSQCoerceError, FSQError, FSQReenqueueError,

Constants as _ c, path as fsq_path, construct,

Hosts as fsq_hosts, FSQWorkItem

From. internal import rationalize_file, wrap_io_ OS _err, fmt_time,

Coerce_unicode, uid_gid

# You can also use.../... etc. in sub-packages.

5. Maintain a small scale for the module

Your module should be relatively small. Remember, the programmer using your software package will import data in the scope of the software package, and you will use your _ init __. as an organization tool to expose a complete interface.

A good practice is to define only one class for a module, along with some help methods and factory methods to help build this module.

?

1

2

3

4

5

6

7 class APackageClass (object ):

'''One class '''

Def apackage_builder (how_many ):

For I in range (how_range ):

Yield APackageClass ()

If your module exposes some methods, divide some interdependent methods into one group and put them into one module, and move the non-interdependent methods to a separate module:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43 ####### exposed methods #######

Def enqueue (trg_queue, item_f, * args, ** kwargs ):

'''Enqueue the contents of a file, or file-like object, file-descriptor or

The contents of a file at an address (e.g. '/my/file') queue

Arbitrary arguments, enqueue is to venqueue what printf is to vprintf

'''

Return venqueue (trg_queue, item_f, args, ** kwargs)

Def senqueue (trg_queue, item_s, * args, ** kwargs ):

'''Enqueue a string, or string-like object to queue with arbitrary

Arguments, senqueue is to enqueue what sprintf is to printf, senqueue

Is to vsenqueue what sprintf is 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 address (e.g. '/my/file') queue

An argument list, venqueue is to enqueue what vprintf is to printf

If entropy is passed in, failure on duplicates is raised to the caller,

If entropy is not passed in, venqueue will 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 l oad/loads in simplejson ). Although this example is intuitive and requires some judgment to keep your module small-scale, a good principle is:

If you have any questions, 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.