关于python:翻译实用的Python编程0901Packages

233次阅读

共计 4619 个字符,预计需要花费 12 分钟才能阅读完成。

目录 | 上一节 (8.3 调试) | [下一节 (9.2 第三方包)]()

9.1 包

如果编写一个较大的程序,咱们并不真的想在顶层将其组织为一个个独立文件的大型汇合。本节对包(package)进行介绍。

模块

任何一个 Python 源文件称为一个模块(module)。

# foo.py
def grok(a):
    ...
def spam(b):
    ...

一条 import 语句加载并 执行 一个模块。

# program.py
import foo

a = foo.grok(2)
b = foo.spam('Hello')
...

包 vs 模块

对于较大的代码汇合,通常将模块组织到包中。

# From this
pcost.py
report.py
fileparse.py

# To this
porty/
    __init__.py
    pcost.py
    report.py
    fileparse.py

首先,抉择一个名字并用该名字创立顶级目录。如上述的 porty(显然,第一步最重要的是抉择名字)。

接着,增加 __init__.py 文件到该目录中。__init__.py 文件能够是一个空文件。

最初,把源文件放到该目录中。

应用包

包用作导入的命名空间。

这意味着当初有了多级导入。

import porty.report
port = porty.report.read_portfolio('port.csv')

导入语句还有其它变体:

from porty import report
port = report.read_portfolio('portfolio.csv')

from porty.report import read_portfolio
port = read_portfolio('portfolio.csv')

两个问题

这种办法存在两个次要的问题:

  • 同一包内不同文件之间的导入有效。
  • 包中的主脚本有效。

因而,基本上所有导入都是有效的,然而,除此之外,程序还是能够工作的。

问题:导入

当初,在导入的时候,同一包内的不同文件之间的导入必须蕴含包名。请记住这个构造:

porty/
    __init__.py
    pcost.py
    report.py
    fileparse.py

根据上述规定(同一包内的不同文件之间的导入必须蕴含包名)批改后的导入示例:

# report.py
from porty import fileparse

def read_portfolio(filename):
    return fileparse.parse_csv(...)

所有的导入都是相对的,而不是绝对的。

# report.py
import fileparse    # BREAKS. fileparse not found

...

绝对导入

除了应用包名间接导入,还能够应用应用 . 援用以后的包。

# report.py
from . import fileparse

def read_portfolio(filename):
    return fileparse.parse_csv(...)

语法:

from . import modname

应用上述语法使得重命名包变得容易。

问题:主脚本

将包内的子模块作为主脚本运行会导致程序中断:

bash $ python porty/pcost.py # BREAKS
...

起因:你正在运行单个脚本,而 Python 不晓得包的其余部分(sys.path 是谬误的)。

所有的导入都会中断。要想解决这个问题,须要以不同的形式运行程序,能够应用 -m 选项。

bash $ python -m porty.pcost # WORKS
...

__init__.py 文件

该文件的次要目标是将模块组织在一起。

例如:

# porty/__init__.py
from .pcost import portfolio_cost
from .report import portfolio_report

这使得导入的时候名字呈现在顶层。

from porty import portfolio_cost
portfolio_cost('portfolio.csv')

而不是应用多级导入:

from porty import pcost
pcost.portfolio_cost('portfolio.csv')

脚本的另一种解决方案

如前所述,须要应用 -m package.module 运行包内的脚本。

bash % python3 -m porty.pcost portfolio.csv

还有另一种抉择:编写一个新的顶级脚本。

#!/usr/bin/env python3
# pcost.py
import porty.pcost
import sys
porty.pcost.main(sys.argv)

脚本位于包里面。目录构造如下:

pcost.py       # top-level-script
porty/         # package directory
    __init__.py
    pcost.py
    ...

利用构造

代码组织和文件构造是应用程序可维护性的要害。

对于 Python 而言,没有“放之四海而皆准”的办法,然而一个实用于多种问题的构造就是这样:

porty-app/
  README.txt
  script.py         # SCRIPT
  porty/
    # LIBRARY CODE
    __init__.py
    pcost.py
    report.py
    fileparse.py

顶级 porty-app 目录是所有其余内容的容器——这些内容包含文档,顶级脚本,用例等。

同样,顶级脚本(如果有)须要搁置在代码包之外(包的上一层)。

#!/usr/bin/env python3
# porty-app/script.py
import sys
import porty

porty.report.main(sys.argv)

