Python 实用程序

在本节中,我们将介绍 Python 为解决常见问题的几个标准实用程序模块。

文件系统 - os、os.path、Shutil

*os* 和 *os.path* 模块包含许多用于与文件系统交互的函数。*shutil* 模块可以复制文件。

  • 操作系统模块文档
  • filenames = os.listdir(dir) -- 该目录路径(不包括 . 和 ..)。文件名只是目录中的名称,而不是其绝对路径。
  • os.path.join(dir, filename) - 给定上述列表中的文件名,使用此参数将 dir 和文件名放在一起以生成路径
  • os.path.abspath(path) - 如果已给定路径,则返回绝对形式,如 /home/nick/foo/bar.html
  • os.path.dirname(path)、os.path.basename(path) - 若给定 dir/foo/bar.html,返回 dirname“dir/foo”和基本名“bar.html”
  • os.path.exists(path) -- 如果存在,则返回 true
  • os.mkdir(dir_path) - 创建一个 dir,os.makedirs(dir_path) 制作此路径中所需的所有目录
  • closeil.copy(source-path, dest-path) - 复制文件(目标路径目录应存在)
## Example pulls filenames from a dir, prints their relative and absolute paths
def printdir(dir):
  filenames = os.listdir(dir)
  for filename in filenames:
    print(filename)  ## foo.txt
    print(os.path.join(dir, filename)) ## dir/foo.txt (relative to current dir)
    print(os.path.abspath(os.path.join(dir, filename))) ## /home/nick/dir/foo.txt

使用内置的 python help() 和 dir() 函数进行探索模块效果非常好。在解释器中,执行“import os”,然后使用这些命令查看模块中可用的内容:dir(os)、help(os.listdir)、dir(os.path)、help(os.path.dirname)。

运行外部进程 - 子进程

*子进程* 模块是运行外部命令并捕获其输出的一种简单方式。

  • 子进程模块文档
  • output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) - 运行命令,等待该命令退出并返回其输出文本。运行该命令时,其标准输出和标准错误会合并到一个输出文本中。如果失败,则会抛出 CalledProcessError。
  • 如果您想要更好地控制子进程的运行,请参阅 subprocess.popen 类
  • 此外,还有一个简单的 subprocess.call(cmd),它会运行命令、将输出转储到您的输出并返回其错误代码。如果您想要运行该命令,但不需要将其输出捕获到 Python 数据结构中,这种方法非常适用。
import subprocess

## Given a dir path, run an external 'ls -l' on it --
## shows how to call an external program
def listdir(dir):
  cmd = 'ls -l ' + dir
  print("Command to run:", cmd)   ## good to debug cmd before actually running it
  (status, output) = subprocess.getstatusoutput(cmd)
  if status:    ## Error case, print the command's output to stderr and exit
    sys.stderr.write(output)
    sys.exit(status)
  print(output)  ## Otherwise do something with the command's output

异常

异常表示运行时错误,会在特定行停止正常执行,并将控制权转交给错误处理代码。本部分介绍了异常的最基本用途。例如,运行时错误可能是程序中使用的变量没有值(ValueError ..,您可能多次看到过该值),或者由于文件不存在而导致文件打开操作错误 (IOError)。如需了解详情,请参阅异常教程并查看完整的异常列表

如果没有任何错误处理代码(就像我们到目前为止所做的那样),运行时异常只会让程序停止运行并显示错误消息。这是一个很好的默认行为,您已经见过很多次了。您可以在代码中添加“try/Alternative”结构来处理异常,如下所示:

  try:
    ## Either of these two lines could throw an IOError, say
    ## if the file does not exist or the read() encounters a low level error.
    f = open(filename, 'rb')
    data = f.read()
    f.close()
  except IOError:
    ## Control jumps directly to here if any of the above lines throws IOError.
    sys.stderr.write('problem reading:' + filename)
  ## In any case, the code then continues with the line after the try/except

try: 部分包含可能会抛出异常的代码。“exception:”部分包含发生异常时要运行的代码。如果没有异常,系统会跳过“exception:”部分(也就是说,该代码仅用于错误处理,而不是用于代码的“常规”情况)。您可以使用语法“Exclude IOError as e: ..”(e 指向异常对象)来获取指向异常对象本身的指针。

HTTP - urllib 和 urlparse

*urllib.request* 模块提供网址提取功能,使网址看起来像您可以从中读取的文件。*urlparse* 模块可以拆分并整合网址。

  • urllib.request 模块文档
  • ufile = urllib.request.urlopen(url) - 针对该网址返回类似对象的文件
  • text = ufile.read() -- 可以像文件一样读取(readlines() 等也可从该文件中读取)
  • info = ufile.info() - 该请求的元信息。info.gettype() 是 MIME 类型,例如“text/html”
  • baseurl = ufile.geturl() -- 获取请求的“基本”网址,由于重定向,该网址可能与原始网址不同
  • urllib.request.urlretrieve(url, filename) - 将网址数据下载到给定的文件路径
  • urllib.parse.urljoin(baseurl, url) - 如果给定的网址可能不完整,也可能不包含,以及其来源网页的基准网址,因此会返回完整网址。使用上面的 geturl() 提供基准网址。

所有异常均位于 urllib.error 中。

from urllib.request import urlopen

## Given a url, try to retrieve it. If it's text/html,
## print its base url and its text.
def wget(url):
  ufile = urlopen(url)  ## get file-like object for url
  info = ufile.info()   ## meta-info about the url content
  if info.get_content_type() == 'text/html':
    print('base url:' + ufile.geturl())
    text = ufile.read()  ## read all its text
    print(text)

上述代码可以正常运行,但如果网址由于某种原因而无法正常运行,则不会进行错误处理。以下是该函数的一个版本,其中添加了 try/exception 逻辑,用于在网址操作失败时输出错误消息。

如果 urlopen() 似乎挂起,则表示您的系统可能不允许直接访问某些 http 地址。您可以通过尝试使用 wgetcurl 提取同一网址来验证这一点。如果这些程序也失败,您将需要通过代理服务提取 HTTP 内容。本教程不介绍如何配置代理访问权限。

## Version that uses try/except to print an error message if the
## urlopen() fails.
def wget2(url):
  try:
    ufile = urlopen(url)
    if ufile.info().get_content_type() == 'text/html':
      print(ufile.read())
  except IOError:
    print('problem reading url:', url)

演习

如需练习文件系统和外部命令资料,请参阅复制特殊练习。如需练习 urllib 资料,请参阅记录拼图练习