练习

此时,咱们有了一个蕴含多个程序的目录:

pcost.py          # computes portfolio cost
report.py         # Makes a report
ticker.py         # Produce a real-time stock ticker

同时,还有许多具备各种性能的反对模块:

stock.py          # Stock class
portfolio.py      # Portfolio class
fileparse.py      # CSV parsing
tableformat.py    # Formatted tables
follow.py         # Follow a log file
typedproperty.py  # Typed class properties

在本次练习中,咱们将整顿这些代码并将它们放入一个通用包中。

练习 9.1:创立一个简略的包

请创立一个名为 porty 的目录并将上述所有的 Python 文件放入其中。另外,在 porty 目录中创立一个空的 __init__.py 文件。最初,文件目录看起来像这样:

porty/
    __init__.py
    fileparse.py
    follow.py
    pcost.py
    portfolio.py
    report.py
    stock.py
    tableformat.py
    ticker.py
    typedproperty.py

请将 porty 目录中的 __pycache__ 目录移除。该目录蕴含了之前预编译的 Python 模块。咱们想从新开始。

尝试导入包中的几个模块:

>>> import porty.report
>>> import porty.pcost
>>> import porty.ticker

如果这些导入失败,请进入到适合的文件中解决模块导入问题,使其可能包含绝对导入。例如,import fileparse 语句能够像上面这样进行批改:

# report.py
from . import fileparse
...

如果有相似于 from fileparse import parse_csv 这样的语句,请像上面这样批改代码:

# report.py
from .fileparse import parse_csv
...

练习 9.2:创立利用目录

对利用而言,将所有代码放到“包”中通常是不够的。有时,反对文件,文档,脚本等文件须要放到 porty/ 目录之外。

请创立一个名为 porty-app 的新目录。而后将咱们在练习 9.1 中创立的 porty 目录挪动到 porty-app 目录中。接着,复制测试文件 Data/portfolio.csvData/prices.csvporty-app 目录。另外,在 porty-app 目录下创立一个 README.txt 文件,该文件蕴含一些无关本人的信息。当初,代码的组织构造像上面这样:

porty-app/
    portfolio.csv
    prices.csv
    README.txt
    porty/
        __init__.py
        fileparse.py
        follow.py
        pcost.py
        portfolio.py
        report.py
        stock.py
        tableformat.py
        ticker.py
        typedproperty.py

要运行代码,须要确保你当初正在顶级目录 porty-app/ 下。例如,从终端运行:

shell % cd porty-app
shell % python3
>>> import porty.report
>>>

尝试将之前的脚本作为主程序运行:

shell % cd porty-app
shell % python3 -m porty.report portfolio.csv prices.csv txt
      Name     Shares      Price     Change
---------- ---------- ---------- ----------
        AA        100       9.22     -22.98
       IBM         50     106.28      15.18
       CAT        150      35.46     -47.98
      MSFT        200      20.89     -30.34
        GE         95      13.48     -26.89
      MSFT         50      20.89     -44.21
       IBM        100     106.28      35.84

shell %

练习 9.3:顶级脚本

应用 python -m 命令通常有点怪异。可能须要编写一个顶级脚本来解决奇怪的包。请创立一个生成上述报告的脚本 print-report.py

#!/usr/bin/env python3
# print-report.py
import sys
from porty.report import main
main(sys.argv)

而后把脚本 print-report.py 放到顶级目录 porty-app/ 中。并确保能够在 porty-app/ 目录下运行它:

shell % cd porty-app
shell % python3 print-report.py portfolio.csv prices.csv txt
      Name     Shares      Price     Change
---------- ---------- ---------- ----------
        AA        100       9.22     -22.98
       IBM         50     106.28      15.18
       CAT        150      35.46     -47.98
      MSFT        200      20.89     -30.34
        GE         95      13.48     -26.89
      MSFT         50      20.89     -44.21
       IBM        100     106.28      35.84

shell %

最初,代码的组织构造应该上面这样:

porty-app/
    portfolio.csv
    prices.csv
    print-report.py
    README.txt
    porty/
        __init__.py
        fileparse.py
        follow.py
        pcost.py
        portfolio.py
        report.py
        stock.py
        tableformat.py
        ticker.py
        typedproperty.py

目录 | 上一节 (8.3 调试) | [下一节 (9.2 第三方包)]()

注:残缺翻译见 https://github.com/codists/practical-python-zh

正文完
 0