精通-Python-系统管理脚本编程-全-

精通 Python 系统管理脚本编程(全)

原文:zh.annas-archive.org/md5/c33d6613eafa4d86b92059a00f7aa16f

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

Python 已经发展并扩展了其功能,涵盖了几乎所有可能的 IT 操作。本书将帮助你利用 Python 的最新功能,编写有效的脚本,并创建用于管理环境的命令行工具(用于数据类型、循环、条件、函数、错误处理等)。本书将围绕整个开发过程展开,从设置和规划到自动化测试和构建不同的命令行工具。本书将使你从基本脚本编写到使用标准库包。最后,你将创建一个大型脚本项目,学习如何规划、实施和分发基于理想资源的项目。

本书适合对象

本书适合具有一定 Python 编程基础的用户,他们有兴趣将编程技能扩展到命令行脚本和系统管理。

需要有 Python 的先验知识。

本书涵盖内容

第一章,Python 脚本概述,涵盖了 Python 的安装程序以及 Python 解释器工具的使用。你将学习如何为变量赋值,并介绍变量和字符串。你将学习包括列表、元组、集合和字典在内的序列数据类型。此外,你还将学习如何在脚本中解析命令行选项。

第二章,调试和分析 Python 脚本,教你如何使用调试器工具调试 Python 程序。你还将学习如何处理错误,并探索分析和计时的概念。

第三章,单元测试-单元测试框架介绍,是关于 Python 中的单元测试。我们将创建单元测试来测试程序。

第四章,自动化常规管理活动,将教你如何自动化系统管理员的常规管理活动。你将学习如何接受输入,处理密码,执行外部命令,读取配置文件,向脚本添加警告代码,实现 CPU 限制,启动 Web 浏览器,使用os模块以及备份。

第五章,处理文件、目录和数据,将教你如何使用 os 模块进行各种活动。你将学习有关数据以及应用于该数据的一些方法,如复制、移动、合并和比较。你还将学习tarfile模块以及如何使用它。

第六章,文件归档、加密和解密,深入研究文件归档、创建存档以及 TAR 和 ZIP 创建。你还将学习如何使用应用程序解压.tar.zip文件。

第七章,文本处理和正则表达式,讨论了 Python 中的文本处理和正则表达式。Python 有一个非常强大的库,叫做正则表达式,可以执行搜索和提取数据等任务。你将学习如何在文件中使用正则表达式。你还将学习如何读取和写入文件。

第八章,文档和报告,将教你如何使用 Python 记录和报告信息。你还将学习如何使用 Python 脚本输入和打印输出。使用 Python,你可以编写用于自动信息收集的脚本。在 Python 中更容易编写用于接收电子邮件的脚本。你将学习如何格式化信息。

第九章,处理各种文件,将涉及处理各种文件,如 PDF 文件、Excel 文件和 CSV 文件的问题。您将学习如何使用 Python 打开、编辑和获取这些文件中的数据。

第十章,基本网络-套接字编程,首先介绍了网络的基础知识;然后您将了解 TCP、UDP 等套接字。您还将学习如何编写套接字以进行通信,并获取 HTTP 和 FTP 等协议的信息。

第十一章,使用 Python 脚本处理电子邮件,探讨了如何使用 Python 脚本撰写和发送电子邮件。发送电子邮件是任何软件程序中非常常见的任务。我们可以使用 Python 的smtplib模块在 Python 程序中发送电子邮件。在本章中,您还将了解在不同服务器上发送电子邮件所使用的不同协议。

第十二章,通过 Telnet 和 SSH 远程监控主机,向您展示如何在使用 SSH 协议的服务器上进行基本配置。我们将首先使用 Telnet 模块,然后使用首选方法 SSH 实现相同的配置。

第十三章,构建图形用户界面,介绍了使用 PyQt 模块创建图形用户界面。

第十四章,使用 Apache 和其他日志文件,解释了如何处理 Apache 日志文件。您还将了解日志解析应用程序;即,识别特定类型的日志消息。您还将学习如何解析这些文件,以及如何处理多个文件;检测任何异常,存储数据并生成报告。

第十五章,SOAP 和 REST API 通信,涉及 SOAP 和 REST 的基础知识,以及它们之间的区别。您还将了解 SOAP API 以及如何使用不同的库来使用它。我们还将学习 REST API 和标准库。

第十六章,Web 抓取-从网站提取有用数据,将教您如何使用 Python 库从网站提取数据。您还将学习如何使用 Python 搜索文章和源代码。

第十七章,统计数据收集和报告,介绍了在科学计算中使用的高级 Python 库。这些库包括 NumPy、SciPy 和 Matplotlib。您将学习数据可视化的概念,并学习如何绘制数据。

第十八章,MySQL 和 SQLite 数据库管理,介绍了使用 MySQL 和 SQLite 数据库进行数据库管理。您将了解此类管理的要求和设计,如何修改插件框架,以及如何编写生产者和消费者代码。

充分利用本书

我们编写本书的目的是尽可能使其易于访问,并通过多个脚本教授您使用 Python 进行编程的许多不同方法。但是,为了充分利用它们,您需要执行以下操作:

  • 设置和配置 Linux 系统以进行测试/调试脚本

  • 理解创建的脚本

  • 记住每个脚本的组件是什么

  • 检查组件如何可以被重用或以新的方式组合

本书假定您在开始学习之前具有一定水平的 Python 知识;这些基本技能在本书中不会涵盖。这些技能包括以下内容:

  • 如何设置和配置 Linux 系统

  • 如何安装、访问和配置特定的 Python IDE(尽管有几种

大多数 Linux 发行版中已经包含)

  • 一些关于计算和编程的基础知识(尽管我们会尽力)

提供一个快速课程)

下载示例代码文件

您可以从您在www.packt.com的帐户中下载本书的示例代码文件。如果您在其他地方购买了这本书,您可以访问www.packt.com/support并注册,以便文件直接发送到您的邮箱。

您可以按照以下步骤下载代码文件:

  1. 登录或注册www.packt.com

  2. 选择“支持”选项卡。

  3. 单击“代码下载和勘误”。

  4. 在搜索框中输入书名,并按照屏幕上的说明进行操作。

下载文件后,请确保使用最新版本的解压缩或提取文件夹:

  • Windows 使用 WinRAR/7-Zip

  • Mac 使用 Zipeg/iZip/UnRarX

  • Linux 使用 7-Zip/PeaZip

该书的代码包也托管在 GitHub 上github.com/PacktPublishing/Mastering-Python-Scripting-for-System-Administrators-/。如果代码有更新,将在现有的 GitHub 存储库上进行更新。

我们还有来自我们丰富的图书和视频目录的其他代码包,可在github.com/PacktPublishing/上找到。去看看吧!

使用的约定

本书中使用了许多文本约定。

CodeInText:表示文本中的代码词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 句柄。这里有一个例子:“要解压缩存档,shutil模块有unpack_archive()函数。”

代码块设置如下:

 >>> 3 * 'hi' + 'hello'
'hihihihello' 

任何命令行输入或输出都以以下形式书写:

 sudo apt install python3-pip

粗体:表示新术语、重要单词或屏幕上看到的单词。这里有一个例子:“CSV格式,代表逗号分隔值格式。”

警告或重要提示会出现在这样的形式中。提示和技巧会出现在这样的形式中。

第一章:Python 脚本概述

Python 是一种脚本语言,由 Guido van Rossum 于 1991 年创建,用于各种应用,如游戏开发,GIS 编程,软件开发,Web 开发,数据分析,机器学习和系统脚本。

Python 是一种面向对象的高级编程语言,具有动态语义。主要是 Python 是一种解释性语言。Python 用于快速应用程序开发,因为它具有所有的高级开发功能。

Python 简单易学,因为其语法使程序更易读。因此,程序的维护成本较低。

Python 还有一个重要的特性,即导入模块和包。这个特性允许代码重用。Python 解释器易于理解。我们可以在其中逐行编写完整的代码,并且由于 Python 是一种解释性语言,代码会逐行执行。Python 还有广泛的库,用于高级功能。

本章将涵盖以下主题:

  • Python 脚本

  • 安装和使用 Python 以及各种工具

  • 变量,数字和字符串

  • Python 支持的数据结构以及如何在脚本中使用所有这些概念

  • 决策制定;也就是if语句

  • 循环语句;也就是forwhile循环

  • 函数

  • 模块

技术要求

在阅读本书之前,您应该了解 Python 编程的基础知识,比如基本语法,变量类型,元组数据类型,列表字典,函数,字符串和方法。在python.org/downloads/上有两个版本,3.7.2 和 2.7.15。在本书中,我们将使用版本 3.7 进行代码示例和包安装。

本章的示例和源代码可在 GitHub 存储库中找到:github.com/PacktPublishing/Mastering-Python-Scripting-for-System-Administrators-

为什么选择 Python?

Python 有广泛的库,用于开源数据分析工具,Web 框架,测试等。Python 是一种可以在不同平台(Windows,Mac,Linux 和嵌入式 Linux 硬件平台,如树莓派)上使用的编程语言。它用于开发桌面应用程序和 Web 应用程序。

如果使用 Python,开发人员可以用更少的行数编写程序。原型设计非常快速,因为 Python 运行在解释器系统上。Python 可以以面向对象,过程式或函数式的方式处理。

Python 可以执行各种任务,比如创建 Web 应用程序。它与软件一起用于创建工作流程;连接到数据库系统,处理文件,处理大数据,并执行复杂的数学运算。

Python 语法与其他编程语言的比较

Python 中编写的代码非常易读,因为它类似于英语。Python 使用新行来完成命令。

Python 有一个很棒的特性:缩进。使用缩进,我们可以定义决策语句,循环(如forwhile循环),函数和类的范围。

Python 安装

在这一部分,我们将学习 Python 在不同平台上的安装,比如 Linux 和 Windows。

在 Linux 平台上安装

大多数 Linux 发行版在默认安装中都有 Python 2。其中一些还包括 Python 3。

要在基于 Debian 的 Linux 上安装python3,请在终端中运行以下命令:

sudo apt install python3

要在centos上安装python3,请在终端中运行以下命令:

sudo yum install python3

如果无法使用上述命令安装 Python,请从www.python.org/downloads/下载 Python 并按照说明进行操作。

在 Windows 平台上安装

要在 Microsoft Windows 中安装 Python,您需要从python.org下载可执行文件并安装。从www.python.org/downloads/下载python.exe,选择要在您的 PC 上安装的 Python 版本。然后,双击下载的exe并安装 Python。在安装向导中,有一个复选框,上面写着将 Python 添加到路径。选中此复选框,然后按照说明安装python3

使用 pip 安装软件包的安装和使用

在 Linux 中,安装pip如下:

sudo apt install python-pip --- This will install pip for python 2.
sudo apt install python3-pip --- This will install pip for python 3.

在 Windows 中,安装pip如下:

python -m pip install pip

在 Mac 上安装

要安装python3,首先必须在系统上安装brew。要在系统上安装brew,运行以下命令:

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

通过运行上述命令,brew将被安装。现在我们将使用brew安装python3

brew install python3

安装 Jupyter 笔记本

要安装 Jupyter 笔记本,请下载 Anaconda。

安装已下载的 Anaconda 并按照向导上的说明操作。

使用pip安装 Jupyter:

pip install jupyter

在 Linux 中,pip install jupyter将为python 2安装 Jupyter。如果要为python 3安装jupyter,请运行以下命令:

pip3 install jupyter

安装和使用虚拟环境

现在我们将看看如何安装虚拟环境以及如何激活它。

要在 Linux 上安装虚拟环境,请执行以下步骤:

  1. 首先检查pip是否已安装。我们将为python3安装pip
sudo apt install python3-pip
  1. 使用pip3安装虚拟环境:
sudo pip3 install virtualenv
  1. 现在我们将创建虚拟环境。您可以给它任何名称;我称其为pythonenv
virtualenv pythonenv
  1. 激活您的虚拟环境:
source venv/bin/activate
  1. 工作完成后,您可以使用以下命令停用virtualenv
deactivate

在 Windows 中,运行pip install virtualenv命令安装虚拟环境。安装virtualenv的步骤与 Linux 相同。

安装 Geany 和 PyCharm

www.geany.org/download/releases下载 Geany,并下载所需的二进制文件。在安装时按照说明操作。

www.jetbrains.com/pycharm/download/#section=windows下载 PyCharm 并按照说明操作。

Python 解释器

Python 是一种解释性语言。它有一个名为 Python 解释器或 Python shell 的交互式控制台。这个控制台提供了一种逐行执行程序而不创建脚本的方法。

您可以在 Python 交互式控制台中访问所有的内置函数和库、安装的模块和命令历史。这个控制台让您有机会探索 Python。当您准备好时,可以将代码粘贴到脚本中。

Python 和 Bash 脚本之间的区别

在本节中,我们将学习 Python 和 Bash 脚本之间的区别。区别如下:

  • Python 是一种脚本语言,而 Bash 是用于输入和执行命令的 Shell

  • 使用 Python 更容易处理更大的程序

  • 在 Python 中,您可以通过调用导入模块的一行函数来完成大多数事情

启动交互式控制台

我们可以从已安装 Python 的任何计算机上访问 Python 的交互式控制台。运行以下命令启动 Python 的交互式控制台:

$ python

这将启动默认的 Python 交互式控制台。

在 Linux 中,如果我们在终端中输入Python,则会启动python2.7控制台。如果要启动python3控制台,则在终端中输入python3并按Enter

在 Windows 中,当您在命令提示符中输入Python时,它将启动已下载 Python 版本的控制台。

使用 Python 交互式控制台编写脚本

Python 交互式控制台从>>>前缀开始。这个控制台将接受您在>>>前缀后面写的 Python 命令。参考以下截图:

现在,我们将看如何给变量赋值,就像下面的例子:

>>> name = John

在这里,我们给name变量赋了一个字符值John。我们按下Enter键,得到了一个带有>>>前缀的新行:

>>> name = John

现在,我们将看一个给变量赋值的例子,然后我们将执行一个数学运算来得到这些值:

>>> num1 = 5000
>>> num2 = 3500
>>> num3 = num1 + num2
>>> print (num3)
8500
>>> num4 = num3 - 2575
>>> print (num4)
5925
>>>

在这里,我们给变量赋值,添加了两个变量,将结果存储在第三个变量中,并将结果打印到终端上。接下来,我们从结果变量中减去一个变量,输出将存储在第四个变量中。然后,我们将结果打印到终端上。这告诉我们,我们也可以将 Python 解释器用作计算器:

>>> 509 / 22
23.136363636363637
>>>

在这里,我们进行了除法运算。我们将509除以22,得到的结果是23.136363636363637

多行

当我们在 Python 解释器中编写多行代码(例如if语句和forwhile循环函数),解释器会使用三个点(...)作为第二个提示符进行行继续。要退出这些行,你必须按两次Enter键。现在我们来看下面的例子:

>>> val1 = 2500
>>> val2 = 2400
>>> if val1 > val2:
... print("val1 is greater than val2")
... else:
... print("val2 is greater than val1")
...
val1 is greater than val2
>>>

在这个例子中,我们给两个变量val1val2赋了整数值,并且检查val1是否大于val2。在这种情况下,val1大于val2,所以if块中的语句被打印出来。记住,ifelse块中的语句是缩进的。如果你不使用缩进,你会得到以下错误:

>>> if val1 > val2:
... print("val1 is greater than val2")
File "<stdin>", line 2
print("val1 is greater than val2")
^
IndentationError: expected an indented block
>>>

通过 Python 解释器导入模块

如果你导入任何模块,那么 Python 解释器会检查该模块是否可用。你可以使用import语句来做到这一点。如果该模块可用,那么在按下Enter键后你会看到>>>前缀。这表示执行成功。如果该模块不存在,Python 解释器会显示一个错误:

>>> import time
>>>

导入time模块后,我们得到>>>前缀。这意味着模块存在,并且这个命令被成功执行了:

>>> import matplotlib

如果模块不存在,你将得到Traceback错误:

File "<stdin>", line 1, in <module>
ImportError: No module named 'matplotlib'

所以在这里,matplotlib不可用,所以会出现错误:ImportError: No module named 'matplotlib'

要解决这个错误,我们需要安装matplotlib,然后再尝试导入matplotlib。安装matplotlib后,你应该能够导入模块,如下所示:

>>> import matplotlib
>>>

退出 Python 控制台

我们可以通过两种方式退出 Python 控制台:

  • 键盘快捷键:Ctrl + D

  • 使用quit()exit()函数

键盘快捷键

键盘快捷键,Ctrl + D,将给出以下代码:

>>> val1 = 5000
>>> val2 = 2500
>>>
>>> val3 = val1 - val2
>>> print (val3)
2500
>>>
student@ubuntu:~$

使用quit()exit()函数

quit()会让你退出 Python 的交互式控制台。它还会把你带回到之前所在的原始终端:

>>> Lion = 'Simba'
>>> quit()
student@ubuntu$

缩进和制表符

在 Python 中编写代码块时,缩进是必须的。当你编写函数、决策语句、循环语句和类时,缩进是有用的。这样可以方便阅读你的 Python 程序。

我们在 Python 程序中使用缩进来表示代码块。要缩进一个代码块,你可以使用空格或制表符。参考以下例子:

if val1 > val2:
 print ("val1 is greater than val2")
print("This part is not indented")

在上面的例子中,我们缩进了print语句,因为它属于if块。下一个打印语句不属于if块,所以我们没有对它进行缩进。

变量

和其他编程语言一样,不需要先声明变量。在 Python 中,只需想一个名字给你的变量并给它赋一个值。你可以在程序中使用该变量。所以在 Python 中,你可以在需要时声明变量。

在 Python 中,变量的值和类型在程序执行过程中可能会发生变化。在下面的代码行中,我们将值100赋给一个变量:

n = 100
Here are assigning 100 to the variable n. Now, we are going to increase the value of n by 1:
>>> n = n + 1
>>> print(n)
101
>>>

以下是一个在执行过程中可以改变的变量类型的例子:

a = 50 # data type is implicitly set to integer
a = 50 + 9.50 # data type is changed to float
a = "Seventy" # and now it will be a string

Python 会处理不同数据类型的表示;也就是说,每种类型的值都存储在不同的内存位置。变量将是一个我们将要为其分配值的名称:

>>> msg = 'And now for something completely different'
>>> a = 20
>>> pi = 3.1415926535897932

这个例子做了三个赋值。第一个赋值是将字符串赋给名为msg的变量。第二个赋值是将整数赋给名为a的变量,最后一个赋值是pi值的赋值。

变量的类型是它所引用的值的类型。看看下面的代码:

>>> type(msg)
<type 'str'>
>>> type(a)
<type 'int'>
>>> type(pi)
<type 'float'>

创建并为变量赋值

在 Python 中,变量不需要显式声明以保留内存空间。因此,只要将值赋给变量,声明就会自动完成。在 Python 中,等号=用于为变量赋值。

考虑以下例子:

#!/usr/bin/python3
name = 'John'
age = 25
address = 'USA'
percentage = 85.5
print(name)
print(age)
print(address)
print(percentage)

Output:
John
25
USA
85.5

在上面的例子中,我们将John赋给name变量,将25赋给age变量,将USA赋给address变量,将85.5赋给percentage变量。

我们不必像其他语言那样首先声明它们。因此,查看值时,解释器将获取该变量的类型。在上面的例子中,nameaddress字符串,age 是整数,percentage 是浮点类型。

可以如下进行相同值的多重赋值:

x = y = z = 1

在上面的例子中,我们创建了三个变量,并将整数值1分配给它们,所有这三个变量都将分配到相同的内存位置。

在 Python 中,我们可以在一行中为多个变量分配多个值:

x, y, z = 10, 'John', 80

在这里,我们声明了一个字符串变量y,并将值John赋给它,还声明了两个整数变量xz,并分别将值1080赋给它们。

数字

Python 解释器也可以充当计算器。您只需输入一个表达式,它就会返回值。括号( )用于进行分组,如下例所示:

>>> 5 + 5
10
>>> 100 - 5*5
75
>>> (100 - 5*5) / 15
5.0
>>> 8 / 5
1.6

整数是int类型的,小数部分是float类型的。

在 Python 中,除法(/)操作始终返回一个浮点值。floor除法(//)得到一个整数结果。%运算符用于计算余数。

考虑以下例子:

>>> 14/3
4.666666666666667
>>>
>>> 14//3
4
>>>
>>> 14%3
2
>>> 4*3+2
14
>>>

要计算幂,Python 有**运算符,如下例所示:

>>> 8**3
512
>>> 5**7
78125
>>>

等号(=)用于为变量赋值:

>>> m = 50
>>> n = 8 * 8
>>> m * n
3200

如果一个变量没有任何值,但我们仍然尝试使用它,那么解释器将显示错误:

>>> k
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'k' is not defined
>>>

如果运算符具有混合类型的操作数,则得到的值将是浮点数:

>>> 5 * 4.75 - 1
22.75

在 Python 交互式控制台中,_包含了最后一个打印的表达式值,如下例所示:

>>> a = 18.5/100
>>> b = 150.50
>>> a * b
27.8425
>>> b + _
178.3425
>>> round(_, 2)
178.34
>>>

数字数据类型存储不可变的数值。如果我们这样做,Python 将为更改后的数据类型分配一个新对象。

我们可以通过为它们分配一个值来创建数字对象,如下例所示:

num1 = 50
num2 = 25

del语句用于删除单个或多个变量。参考以下例子:

del num
del num_a, num_b

数字类型转换

在某些情况下,您需要显式地将一个类型的数字转换为另一个类型以满足某些要求。Python 在表达式中内部执行此操作

  • 输入int(a)a转换为整数

  • 输入float(a)a转换为浮点数

  • 输入complex(a)a转换为具有实部x和虚部的复数

  • 使用complex(a, b)ab转换为具有实部a和虚部b的复数。ab是数值表达式

字符串

与数字一样,字符串也是 Python 中的数据结构之一。Python 可以操作字符串。字符串可以表示如下:

  • 用单引号('...')括起来

  • 用双引号("...")括起来

看下面的例子:

>>> 'Hello Python'
'Hello Python'
>>> "Hello Python"
'Hello Python'

字符串是一组字符。我们可以按顺序访问字符,如下所示:

>>> city = 'delhi'
>>> letter = city[1]
>>> letter = city[-3]

在第二个语句中,我们从city中选择字符编号1并将其分配给letter。方括号中的数字是索引。索引表示您要访问的字符。它从0开始。因此,在上面的例子中,当您执行letter = city[1]时,您将得到以下输出:

city d e l h i
index 0 1 2 3 4
-5 -4 -3 -2 -1

Output:
e
l

连接(+)和重复(*)

接下来是连接和重复。参考以下代码:

>>> 3 * 'hi' + 'hello'
'hihihihello'

在上面的例子中,我们正在进行字符串连接和重复。3 * 'hi'意味着hi被打印3次,并且使用+号,我们将hello字符串连接到hi旁边。

我们可以通过将它们写在一起来自动连接两个字符串。这两个字符串必须用引号括起来,如下所示:

>>> 'he' 'llo'
'hello'

当您有很长的字符串并且想要打破它们时,这个功能真的很有帮助。这里有一个例子:

>>> str = ('Several strings'
... 'joining them together.')
>>> str
'Several strings joining them together.'

字符串切片

字符串支持切片,这意味着从字符串中按指定范围获取字符。让我们看看以下例子。请注意,起始索引值始终包括在内,结束值始终不包括在内。

考虑一个字符串,str = "Programming":

>>> str[0:2]
'Pr'
>>> str[2:5]
'ogr'

现在,省略的第一个索引的默认值是零,就像例子中一样:

>>> str[:2] + str[2:]
'Python'
>>> str[:4] + str[4:]
'Python' >>> str[:2]
'Py'
>>> str[4:]
'on'
>>> str[-2:]
'on'

在字符串中访问值

我们可以使用方括号切片从字符串中访问字符。我们还可以在指定范围内从字符串中访问字符。参考以下示例:

#!/usr/bin/python3
str1 = 'Hello Python!'
str2 = "Object Oriented Programming"
print ("str1[0]: ", str1[0])
print ("str2[1:5]: ", str2[1:5])

Output:
str1[0]: H
str2[1:5]: bjec

更新字符串

我们可以通过将新值重新分配给指定的索引来更新字符串。参考以下示例:

#!/usr/bin/python3
str1 = 'Hello Python!'
print ("Updated String: - ", str1 [:6] + 'John')

Output:
Updated String: - Hello John

转义字符

Python 支持转义字符,这些字符是不可打印的,可以用反斜杠表示。转义字符在单引号和双引号字符串中都会被解释:

符号 十六进制字符 描述
a 0x07 响铃或警报
b 0x08 退格
cx 控制-x
n 0x0a 换行符
C-x 控制-x
e 0x1b 转义
f 0x0c 换页符
s 0x20 空格
M-C-x 元控制-x
x 字符x
nnn 八进制表示法,其中n在范围 0.7 内
r 0x0d 回车
xnn 十六进制表示法,其中n在范围0.9a.fA.F
t 0x09 制表符
v 0x0b 垂直制表符

特殊字符串运算符

以下表格显示了字符串的特殊运算符。考虑aHellobWorld

运算符 描述 例子
+ 连接:在运算符的两侧添加值 a + b会得到HelloWorld
[] 切片:从给定索引中获取字符 a[7]会得到r
[ : ] 范围切片:给出给定范围内的字符 a[1:4]会得到ell
* 重复:创建新字符串,连接多个相同字符串的副本 a*2会得到HelloHello
not in 成员资格:如果字符不存在于给定字符串中,则返回true Z不在will中会得到1
in 成员资格:如果字符存在于给定字符串中,则返回true Ha中会得到1
% 格式:执行字符串格式化

% 字符串格式化运算符

%是 Python 中的字符串格式化运算符。参考以下示例:

#!/usr/bin/python3
print ("Hello this is %s and my age is %d !" % ('John', 25))

Output:
Hello this is John and my age is 25 !

以下表格显示了与%一起使用的符号列表:

序号 格式符号和转换
1 %c – 字符
2 %s – 格式化之前通过str()进行字符串转换
3 %i – 有符号十进制整数
4 %d – 有符号十进制整数
5 %u – 无符号十进制整数
6 %o – 八进制整数
7 %x – 十六进制整数(小写字母)
8 %X – 十六进制整数(大写字母)
9 %e – 指数表示法(小写e
10 %E – 指数表示法(大写E
11 %f – 浮点实数

Python 中的三重引号

Python 的三重引号功能用于跨越多行,包括换行符和制表符。三重引号的语法由三个连续的单引号或双引号组成。参考以下代码:

#!/usr/bin/python3

para_str = """ Python is a scripting language which was created by
Guido van Rossum in 1991, t which is used in various sectors such as Game Development, GIS Programming, Software Development, web development,
Data Analytics and Machine learning, System Scripting etc.
"""
print (para_str)

它产生以下输出。请注意制表符和换行符:

Output:
Python is a scripting language which was created by
Guido van Rossum in 1991, which is used in various sectors such as
Game Development, GIS Programming, Software Development, web development,
Data Analytics and Machine learning, System Scripting etc.

字符串是不可变的

字符串是不可变的,意味着我们不能改变值。参考给定的示例:

>>> welcome = 'Hello, John!'
>>> welcome[0] = 'Y'
TypeError: 'str' object does not support item assignment

由于字符串是不可变的;我们不能改变现有的字符串。但我们可以创建一个与原始字符串不同的新字符串:

>>> str1 = 'Hello John'
>>> new_str = 'Welcome' + str1[5:]
>>> print(str1)
Hello John
>>> print(new_str)
Welcome John
>>>

理解列表

Python 支持一种称为list的数据结构,它是一个可变的有序元素序列。列表中的每个元素称为项。列表是通过在方括号[]之间插入值来定义的。list的每个元素都被赋予一个数字,我们称之为位置或索引。索引从零开始;即第一个索引为零,第二个索引为 1,依此类推。我们可以对列表执行以下操作:索引、切片、添加、乘法和检查成员资格。

Python 的内置length函数返回列表的长度。Python 还有用于查找list的最大和最小项的函数。列表可以是编号列表、字符串列表或混合列表。

以下是创建列表的代码:

l = list()
numbers = [10, 20, 30, 40]
animals = ['Dog', 'Tiger', 'Lion']
list1 = ['John', 5.5, 500, [110, 450]]

在这里,我们创建了三个列表:第一个是numbers,第二个是animals,第三个是list1。列表中的另一个列表称为嵌套列表。我们的list1是一个嵌套列表。不包含任何元素的列表称为空列表;可以使用空括号[]创建一个空列表。

正如您所期望的,您可以将列表值分配给变量:

>>> cities = ['Mumbai', 'Pune', 'Chennai']
>>> numbers_list = [75, 857]
>>> empty_list = []
>>> print (cities, numbers_list, empty_list)
['Mumbai', 'Pune', 'Chennai'] [75, 857] []

访问列表中的值

我们可以通过使用索引值从列表中访问值。我们将在[和]中指定索引号。索引从0开始。参考给定的示例:

#!/usr/bin/python3
cities = ['Mumbai', 'Bangalore', 'Chennai', 'Pune']
numbers = [1, 2, 3, 4, 5, 6, 7 ]
print (cities[0])
print (numbers[1:5])

Output:
Mumbai
[2, 3, 4, 5]

更新列表

您可以更新列表的元素,如下面的代码所示:

#!/usr/bin/python3
cities = ['Mumbai', 'Bangalore', 'Chennai', 'Pune']
print ("Original Value: ", cities[3])
cities[3] = 'Delhi'
print ("New value: ", cities[3])

Output:
Original Value: Pune
New value: Delhi

删除列表元素

要删除列表元素,可以使用del语句(如果知道要删除的确切元素),也可以使用remove()方法(如果不知道要删除哪些项目)。参考以下示例:

#!/usr/bin/python3
cities = ['Mumbai', 'Bangalore', 'Chennai', 'Pune']
print ("Before deleting: ", cities)
del cities[2]
print ("After deleting: ", cities)

Output:
Before deleting: ['Mumbai', 'Bangalore', 'Chennai', 'Pune']
After deleting: ['Mumbai', 'Bangalore', 'Pune']

基本列表操作

有五种基本的列表操作:

  • 连接

  • 重复

  • 长度

  • 成员资格

  • 迭代

描述 表达式 结果
连接  [30, 50, 60] + ['Hello', 75, 66]  [30,50,60,'Hello',75,66]
成员资格  45 in [45,58,99,65]  True
迭代  for x in [45,58,99] : print (x,end = ' ')  45 58 99
重复  ['Python'] * 3  ['python', 'python', 'python']
长度  len([45, 58, 99, 65])  4

列表操作

在本节中,我们将学习基本的列表操作:连接和重复。

+运算符连接列表:

>>> a = [30, 50, 60]
>>> b = ['Hello', 75, 66 ]
>>> c = a + b
>>> print c
[30,50,60,'Hello',75,66]

类似地,*运算符重复给定次数的列表:

>>> [0] * 4
[0, 0, 0, 0]
>>> ['Python'] * 3
['python', 'python', 'python']

索引、切片和矩阵

列表索引的工作方式与字符串索引相同。可以使用index访问值。如果尝试读取或写入不存在的元素,则会收到IndexError。如果索引具有负值,则从列表的末尾开始向后计数。

现在,我们将创建一个名为cities的列表,并查看索引操作:

cities = ['Mumbai', 'Bangalore', 'Chennai', 'Pune']

描述 表达式 结果
索引从零开始 cities[2] 'Chennai'
切片:获取部分 cities[1:] ['Bangalore', 'Chennai', 'Pune']
负数:从右边计数 cities[-3] 'Bangalore'

元组

Python 的元组数据结构是不可变的,意味着我们不能改变元组的元素。基本上,元组是由逗号分隔并括在括号( )中的值序列。与列表一样,元组是有序的元素序列:

>>> t1 = 'h', 'e', 'l', 'l', 'o'

元组用括号( )括起来:

>>> t1 = ('h', 'e', 'l', 'l', 'o')

您还可以创建一个只有一个元素的元组。您只需在元组中放置最后一个逗号:

>>> t1 = 'h',
>>> type(t1)
<type 'tuple'>

括号中的值不是元组:

>>> t1 = ('a')
>>> type(t1)
<type 'str'>

我们可以使用tuple()函数创建一个空元组:

>>> t1 = tuple()
>>> print (t1)
()

如果参数是一个序列(字符串、列表或元组),则结果是具有序列元素的元组:

>>> t = tuple('mumbai')
>>> print t
('m', 'u', 'm', 'b', 'a', 'i')

元组的值在括号()之间用逗号分隔:

>>> t = ('a', 'b', 'c', 'd', 'e')
>>> print t[0]
'a'

切片运算符选择一系列元素。

>>> print t[1:3]
('b', 'c')

访问元组中的值

要访问元组中的值,请使用方括号进行切片,并使用索引或索引来获取该索引或索引处的值,如下例所示:

#!/usr/bin/python3
cities = ('Mumbai', 'Bangalore', 'Chennai', 'Pune')
numbers = (1, 2, 3, 4, 5, 6, 7)
print (cities[3])
print (numbers[1:6])

Output:
Pune
(2, 3, 4, 5)

更新元组

在 Python 中无法更新元组,因为元组是不可变的。但是可以使用现有元组创建一个新元组,如下例所示:

#!/usr/bin/python3
cities = ('Mumbai', 'Bangalore', 'Chennai', 'Pune')
numbers = (1,2,3,4,5,6,7)
tuple1 = cities + numbers
print(tuple1)

Output:
('Mumbai', 'Bangalore', 'Chennai', 'Pune', 1, 2, 3, 4, 5, 6, 7)

删除元组元素

我们无法删除单个元组元素。因此,要显式删除整个元组,请使用del语句。请参阅以下示例:

#!/usr/bin/python3
cities = ('Mumbai', 'Bangalore', 'Chennai', 'Pune')
print ("Before deleting: ", cities)
del cities
print ("After deleting: ", cities)

Output:
Before deleting: ('Mumbai', 'Bangalore', 'Chennai', 'Pune')
Traceback (most recent call last):
File "01.py", line 5, in <module>
print ("After deleting: ", cities)
NameError: name 'cities' is not defined

基本元组操作

与列表一样,元组有五种基本操作:

  • 连接

  • 重复

  • 长度

  • 成员资格

  • 迭代

描述 表达式 结果
迭代 for x in (45,58,99) : print (x,end = ' ') 45 58 99
重复 ('Python') * 3 ('python', 'python', 'python')
长度 len(45, 58, 99, 65) 4
连接 (30, 50, 60) + ('Hello', 75, 66) (30,50,60,'Hello',75,66)
成员资格 45 in (45,58,99,65) True

索引、切片和矩阵

元组索引的工作方式与列表索引相同。可以使用索引访问值。如果尝试读取或写入不存在的元素,则会收到IndexError。如果索引具有负值,则从列表末尾向后计数。

现在,我们将创建一个名为cities的元组并执行一些索引操作:

cities = ('Mumbai', 'Bangalore', 'Chennai', 'Pune')

描述 表达式 结果
索引从零开始 cities[2] 'Chennai'
切片:获取部分 cities[1:] ('Bangalore', 'Chennai', 'Pune')
负数:从右边计数 cities[-3] 'Bangalore'

max()和 min()

使用max()min()函数,我们可以从元组中找到最高和最低的值。这些函数允许我们获取有关定量数据的信息。让我们看一个例子:

>>> numbers = (50, 80,98, 110.5, 75, 150.58)
>>> print(max(numbers))
150.58
>>>

使用max(),我们将获得元组中的最大值。类似地,我们可以使用min()函数:

>>> numbers = (50, 80,98, 110.5, 75, 150.58)
>>> print(min(numbers))
50
>>>

因此,在这里我们得到了最小值。

集合

集合是一个无序的元素集合,没有重复项。集合的基本用途是检查成员资格测试和消除重复条目。这些集合对象支持数学运算,如并集、交集、差集和对称差。我们可以使用大括号或set()函数创建一个集合。如果要创建一个空集合,则使用set()而不是{}

以下是一个简要演示:

>>> fruits = {'Mango', 'Apple', 'Mango', 'Watermelon', 'Apple', 'Orange'}
>>> print (fruits)
{'Orange', 'Mango', 'Apple', 'Watermelon'}
>>> 'Orange' in fruits
True
>>> 'Onion' in fruits
False
>>>
>>> a = set('abracadabra')
>>> b = set('alacazam')
>>> a
{'d', 'c', 'r', 'b', 'a'}
>>> a - b
{'r', 'd', 'b'}
>>> a | b
{'d', 'c', 'r', 'b', 'm', 'a', 'z', 'l'}
>>> a & b
{'a', 'c'}
>>> a ^ b
{'r', 'd', 'b', 'm', 'z', 'l'}

Python 还支持集合解析。请参阅以下代码:

>>> a = {x for x in 'abracadabra' if x not in 'abc'}
>>> a
{'r', 'd'}

字典

字典是 Python 中的一种数据类型,由键值对组成,括在大括号{}中。字典是无序的,并由键索引,其中每个键必须是唯一的。这些键必须是不可变类型。如果元组只包含字符串、数字或元组,则可以将元组用作键。

只有一对大括号会创建一个空字典:{}。字典的主要操作是使用某个键存储值并提取给定键的值。还可以使用del删除键值对。如果使用已经使用的键进行存储,则与该键关联的旧值将被遗忘。使用不存在的键提取值是错误的。以下是使用字典的一个小例子:

>>> student = {'Name':'John', 'Age':25}
>>> student['Address'] = 'Mumbai'
>>> student
student = {'Name':'John', 'Age':25, 'Address':'Mumbai'}
>>> student['Age']
25
>>> del student['Address']
>>> student
student = {'Name':'John', 'Age':25}
>>> list(student.keys())
['Name', 'Age']
>>> sorted(student.keys())
['Age', 'Name']
>>> 'Name' in student
True
>>> 'Age' not in student
False

使用字典解析还支持任意键和值表达式来创建字典:

>>> {x: x**2 for x in (4, 6, 8)}
{4: 16, 6: 36, 8: 64}

当键是简单字符串时,有时使用关键字参数指定对更容易:

>>> dict(John=25, Nick=27, Jack=28)
{'Nick': 27, 'John': 25, 'Jack': 28}

解析命令行参数

在本节中,我们将学习解析参数和用于解析参数的模块。

Python 中的命令行参数

我们可以在命令行中使用额外的参数来启动程序。Python 程序可以使用命令行参数启动。让我们看一个例子:

$ python program_name.py img.jpg

在这里,program_name.pyimg.jpg是参数。

现在,我们将使用模块来获取参数:

模块 用途 Python 版本
optparse 已弃用 < 2.7
sys sys.argv中的所有参数(基本) 所有
argparse 构建命令行界面 >= 2.3
fire 自动生成命令行界面CLIs 所有
docopt 创建 CLIs 界面 >= 2.5

Sys.argv

sys模块用于访问命令行参数。len(sys.argv)函数包含参数的数量。要打印所有参数,只需执行str(sys.argv)。让我们看一个例子:

01.py
import sys
print('Number of arguments:', len(sys.argv))
print('Argument list:', str(sys.argv))

Output:
Python3 01.py img
Number of arguments 2
Arguments list: ['01.py', 'img']

决策制定

当条件为true时,决策制定就派上用场了。if...elif...else语句用于在 Python 中进行决策制定。

Python if 语句语法

以下是if语句的语法:

if test_expression:
 statement(s)

在这里,程序评估测试表达式,并且只有在测试表达式为true时才执行语句。如果测试表达式为false,则不执行语句

在 Python 中,if语句的主体由缩进表示。主体以缩进开始,第一行不缩进的行标志着结束。让我们看一个例子:

a = 10
if a > 0:
 print(a, "is a positive number.")
print("This statement is always printed.")

a = -10
if a > 0:
 print(a, "is a positive number.")

Output:
10 is a positive number.
This statement is always printed.

Python if...else 语句语法

在本节中,我们将学习if..else语句。只有当if条件为false时,else块才会被执行。请参考以下语法:

if test expression:
 if block
else:
 else block

if..else语句评估测试表达式,并且只有在测试条件为true时才执行if的主体。如果条件为false,则执行else的主体。缩进用于分隔块。请参考以下示例:

a = 10
if a > 0:
 print("Positive number")
else:
 print("Negative number")

Output:
Positive number

Python if...elif...else 语句

elif语句检查多个语句是否为true值。每当值评估为true时,该代码块就会被执行。请参考以下语法:

if test expression:
 if block statements
elif test expression:
 elif block statements
else:
 else block statements

elifelse if的缩写。它允许我们检查多个表达式。如果if语句中的条件为false,那么它将检查下一个elif块的条件,依此类推。如果所有条件都为false,则执行else的主体。

根据条件,if...elif...else块中的多个块中只有一个块被执行。if块只能有一个else块。但它可以有多个elif块。让我们看一个例子:

a = 10
if a > 50:
 print("a is greater than 50")
elif a == 10:
 print("a is equal to 10")
else:
 print("a is negative")

Output:
a is equal to 10

循环

为了处理脚本中的所有循环需求,Python 支持两种循环:

  • for 循环

  • while 循环

现在,我们将学习for 循环while 循环

for 循环

for 循环遍历序列或任何其他可迭代对象的每个项目,并且每次都会执行 for 块中的语句。请参考以下语法:

for i in sequence:
 for loop body

在这里,i是变量,它在每次迭代时取序列内的项目的值。这个循环会一直持续,直到我们到达序列中的最后一个项目。这在下面的图表中有所说明:

请参考以下示例:

numbers = [6, 5, 3, 8, 4, 2, 5, 4, 11]
sum = 0
for i in numbers:
 sum = sum + i
 print("The sum is", sum)

Output:
The sum is 6
The sum is 11
The sum is 14
The sum is 22
The sum is 26
The sum is 28
The sum is 33
The sum is 37
The sum is 48

range()函数

Python 的range()函数将生成一个数字序列。例如,range(10)将生成从09的数字(10 个数字)。

我们还可以将起始、停止和步长大小定义为参数,range()将如下所示:

range(start, stop, step size).
Step size defaults to 1 if not provided.
For loop example using range() function:

让我们看一个例子:

for i in range(5):
 print("The number is", i)

Output:
The number is 0
The number is 1
The number is 2
The number is 3
The number is 4

while 循环

while是一个循环语句,它将在输入的测试表达式为true时迭代一段代码块。当我们不知道迭代将进行多少次时,我们使用这个循环。请参考以下语法:

while test_expression:
 while body statements

在 while 循环中,首先我们将检查测试表达式。只有在测试表达式为true时,while块才会被执行。经过一次迭代后,表达式将再次被检查,这个过程将继续,直到test_expression评估为false。这在下图中有所说明:

以下是while循环的示例:

a = 10
sum = 0
i = 1
while i <= a:
 sum = sum + i
 i = i + 1
 print("The sum is", sum)

Output:
The sum is 1
The sum is 3
The sum is 6
The sum is 10
The sum is 15
The sum is 21
The sum is 28
The sum is 36
The sum is 45
The sum is 55

迭代器

在 Python 中,迭代器是可以被迭代的对象。它是一个对象,每次返回一个元素的数据。Python 的迭代器对象实现了两个方法,__iter__()__next__()。大多数情况下,迭代器在循环、生成器和推导式中实现。

在以下示例中,我们使用next()函数,它将遍历所有项目。在到达末尾并且没有更多数据需要返回时,它将引发StopIteration,如下例所示:

numbers = [10, 20, 30, 40]

numbers_iter = iter(numbers)

print(next(numbers_iter))
print(next(numbers_iter))
print(numbers_iter.__next__())
print(numbers_iter.__next__())

next(numbers_iter)

Output:
10
20
30
40
Traceback (most recent call last):
 File "sample.py", line 10, in <module>
 next(numbers_iter)
StopIteration

生成器

我们可以使用 Python 生成器创建迭代器。在 Python 中,生成器是一个返回可以迭代的对象的函数。

如何在 Python 中创建一个生成器?

在 Python 中创建生成器很容易。您可以通过定义一个带有yield语句而不是return语句的函数来创建生成器。如果一个函数包含至少一个yield语句,它就成为一个生成器函数。yieldreturn语句将从函数返回一些值。以下是一个例子:

def my_gen():
 n = 1
 print('This is printed first')
 yield n
 n += 1
 print('This is printed second')
 yield n
 n += 1
 print('This is printed at last')
 yield n
for item in my_gen():
 print(item)

Output:
This is printed first
1
This is printed second
2
This is printed at last
3

函数

函数是执行特定任务的一组语句。使用函数有助于将程序分解为更小的部分。如果使用函数,程序将更有组织性,因为它避免了重复,并使代码可重用。看一下以下语法:

def function_name(parameters):
 statement(s)

参考以下示例:

def welcome(name):
 print("Hello " + name + ", Welcome to Python Programming !")
 welcome("John")

Output:
Hello John, Welcome to Python Programming !

返回语句

return语句用于退出函数。参考以下语法:

return [expression_list]

此语句可能包含一个表达式,其中必须返回一个值。如果没有表达式,那么函数将返回一个 None 对象,如下例所示:

def return_value(a):
 if a >= 0:
 return a
 else:
 return -a
print(return_value(2))
print(return_value(-4))

Output:
2
4

Lambda 函数

在 Python 中,匿名函数是没有名称定义的函数,称为lambda函数,因为它是使用关键字lambda定义的。我们在需要短时间内使用函数时使用这些函数。

Lambda 函数与内置函数一起使用,例如filter()map()

filter()函数返回一个元素列表,并且只有一个可迭代的输入。以下是使用filter()的示例:

numbers = [10, 25, 54, 86, 89, 11, 33, 22]
new_numbers = list(filter(lambda x: (x%2 == 0) , numbers))
print(new_numbers)

Output:
[10, 54, 86, 22]

在这个例子中,filter()函数接受一个lambda函数和一个列表作为参数。

map()函数在应用指定函数后返回结果列表。现在,让我们看一个使用map()的示例:

my_list = [1, 5, 4, 6, 8, 11, 3, 12]
new_list = list(map(lambda x: x * 2 , my_list))
print(new_list)

Output:
[2, 10, 8, 12, 16, 22, 6, 24]

在这里,map()函数接受一个lambda函数和一个列表。

模块

模块只是包含 Python 语句和定义的文件。包含 Python 代码的文件(例如,sample.py)被称为模块,其模块名称将是sample。使用模块,我们可以将较大的程序分解为小的有组织的部分。模块的一个重要特性是可重用性。您可以在模块中定义最常用的函数的定义,而不是在不同的程序中复制它们,只需在需要时导入它们。

让我们创建一个模块并导入它。我们将创建两个脚本:sample.pyadd.py。我们将在add.py中导入一个示例模块。现在,将以下代码保存为sample.py。让我们看看以下示例:

sample.py
def addition(num1, num2):
 result = num1 + num2
 return result

在这里,我们在名为sample的模块中定义了一个addition()函数。该函数接受两个数字并返回它们的和。现在我们已经创建了一个模块。您可以在任何 Python 程序中导入它。

导入模块

现在,在创建模块之后,我们将学习如何导入该模块。在前面的示例中,我们创建了一个示例模块。现在我们将在add.py脚本中导入示例模块:

add.py
import sample
sum = sample.addition(10, 20)
print(sum)

Output:
30

总结

在本章中,我们概述了 Python 脚本语言。我们学习了如何安装 Python 和各种工具。我们还学习了 Python 解释器以及如何使用它。我们了解了 Python 支持的数据类型、变量、数字和字符串、决策语句以及循环语句。我们还学习了函数以及如何在脚本和模块中使用它们以及如何创建和导入它们。

在下一章《调试和分析 Python 脚本》中,您将学习 Python 调试技术、错误处理(异常处理)、调试工具、调试基本程序崩溃、程序分析和计时、以及使程序运行更快的方法。

问题

  1. 迭代器和生成器是什么?

  2. 列表是可变的还是不可变的?

  3. Python 中的数据结构是什么?

  4. 如何访问列表中的值?

  5. 模块是什么?

进一步阅读

所有 Python 文档都可以在以下网站上找到:www.python.org

您还可以查阅以下书籍,《学习 Python 的艰难方式》和《Python 之字节》,以了解 Python 的基础知识。

第二章:调试和分析 Python 脚本

调试和分析在 Python 开发中扮演重要角色。调试器帮助程序员分析完整的代码。调试器设置断点,而分析器运行我们的代码并提供执行时间的详细信息。分析器将识别程序中的瓶颈。在本章中,我们将学习pdb Python 调试器、cProfile模块和timeit模块来计算 Python 代码的执行时间。

在本章中,您将学习以下内容:

  • Python 调试技术

  • 错误处理(异常处理)

  • 调试器工具

  • 调试基本程序崩溃

  • 分析和计时程序

  • 使程序运行更快

什么是调试?

调试是解决代码中出现的问题并防止软件正常运行的过程。在 Python 中,调试非常容易。Python 调试器设置条件断点,并逐行调试源代码。我们将使用 Python 标准库中的pdb模块来调试我们的 Python 脚本。

Python 调试技术

为了更好地调试 Python 程序,有各种技术可用。我们将看一下 Python 调试的四种技术:

  • print()语句:这是了解发生了什么的最简单方法,因此您可以检查已执行了什么。

  • logging:这类似于print语句,但提供更多上下文信息,以便您可以完全理解。

  • pdb调试器:这是一种常用的调试技术。使用pdb的优势是可以从命令行、在解释器内和在程序内部使用pdb

  • IDE 调试器:IDE 具有集成的调试器。它允许开发人员执行其代码,然后开发人员可以在程序执行时进行检查。

错误处理(异常处理)

在本节中,我们将学习 Python 如何处理异常。但首先,什么是异常?异常是程序执行过程中发生的错误。每当发生任何错误时,Python 都会生成一个异常,该异常将使用try…except块进行处理。有些异常无法由程序处理,因此会导致错误消息。现在,我们将看一些异常示例。

在您的终端中,启动python3交互式控制台,我们将看到一些异常示例:

student@ubuntu:~$ python3 Python 3.5.2 (default, Nov 23 2017, 16:37:01) [GCC 5.4.0 20160609] on linux Type "help", "copyright", "credits" or "license" for more information. >>> >>> 50 / 0 Traceback (most recent call last):
 File "<stdin>", line 1, in <module> ZeroDivisionError: division by zero >>> >>> 6 + abc*5 Traceback (most recent call last):
 File "<stdin>", line 1, in <module> NameError: name 'abc' is not defined >>> >>> 'abc' + 2 Traceback (most recent call last):
 File "<stdin>", line 1, in <module> TypeError: Can't convert 'int' object to str implicitly >>> >>> import abcd Traceback (most recent call last):
 File "<stdin>", line 1, in <module> ImportError: No module named 'abcd' >>> 

这些是一些异常示例。现在,我们将看看如何处理这些异常。

每当您的 Python 程序发生错误时,都会引发异常。我们还可以使用raise关键字强制引发异常。

现在我们将看到一个处理异常的try…except块。在try块中,我们将编写可能生成异常的代码。在except块中,我们将为该异常编写解决方案。

try…except的语法如下:

try:
 statement(s)
except:
 statement(s)

try块可以有多个 except 语句。我们还可以在except关键字后输入异常名称来处理特定异常。处理特定异常的语法如下:

try:
 statement(s)
except exception_name:
 statement(s)

我们将创建一个exception_example.py脚本来捕获ZeroDivisionError。在您的脚本中编写以下代码:

a = 35 b = 57 try:
 c = a + b print("The value of c is: ", c) d = b / 0 print("The value of d is: ", d)except:
 print("Division by zero is not possible")print("Out of try...except block")

按以下方式运行脚本,您将获得以下输出:

student@ubuntu:~$ python3 exception_example.py The value of c is:  92 Division by zero is not possible Out of try...except block

调试工具

Python 支持许多调试工具:

  • winpdb

  • pydev

  • pydb

  • pdb

  • gdb

  • pyDebug

在本节中,我们将学习pdb Python 调试器。pdb模块是 Python 标准库的一部分,始终可供使用。

pdb 调试器

pdb模块用于调试 Python 程序。Python 程序使用pdb交互式源代码调试器来调试程序。pdb设置断点并检查堆栈帧,并列出源代码。

现在我们将学习如何使用pdb调试器。有三种使用此调试器的方法:

  • 在解释器内

  • 从命令行

  • 在 Python 脚本内

我们将创建一个pdb_example.py脚本,并在该脚本中添加以下内容:

class Student:
 def __init__(self, std): self.count = std            def print_std(self):
 for i in range(self.count): print(i) return if __name__ == '__main__':
 Student(5).print_std()

使用此脚本作为学习 Python 调试的示例,我们将详细了解如何启动调试器。

在解释器中

要从 Python 交互式控制台启动调试器,我们使用run()runeval()

启动您的python3交互式控制台。运行以下命令启动控制台:

 $ python3

导入我们的pdb_example脚本名称和pdb模块。现在,我们将使用run(),并将一个字符串表达式作为参数传递给run(),该表达式将由 Python 解释器自身进行评估:

student@ubuntu:~$ python3 Python 3.5.2 (default, Nov 23 2017, 16:37:01) [GCC 5.4.0 20160609] on linux Type "help", "copyright", "credits" or "license" for more information. >>> >>> import pdb_example >>> import pdb >>> pdb.run('pdb_example.Student(5).print_std()') > <string>(1)<module>() (Pdb)

要继续调试,在(Pdb)提示后输入continue,然后按Enter。如果想要了解我们可以在其中使用的选项,那么在(Pdb)提示后按两次Tab键。

现在,在输入continue后,我们将得到以下输出:

student@ubuntu:~$ python3 Python 3.5.2 (default, Nov 23 2017, 16:37:01) [GCC 5.4.0 20160609] on linux Type "help", "copyright", "credits" or "license" for more information. >>> >>> import pdb_example >>> import pdb >>> pdb.run('pdb_example.Student(5).print_std()') > <string>(1)<module>() (Pdb) continue 0 1 2 3 4 >>> 

从命令行

从命令行运行调试器的最简单和最直接的方法。我们的程序将作为调试器的输入。您可以按以下方式从命令行使用调试器:

$ python3 -m pdb pdb_example.py

当您从命令行运行调试器时,将加载源代码,并且它将在找到的第一行上停止执行。输入continue以继续调试。以下是输出:

student@ubuntu:~$ python3 -m pdb pdb_example.py > /home/student/pdb_example.py(1)<module>() -> class Student: (Pdb) continue 0 1 2 3 4 The program finished and will be restarted > /home/student/pdb_example.py(1)<module>() -> class Student: (Pdb)

在 Python 脚本中

前两种技术将在 Python 程序的开头启动调试器。但是这第三种技术最适合长时间运行的进程。要在脚本中启动调试器,请使用set_trace()

现在,按以下方式修改您的pdb_example.py文件:

import pdb class Student:
 def __init__(self, std): self.count = std            def print_std(self):
 for i in range(self.count): pdb.set_trace() print(i) returnif __name__ == '__main__':
 Student(5).print_std()

现在,按以下方式运行程序:

student@ubuntu:~$ python3 pdb_example.py > /home/student/pdb_example.py(10)print_std() -> print(i) (Pdb) continue 0 > /home/student/pdb_example.py(9)print_std() -> pdb.set_trace() (Pdb)

set_trace()是一个 Python 函数,因此您可以在程序的任何地方调用它。

因此,这些是您可以启动调试器的三种方式。

调试基本程序崩溃

在本节中,我们将看到跟踪模块。跟踪模块有助于跟踪程序的执行。因此,每当您的 Python 程序崩溃时,我们都可以了解它崩溃的位置。我们可以通过将其导入到脚本中以及从命令行中使用跟踪模块。

现在,我们将创建一个名为trace_example.py的脚本,并在脚本中写入以下内容:

class Student:
 def __init__(self, std): self.count = std            def go(self):
 for i in range(self.count): print(i) return if __name__ == '__main__':
 Student(5).go()

输出将如下所示:

student@ubuntu:~$ python3 -m trace --trace trace_example.py
 --- modulename: trace_example, funcname: <module> trace_example.py(1): class Student:
 --- modulename: trace_example, funcname: Student trace_example.py(1): class Student: trace_example.py(2):   def __init__(self, std): trace_example.py(5):   def go(self): trace_example.py(10): if __name__ == '__main__': trace_example.py(11):             Student(5).go()
 --- modulename: trace_example, funcname: init trace_example.py(3):               self.count = std
 --- modulename: trace_example, funcname: go trace_example.py(6):               for i in range(self.count): trace_example.py(7):                           print(i) 0 trace_example.py(6):               for i in range(self.count): trace_example.py(7):                           print(i) 1 trace_example.py(6):               for i in range(self.count): trace_example.py(7):                           print(i) 2 trace_example.py(6):               for i in range(self.count): trace_example.py(7):                           print(i) 3 trace_example.py(6):               for i in range(self.count): trace_example.py(7):                           print(i) 4

因此,通过在命令行中使用trace --trace,开发人员可以逐行跟踪程序。因此,每当程序崩溃时,开发人员都将知道它崩溃的位置。

对程序进行分析和计时

对 Python 程序进行分析意味着测量程序的执行时间。它测量了每个函数中花费的时间。Python 的cProfile模块用于对 Python 程序进行分析。

cProfile 模块

如前所述,分析意味着测量程序的执行时间。我们将使用cProfile Python 模块对程序进行分析。

现在,我们将编写一个cprof_example.py脚本,并在其中写入以下代码:

mul_value = 0 def mul_numbers( num1, num2 ):
 mul_value = num1 * num2; print ("Local Value: ", mul_value) return mul_value mul_numbers( 58, 77 ) print ("Global Value: ", mul_value)

运行程序,您将看到以下输出:

student@ubuntu:~$ python3 -m cProfile cprof_example.py Local Value:  4466 Global Value:  0
 6 function calls in 0.000 seconds Ordered by: standard name   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
 1    0.000    0.000    0.000    0.000 cprof_example.py:1(<module>) 1    0.000    0.000    0.000    0.000 cprof_example.py:2(mul_numbers) 1    0.000    0.000    0.000    0.000 {built-in method builtins.exec} 2    0.000    0.000    0.000    0.000 {built-in method builtins.print} 1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

因此,使用cProfile,所有调用的函数都将打印出每个函数所花费的时间。现在,我们将看看这些列标题的含义:

  • ncalls:调用次数

  • tottime: 在给定函数中花费的总时间

  • percalltottime除以ncalls的商

  • cumtime:在此及所有子函数中花费的累计时间

  • percallcumtime除以原始调用的商

  • filename:lineno(function): 提供每个函数的相应数据

timeit

timeit是一个用于计时 Python 脚本的 Python 模块。您可以从命令行调用timeit,也可以将timeit模块导入到您的脚本中。我们将编写一个脚本来计时一段代码。创建一个timeit_example.py脚本,并将以下内容写入其中:

import timeit prg_setup = "from math import sqrt" prg_code = ''' def timeit_example():
 list1 = [] for x in range(50): list1.append(sqrt(x)) ''' # timeit statement print(timeit.timeit(setup = prg_setup, stmt = prg_code, number = 10000)) 

使用timeit,我们可以决定要测量性能的代码片段。因此,我们可以轻松地分别定义设置代码以及要执行测试的代码片段。主要代码运行 100 万次,这是默认时间,而设置代码只运行一次。

使程序运行更快

有各种方法可以使您的 Python 程序运行更快,例如以下方法:

  • 对代码进行分析,以便识别瓶颈

  • 使用内置函数和库,这样解释器就不需要执行循环。

  • 避免使用全局变量,因为 Python 在访问全局变量时非常慢

  • 使用现有包

总结

在本章中,我们学习了调试和分析程序的重要性。我们了解了调试的不同技术。我们学习了pdb Python 调试器以及如何处理异常。我们学习了如何在分析和计时我们的脚本时使用 Python 的cProfiletimeit模块。我们还学习了如何使您的脚本运行更快。

在下一章中,我们将学习 Python 中的单元测试。我们将学习如何创建和使用单元测试。

问题

  1. 调试程序时,使用哪个模块?

  2. 查看如何使用ipython以及所有别名和魔术函数。

  3. 什么是全局解释器锁GIL)?

  4. PYTHONSTARTUPPYTHONCASEOKPYTHONHOMEPYTHONSTARTUP环境变量的目的是什么?

  5. 以下代码的输出是什么? a) [0],b) [1],c) [1, 0],d) [0, 1]

def foo(k):
    k = [1]
q = [0]
foo(q)
print(q)
  1. 以下哪个是无效的变量?

a) my_string_1

b) 1st_string

c) foo

d) _

进一步阅读

第三章:单元测试-单元测试框架简介

测试您的项目是软件开发的重要部分。在本章中,我们将学习 Python 中的单元测试。Python 有一个名为unittest的模块,这是一个单元测试框架。我们将在本章学习unittest框架。

在本章中,您将学习以下主题:

  • 单元测试框架简介

  • 创建单元测试任务

什么是 unittest?

unittest是 Python 中的一个单元测试框架。它支持多个任务,如测试固件、编写测试用例、将测试用例聚合到测试套件中以及运行测试。

unittest支持四个主要概念,列在这里:

  • test fixture: 这包括为执行一个或多个测试准备和清理活动

  • test case: 这包括您的单个单元测试。通过使用unittestTestCase基类,我们可以创建新的测试用例

  • test suite: 这包括一组测试用例、测试套件或两者。这是为了一起执行测试用例

  • test runner: 这包括安排测试执行并向用户提供输出

Python 有一个unittest模块,我们将在脚本中导入它。unittest模块有TestCase类用于创建测试用例。

可以将单独的测试用例创建为方法。这些方法名称以单词test开头。因此,测试运行器将知道哪些方法代表测试用例。

创建单元测试

在本节中,我们将创建单元测试。为此,我们将创建两个脚本。一个将是您的常规脚本,另一个将包含用于测试的代码。

首先,创建一个名为arithmetic.py的脚本,并在其中编写以下代码:

# In this script, we are going to create a 4 functions: add_numbers, sub_numbers, mul_numbers, div_numbers. def add_numbers(x, y):
 return x + y def sub_numbers(x, y):
 return x - y def mul_numbers(x, y):
 return x * y def div_numbers(x, y):
 return (x / y)

在上面的脚本中,我们创建了四个函数:add_numberssub_numbersmul_numbersdiv_numbers。现在,我们将为这些函数编写测试用例。首先,我们将学习如何为add_numbers函数编写测试用例。创建一个名为test_addition.py的脚本,并在其中编写以下代码:

import arithmetic import unittest # Testing add_numbers function from arithmetic. class Test_addition(unittest.TestCase): # Testing Integers def test_add_numbers_int(self): sum = arithmetic.add_numbers(50, 50) self.assertEqual(sum, 100) # Testing Floats def test_add_numbers_float(self): sum = arithmetic.add_numbers(50.55, 78) self.assertEqual(sum, 128.55) # Testing Strings def test_add_numbers_strings(self): sum = arithmetic.add_numbers('hello','python') self.assertEqual(sum, 'hellopython')  if __name__ == '__main__': unittest.main()

在上面的脚本中,我们为add_numbers函数编写了三个测试用例。第一个是测试整数,第二个是测试浮点数,第三个是测试字符串。在字符串中,添加意味着连接两个字符串。类似地,您可以为减法、乘法和除法编写测试用例。

现在,我们将运行我们的test_addition.py测试脚本,并看看运行此脚本后我们得到什么结果。

按照以下方式运行脚本,您将获得以下输出:

student@ubuntu:~$ python3 test_addition.py ... ---------------------------------------------------------------------- Ran 3 tests in 0.000s
OK

在这里,我们得到了OK,这意味着我们的测试成功了。

每当运行测试脚本时,您有三种可能的测试结果:

结果 描述
OK 成功
FAIL 测试失败-引发AssertionError异常
ERROR 引发除AssertionError之外的异常

单元测试中使用的方法

每当我们使用unittest时,我们在脚本中使用一些方法。这些方法如下:

  • assertEqual()assertNotEqual(): 这检查预期结果

  • assertTrue()assertFalse(): 这验证条件

  • assertRaises(): 这验证特定异常是否被引发

  • setUp()tearDown(): 这定义了在每个测试方法之前和之后执行的指令

您也可以从命令行使用unittest模块。因此,您可以按照以下方式运行先前的测试脚本:

student@ubuntu:~$ python3 -m unittest test_addition.py ... ---------------------------------------------------------------------- Ran 3 tests in 0.000s
OK

现在,我们将看另一个例子。我们将创建两个脚本:if_example.pytest_if.pyif_example.py将是我们的常规脚本,test_if.py将包含测试用例。在此测试中,我们正在检查输入的数字是否等于100。如果等于100,则我们的测试将是成功的。如果不是,它必须显示一个FAILED结果。

创建一个名为if_example.py的脚本,并在其中编写以下代码:

def check_if():
 a = int(input("Enter a number \n")) if (a == 100): print("a is equal to 100") else: print("a is not equal to 100") return a

现在,创建一个名为test_if.py的测试脚本,并在其中编写以下代码:

import if_example import unittest  class Test_if(unittest.TestCase): def test_if(self): result = if_example.check_if() self.assertEqual(result, 100) if __name__ == '__main__':
 unittest.main()

按以下方式运行测试脚本:

student@ubuntu:~/Desktop$ python3 -m unittest test_if.py Enter a number 100 a is equal to 100 . ---------------------------------------------------------------------- Ran 1 test in 1.912s OK 

我们运行脚本以获得成功的测试结果。现在,我们将输入除100之外的一些值,我们必须得到一个FAILED的结果。按以下方式运行脚本:

student@ubuntu:~/Desktop$ python3 -m unittest test_if.py Enter a number 50 a is not equal to 100 F ====================================================================== FAIL: test_if (test_if.Test_if) ---------------------------------------------------------------------- Traceback (most recent call last):
 File "/home/student/Desktop/test_if.py", line 7, in test_if self.assertEqual(result, 100) AssertionError: 50 != 100
---------------------------------------------------------------------- Ran 1 test in 1.521s
FAILED (failures=1)

摘要

在本章中,我们学习了 Python 的单元测试框架unittest。我们还学习了如何创建测试用例以及单元测试中使用的方法。

在下一章中,我们将学习如何自动化系统管理员的常规管理活动。您将学习如何接受输入,处理密码,执行外部命令,读取配置文件,向脚本添加警告代码,设置 CPU 限制,启动 web 浏览器,使用os模块并进行备份。

问题

  1. 什么是单元测试、自动化测试和手动测试?

  2. 除了unittest之外还有哪些替代模块?

  3. 编写测试用例有什么用?

  4. 什么是 PEP8 标准?

进一步阅读

第四章:自动化常规管理活动

系统管理员执行各种管理活动。这些活动可能包括文件处理、日志记录、管理 CPU 和内存、处理密码,以及最重要的是进行备份。这些活动需要自动化。在本章中,我们将学习如何使用 Python 自动化这些活动。

在本章中,我们将涵盖以下主题:

  • 通过重定向、管道和输入文件接受输入

  • 在脚本中在运行时处理密码

  • 执行外部命令并获取它们的输出

  • 在运行时提示密码和验证

  • 读取配置文件

  • 向脚本添加日志和警告代码

  • 限制 CPU 和内存使用

  • 启动 Web 浏览器

  • 使用os模块处理目录和文件

  • 进行备份(使用rsync

通过重定向、管道和输入文件接受输入

在本节中,我们将学习用户如何通过重定向、管道和外部输入文件接受输入。

接受重定向输入时,我们使用stdinpipe是另一种重定向形式。这个概念意味着将一个程序的输出作为另一个程序的输入。我们可以通过外部文件和使用 Python 来接受输入。

通过重定向输入

stdinstdoutos模块创建的对象。我们将编写一个脚本,其中我们将使用stdinstdout

创建一个名为redirection.py的脚本,并在其中编写以下代码:

import sys class Redirection(object):
 def __init__(self, in_obj, out_obj): self.input = in_obj self.output = out_obj def read_line(self): res = self.input.readline() self.output.write(res) return resif __name__ == '__main__':
 if not sys.stdin.isatty(): sys.stdin = Redirection(in_obj=sys.stdin, out_obj=sys.stdout) a = input('Enter a string: ') b = input('Enter another string: ') print ('Entered strings are: ', repr(a), 'and', repr(b)) 

如下运行上述程序:

$ python3 redirection.py 

我们将收到以下输出:

Output: Enter a string: hello Enter another string: python Entered strings are:  'hello' and 'python'

每当程序在交互会话中运行时,stdin是键盘输入,stdout是用户的终端。input()函数用于从用户那里获取输入,print()是在终端(stdout)上写入的方式。

通过管道输入

管道是另一种重定向形式。这种技术用于将信息从一个程序传递到另一个程序。|符号表示管道。通过使用管道技术,我们可以以一种使一个命令的输出作为下一个命令的输入的方式使用两个以上的命令。

现在,我们将看看如何使用管道接受输入。为此,首先我们将编写一个返回floor除法的简单脚本。创建一个名为accept_by_pipe.py的脚本,并在其中编写以下代码:

import sys for n in sys.stdin:
 print ( int(n.strip())//2 ) 

运行脚本,您将得到以下输出:

$ echo 15 | python3 accept_by_pipe.py Output: 7 

在上面的脚本中,stdin是键盘输入。我们对我们在运行时输入的数字执行floor除法。floor 除法仅返回商的整数部分。当我们运行程序时,我们传递15,然后是管道|符号,然后是我们的脚本名称。因此,我们将15作为输入提供给我们的脚本。因此进行了 floor 除法,我们得到输出为7

我们可以向我们的脚本传递多个输入。因此,在以下执行中,我们已经传递了多个输入值,如154520。为了处理多个输入值,我们在脚本中编写了一个for循环。因此,它将首先接受15作为输入,然后是45,然后是20。输出将以新行打印出每个输入,因为我们在输入值之间写了\n。为了启用对反斜杠的这种解释,我们传递了-e标志:

$ echo -e '15\n45\n20' | python3 accept_by_pipe.py Output: 7 22 10

运行后,我们得到了154520的 floor 除法分别为72210,显示在新行上。

通过输入文件输入

在本节中,我们将学习如何从输入文件中获取输入。在 Python 中,从输入文件中获取输入更容易。我们将看一个例子。但首先,我们将创建一个名为sample.txt的简单文本文件,并在其中编写以下代码:

Sample.txt

Hello World Hello Python

现在,创建一个名为accept_by_input_file.py的脚本,并在其中编写以下代码:

i = open('sample.txt','r')
o = open('sample_output.txt','w')

a = i.read()
o.write(a)

运行程序,您将得到以下输出:

$ python3 accept_by_input_file.py $ cat sample_output.txt Hello World Hello Python

在脚本中在运行时处理密码

在本节中,我们将看一个简单的处理脚本密码的例子。我们将创建一个名为handling_password.py的脚本,并在其中编写以下内容:

import sys import paramiko import time ip_address = "192.168.2.106" username = "student" password = "training" ssh_client = paramiko.SSHClient() ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh_client.load_system_host_keys() ssh_client.connect(hostname=ip_address,\
 username=username, password=password) print ("Successful connection", ip_address) ssh_client.invoke_shell() remote_connection = ssh_client.exec_command('cd Desktop; mkdir work\n') remote_connection = ssh_client.exec_command('mkdir test_folder\n') #print( remote_connection.read() ) ssh_client.close

运行上述脚本,您将收到以下输出:

$ python3 handling_password.py  Output: Successful connection 192.168.2.106

在上述脚本中,我们使用了paramiko模块。paramiko模块是ssh的 Python 实现,提供了客户端-服务器功能。

按以下方式安装paramiko

pip3 install paramiko

在上述脚本中,我们远程连接到主机192.168.2.106。我们在脚本中提供了主机的用户名和密码。

运行此脚本后,在192.168.2.106桌面上,您将找到一个work文件夹,并且test_folder可以在192.168.2.106home/目录中找到。

执行外部命令并获取它们的输出

在本节中,我们将学习 Python 的 subprocess 模块。使用subprocess,很容易生成新进程并获取它们的返回代码,执行外部命令并启动新应用程序。

我们将看一下如何在 Python 中执行外部命令并获取它们的输出,使用subprocess模块。我们将创建一个名为execute_external_commands.py的脚本,并在其中编写以下代码:

import subprocess subprocess.call(["touch", "sample.txt"]) subprocess.call(["ls"]) print("Sample file created") subprocess.call(["rm", "sample.txt"]) 
subprocess.call(["ls"]) print("Sample file deleted")

运行程序,您将得到以下输出:

$ python3 execute_external_commands.py Output: 1.py     accept_by_pipe.py      sample_output.txt       sample.txt accept_by_input_file.py         execute_external_commands.py         output.txt        sample.py Sample.txt file created 1.py     accept_by_input_file.py         accept_by_pipe.py execute_external_commands.py  output.txt            sample_output.txt       sample.py Sample.txt file deleted

使用 subprocess 模块捕获输出

在本节中,我们将学习如何捕获输出。我们将为stdout参数传递PIPE以捕获输出。编写一个名为capture_output.py的脚本,并在其中编写以下代码:

import subprocess res = subprocess.run(['ls', '-1'], stdout=subprocess.PIPE,) print('returncode:', res.returncode) print(' {} bytes in stdout:\n{}'.format(len(res.stdout), res.stdout.decode('utf-8'))) 

按以下方式执行脚本:

student@ubuntu:~$ python3 capture_output.py 

在执行时,我们将收到以下输出:

Output: returncode: 0 191 bytes in stdout: 1.py accept_by_input_file.py accept_by_pipe.py execute_external_commands.py getpass_example.py ouput.txt output.txt password_prompt_again.py sample_output.txt sample.py capture_output.py

在上述脚本中,我们导入了 Python 的 subprocess 模块,它有助于捕获输出。subprocess 模块用于创建新进程。它还有助于连接输入/输出管道并获取返回代码。subprocess.run()将运行作为参数传递的命令。Returncode将是子进程的退出状态。在输出中,如果返回代码为0,表示它成功运行。

运行时提示密码和验证

在本节中,我们将学习如何在运行时处理密码,使用getpass 模块。Python 中的getpass()模块提示用户输入密码而不回显。getpass模块用于在程序通过终端与用户交互时处理密码提示。

我们将看一些如何使用getpass模块的例子:

  1. 创建一个名为no_prompt.py的脚本,并在其中编写以下代码:
import getpass try:
 p = getpass.getpass() except Exception as error:
 print('ERROR', error) else:
 print('Password entered:', p)

在此脚本中,不为用户提供提示。因此,默认情况下,它设置为Password提示。

按以下方式运行脚本:

$ python3 no_prompt.py Output : Password: Password entered: abcd
  1. 我们将提供一个输入密码的提示。因此,在其中创建一个名为with_prompt.py的脚本,并在其中编写以下代码:
import getpass try:
 p = getpass.getpass("Enter your password: ") except Exception as error:
 print('ERROR', error) else:
 print('Password entered:', p)

现在,我们已经编写了一个脚本,用于提供密码的提示。按以下方式运行程序:

$ python3 with_prompt.py Output: Enter your password: Password entered: abcd

在这里,我们为用户提供了“输入密码”的提示。

现在,我们将编写一个脚本,如果输入错误的密码,它将只是打印一个简单的消息,但不会再提示输入正确的密码。

  1. 编写一个名为getpass_example.py的脚本,并在其中编写以下代码:
import getpass passwd = getpass.getpass(prompt='Enter your password: ') if passwd.lower() == '#pythonworld':
 print('Welcome!!') else:
 print('The password entered is incorrect!!')

按以下方式运行程序(这里我们输入了正确的密码,即#pythonworld):

$ python3 getpass_example.py Output: Enter your password: Welcome!!

现在,我们将输入一个错误的密码,并检查我们收到什么消息:

$ python3 getpass_example.py Output: Enter your password: The password entered is incorrect!!

在这里,我们编写了一个脚本,如果我们输入错误的密码,就不会再要求输入密码。

现在,我们将编写一个脚本,当我们提供错误的密码时,它将再次要求输入正确的密码。使用getuser()来获取用户的登录名。getuser()函数将返回系统登录的用户。创建一个名为password_prompt_again.py的脚本,并在其中编写以下代码:

import getpass user_name = getpass.getuser() print ("User Name : %s" % user_name) while True:
 passwd = getpass.getpass("Enter your Password : ") if passwd == '#pythonworld': print ("Welcome!!!") break else: print ("The password you entered is incorrect.")

运行程序,您将得到以下输出:

student@ubuntu:~$ python3 password_prompt_again.py User Name : student Enter your Password : The password you entered is incorrect. Enter your Password : Welcome!!!

读取配置文件

在本节中,我们将学习 Python 的configparser模块。通过使用configparser模块,您可以管理应用程序的用户可编辑的配置文件。

这些配置文件的常见用途是,用户或系统管理员可以使用简单的文本编辑器编辑文件以设置应用程序默认值,然后应用程序将读取并解析它们,并根据其中写入的内容进行操作。

要读取配置文件,configparserread()方法。现在,我们将编写一个名为read_config_file.py的简单脚本。在那之前,创建一个名为read_simple.ini.ini文件,并在其中写入以下内容:read_simple.ini

[bug_tracker] url = https://timesofindia.indiatimes.com/

创建read_config_file.py并输入以下内容:

from configparser import ConfigParser p = ConfigParser() p.read('read_simple.ini') print(p.get('bug_tracker', 'url'))

运行read_config_file.py,您将获得以下输出:

$ python3 read_config_file.py  Output: https://timesofindia.indiatimes.com/

read()方法接受多个文件名。每当扫描每个文件名并且该文件存在时,它将被打开并读取。现在,我们将编写一个用于读取多个文件名的脚本。创建一个名为read_many_config_file.py的脚本,并在其中编写以下代码:

from configparser import ConfigParser import glob p = ConfigParser() files = ['hello.ini', 'bye.ini', 'read_simple.ini', 'welcome.ini'] files_found = p.read(files) files_missing = set(files) - set(files_found) print('Files found:  ', sorted(files_found)) print('Files missing:  ', sorted(files_missing))

运行上述脚本,您将获得以下输出:

$ python3 read_many_config_file.py  Output Files found:   ['read_simple.ini'] Files missing:   ['bye.ini', 'hello.ini', 'welcome.ini']

在上面的示例中,我们使用了 Python 的configparser模块,该模块有助于管理配置文件。首先,我们创建了一个名为files的列表。read()函数将读取配置文件。在示例中,我们创建了一个名为files_found的变量,它将存储目录中存在的配置文件的名称。接下来,我们创建了另一个名为files_missing的变量,它将返回目录中不存在的文件名。最后,我们打印存在和缺失的文件名。

向脚本添加日志记录和警告代码

在本节中,我们将学习 Python 的日志记录和警告模块。日志记录模块将跟踪程序中发生的事件。警告模块警告程序员有关语言和库中所做更改的信息。

现在,我们将看一个简单的日志记录示例。我们将编写一个名为logging_example.py的脚本,并在其中编写以下代码:

import logging LOG_FILENAME = 'log.txt' logging.basicConfig(filename=LOG_FILENAME, level=logging.DEBUG,) logging.debug('This message should go to the log file') with open(LOG_FILENAME, 'rt') as f:
 prg = f.read() print('FILE:') print(prg)

运行以下程序:

$ python3 logging_example.py Output: FILE: DEBUG:root:This message should go to the log file

检查hello.py,您会看到在该脚本中打印的调试消息:

$ cat log.txt  Output: DEBUG:root:This message should go to the log file

现在,我们将编写一个名为logging_warnings_codes.py的脚本,并在其中编写以下代码:

import logging import warnings logging.basicConfig(level=logging.INFO,) warnings.warn('This warning is not sent to the logs') logging.captureWarnings(True) warnings.warn('This warning is sent to the logs')

运行以下脚本:

$ python3 logging_warnings_codes.py Output: logging_warnings_codes.py:6: UserWarning: This warning is not sent to the logs
 warnings.warn('This warning is not sent to the logs') WARNING:py.warnings:logging_warnings_codes.py:10: UserWarning: This warning is sent to the logs
 warnings.warn('This warning is sent to the logs')

生成警告

warn()用于生成警告。现在,我们将看一个生成警告的简单示例。编写一个名为generate_warnings.py的脚本,并在其中编写以下代码:

import warnings warnings.simplefilter('error', UserWarning) print('Before') warnings.warn('Write your warning message here') print('After')

如下所示运行脚本:

$ python3 generate_warnings.py Output: Before: Traceback (most recent call last):
 File "generate_warnings.py", line 6, in <module> warnings.warn('Write your warning message here') UserWarning: Write your warning message here

在上面的脚本中,我们通过warn()传递了一个警告消息。我们使用了一个简单的过滤器,以便您的警告将被视为错误,并且程序员将相应地解决该错误。

限制 CPU 和内存使用

在本节中,我们将学习如何限制 CPU 和内存使用。首先,我们将编写一个用于限制 CPU 使用的脚本。创建一个名为put_cpu_limit.py的脚本,并在其中编写以下代码:

import resource import sys import signal import time def time_expired(n, stack):
 print('EXPIRED :', time.ctime()) raise SystemExit('(time ran out)') signal.signal(signal.SIGXCPU, time_expired) # Adjust the CPU time limit soft, hard = resource.getrlimit(resource.RLIMIT_CPU) print('Soft limit starts as  :', soft) resource.setrlimit(resource.RLIMIT_CPU, (10, hard)) soft, hard = resource.getrlimit(resource.RLIMIT_CPU) print('Soft limit changed to :', soft) print() # Consume some CPU time in a pointless exercise print('Starting:', time.ctime()) for i in range(200000):
 for i in range(200000): v = i * i # We should never make it this far print('Exiting :', time.ctime())

如下所示运行上述脚本:

$ python3 put_cpu_limit.py Output: Soft limit starts as  : -1 Soft limit changed to : 10 Starting: Thu Sep  6 16:13:20 2018 EXPIRED : Thu Sep  6 16:13:31 2018 (time ran out)

在上面的脚本中,我们使用setrlimit()来限制 CPU 使用。因此,在我们的脚本中,我们将限制设置为 10 秒。

启动 webbrowser

在本节中,我们将学习 Python 的webbrowser模块。该模块具有在浏览器应用程序中打开 URL 的功能。我们将看一个简单的示例。创建一个名为open_web.py的脚本,并在其中编写以下代码:

import webbrowser webbrowser.open('https://timesofindia.indiatimes.com/world')

如下所示运行脚本:

$ python3 open_web.py Output:
Url mentioned in open() will be opened in your browser.
webbrowser – Command line interface

您还可以通过命令行使用 Python 的webbrowser模块,并且可以使用所有功能。要通过命令行使用webbrowser,运行以下命令:

$ python3 -m webbrowser -n https://www.google.com/

在这里,www.google.com/将在浏览器窗口中打开。您可以使用以下两个选项:

  • -n:打开一个新窗口

  • -t:打开一个新标签

使用 os 模块处理目录和文件

在本节中,我们将学习 Python 的os模块。Python 的os模块有助于实现操作系统任务。如果我们想执行操作系统任务,我们需要导入os模块。

我们将看一些与处理文件和目录相关的示例。

创建和删除目录

在本节中,我们将创建一个脚本,我们将看到可以用于处理文件系统上的目录的函数,其中将包括创建、列出和删除内容。创建一个名为os_dir_example.py的脚本,并在其中编写以下代码:

import os directory_name = 'abcd' print('Creating', directory_name) os.makedirs(directory_name) file_name = os.path.join(directory_name, 'sample_example.txt') print('Creating', file_name) with open(file_name, 'wt') as f:
 f.write('sample example file') print('Cleaning up') os.unlink(file_name) os.rmdir(directory_name)       # Will delete the directory

按以下方式运行脚本:

$ python3 os_dir_example.py Output: Creating abcd Creating abcd/sample_example.txt Cleaning up

使用mkdir()创建目录时,所有父目录必须已经创建。但是,使用makedirs()创建目录时,它将创建任何在路径中提到但不存在的目录。unlink()将删除文件路径,rmdir()将删除目录路径。

检查文件系统的内容

在本节中,我们将使用listdir()列出目录的所有内容。创建一个名为list_dir.py的脚本,并在其中编写以下代码:

import os import sys print(sorted(os.listdir(sys.argv[1])))

按以下方式运行脚本:

$ python3 list_dir.py /home/student/ ['.ICEauthority', '.bash_history', '.bash_logout', '.bashrc', '.cache', '.config', '.gnupg', '.local', '.mozilla', '.pam_environment', '.profile', '.python_history', '.ssh', '.sudo_as_admin_successful', '.viminfo', '1.sh', '1.sh.x', '1.sh.x.c', 'Desktop', 'Documents', 'Downloads', 'Music', 'Pictures', 'Public', 'Templates', 'Videos', 'examples.desktop', 'execute_external_commands.py', 'log.txt', 'numbers.txt', 'python_learning', 'work']

因此,通过使用listdir(),您可以列出文件夹的所有内容。

备份(使用 rsync)

这是系统管理员必须做的最重要的工作。在本节中,我们将学习如何使用rsync进行备份。rsync命令用于在本地和远程复制文件和目录,并使用rsync执行数据备份。为此,我们将编写一个名为take_backup.py的脚本,并在其中编写以下代码:

import os import shutil import time from sh import rsync def check_dir(os_dir):
 if not os.path.exists(os_dir): print (os_dir, "does not exist.") exit(1) def ask_for_confirm():
 ans = input("Do you want to Continue? yes/no\n") global con_exit if ans == 'yes': con_exit = 0 return con_exit elif ans == "no": con_exit = 1 return con_exit else:1 print ("Answer with yes or no.") ask_for_confirm() def delete_files(ending):
 for r, d, f in os.walk(backup_dir): for files in f: if files.endswith("." + ending): os.remove(os.path.join(r, files)) backup_dir = input("Enter directory to backup\n")   # Enter directory name check_dir(backup_dir) print (backup_dir, "saved.") time.sleep(3) backup_to_dir= input("Where to backup?\n") check_dir(backup_to_dir) print ("Doing the backup now!") ask_for_confirm() if con_exit == 1:
 print ("Aborting the backup process!") exit(1) rsync("-auhv", "--delete", "--exclude=lost+found", "--exclude=/sys", "--exclude=/tmp", "--exclude=/proc", "--exclude=/mnt", "--exclude=/dev", "--exclude=/backup", backup_dir, backup_to_dir)

按以下方式运行脚本:

student@ubuntu:~/work$ python3 take_backup.py Output : Enter directory to backup /home/student/work /home/student/work saved. Where to backup? /home/student/Desktop Doing the backup now! Do you want to Continue? yes/no yes

现在,检查Desktop/directory,您将在该目录中看到您的工作文件夹。rsync命令有一些选项,即以下选项:

  • -a:存档

  • -u:更新

  • -h:人类可读格式

  • -v:详细

  • --delete:从接收方删除多余的文件

  • --exclude:排除规则

摘要

在本章中,我们学习了如何自动化常规管理任务。我们学习了通过各种技术接受输入,运行时提示密码,执行外部命令,读取配置文件,在脚本中添加警告,通过脚本和命令行启动webbrowser,使用os模块处理文件和目录以及进行备份。

在下一章中,您将学习更多关于os模块和数据处理的知识。此外,您还将学习tarfile模块以及如何使用它。

问题

  1. 如何使用readline模块?

  2. 用于读取、创建新文件、删除文件、列出当前目录中文件的 Linux 命令是什么?

  3. 有哪些包可用于在 Python 中运行 Linux/Windows 命令?

  4. 如何读取或在配置ini文件中设置新值

  5. 列出用于查找cpu使用情况的库?

  6. 列出接受用户输入的不同方法?

  7. 排序和排序有什么区别?

进一步阅读

第五章:处理文件,目录和数据

系统管理员执行处理各种文件,目录和数据等任务。在本章中,我们将学习os模块。os模块提供了与操作系统交互的功能。Python 程序员可以轻松使用此os模块执行文件和目录操作。os模块为处理文件,路径,目录和数据的程序员提供了工具。

在本章中,您将学习以下内容:

  • 使用 os 模块处理目录

  • 复制,移动,重命名和删除数据

  • 处理路径,目录和文件

  • 比较数据

  • 合并数据

  • 模式匹配文件和目录

  • 元数据:关于数据的数据

  • 压缩和恢复

  • 使用tarfile模块创建 TAR 存档

  • 使用tarfile模块检查 TAR 文件的内容

使用 os 模块处理目录

目录是文件和子目录的集合。os模块提供了各种函数,允许我们与操作系统交互。在本节中,我们将学习一些在处理目录时可以使用的函数。

获取工作目录

要开始处理目录,首先我们将获取当前工作目录的名称。os模块有一个getcwd()函数,使用它我们可以获取当前工作目录。启动python3控制台并输入以下命令以获取目录名称:

$ python3 Python 3.6.5 (default, Apr  1 2018, 05:46:30) [GCC 7.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import os >>> os.getcwd() '/home/student' **>>** 

更改目录

使用os模块,我们可以更改当前工作目录。为此,os模块具有chdir()函数,例如:

>>> os.chdir('/home/student/work') >>> print(os.getcwd()) /home/student/work >>> 

列出文件和目录

在 Python 中列出目录内容很容易。我们将使用os模块,该模块具有一个名为listdir()的函数,该函数将返回工作目录中文件和目录的名称:

>>> os.listdir() ['Public', 'python_learning', '.ICEauthority', '.python_history', 'work', '.bashrc', 'Pictures', '.gnupg', '.cache', '.bash_logout', '.sudo_as_admin_successful', '.bash_history', '.config', '.viminfo', 'Desktop', 'Documents', 'examples.desktop', 'Videos', '.ssh', 'Templates', '.profile', 'dir', '.pam_environment', 'Downloads', '.local', '.dbus', 'Music', '.mozilla'] >>> 

重命名目录

Python 中的os模块具有一个rename()函数,可帮助更改目录的名称:

>>> os.rename('work', 'work1') >>> os.listdir() ['Public', 'work1', 'python_learning', '.ICEauthority', '.python_history', '.bashrc', 'Pictures', '.gnupg', '.cache', '.bash_logout', '.sudo_as_admin_successful', '.bash_history', '.config', '.viminfo', 'Desktop', 'Documents', 'examples.desktop', 'Videos', '.ssh', 'Templates', '.profile', 'dir', '.pam_environment', 'Downloads', '.local', '.dbus', 'Music', '.mozilla'] **>>** 

复制,移动,重命名和删除数据

我们将学习系统管理员在数据上执行的四种基本操作,即复制,移动,重命名和删除。Python 有一个名为shutil的内置模块,可以执行这些任务。使用shutil模块,我们还可以对数据执行高级操作。要在程序中使用shutil模块,只需编写import shutil导入语句。shutil模块提供了一些支持文件复制和删除操作的函数。让我们逐一了解这些操作。

复制数据

在本节中,我们将看到如何使用shutil模块复制文件。为此,首先我们将创建一个hello.py文件并在其中写入一些文本。

hello.py

print ("") print ("Hello World\n") print ("Hello Python\n")

现在,我们将编写将内容复制到shutil_copy_example.py脚本的代码。在其中写入以下内容:

import shutil import os shutil.copy('hello.py', 'welcome.py') print("Copy Successful")

按照以下方式运行脚本:

$ python3 shutil_copy_example.py Output: Copy Successful

检查welcome.py脚本的存在,并且您将发现hello.py的内容已成功复制到welcome.py中。

移动数据

在这里,我们将看到如何移动数据。我们将使用shutil.move()来实现这个目的。shutil.move(source, destination)将文件从源移动到目标。现在,我们将创建一个shutil_move_example.py脚本,并在其中写入以下内容:

import shutil shutil.move('/home/student/sample.txt', '/home/student/Desktop/.')

按照以下方式运行脚本:

$ python3 shutil_move_example.py

在此脚本中,我们要移动的文件是sample.txt,它位于/home/student目录中。/home/student是我们的源文件夹,/home/student/Desktop是我们的目标文件夹。因此,在运行脚本后,sample.txt将从/home/student移动到/home/student/Desktop目录。

重命名数据

在上一节中,我们学习了如何使用shutil.move()将文件从源移动到目标。使用shutil.move(),文件可以被重命名。创建一个shutil_rename_example.py脚本,并在其中写入以下内容:

import shutil shutil.move('hello.py', 'hello_renamed.py')

按照以下方式运行脚本:

$ python3 shutil_rename_example.py

输出:

现在,检查您的文件名是否已重命名为hello_renamed.py

删除数据

我们将学习如何使用 Python 的os模块删除文件和文件夹。os模块的remove()方法将删除一个文件。如果您尝试使用此方法删除目录,它将给出一个OSError。要删除目录,请使用rmdir()

现在,创建一个os_remove_file_directory.py脚本,并在其中写入以下内容:

import os os.remove('sample.txt') print("File removed successfully") os.rmdir('work1') print("Directory removed successfully")

按照以下方式运行脚本:

$ python3 os_remove_file_directory.py Output: File removed successfully Directory removed successfully

处理路径

现在,我们将学习关于os.path()的知识。它用于路径操作。在本节中,我们将看一些os模块为路径名提供的函数。

启动python3控制台:

student@ubuntu:~$ python3
Python 3.6.6 (default, Sep 12 2018, 18:26:19)
[GCC 8.0.1 20180414 (experimental) [trunk revision 259383]] on linux
Type "help", "copyright", "credits" or "license" for more information.
<q>>></q>
  • os.path.absname(path): 返回路径名的绝对版本。
>>> import os >>> os.path.abspath('sample.txt') '/home/student/work/sample.txt'
  • os.path.dirname(path): 返回路径的目录名。
>>> os.path.dirname('/home/student/work/sample.txt') '/home/student/work'
  • os.path.basename(path): 返回路径的基本名称。
>>> os.path.basename('/home/student/work/sample.txt') 'sample.txt'
  • os.path.exists(path): 如果路径指向现有路径,则返回True
>>> os.path.exists('/home/student/work/sample.txt') True
  • os.path.getsize(path): 返回以字节为单位的输入路径的大小。
>>> os.path.getsize('/home/student/work/sample.txt') 39
  • os.path.isfile(path): 检查输入的路径是否为现有文件。如果是文件,则返回True
>>> os.path.isfile('/home/student/work/sample.txt') True
  • os.path.isdir(path): 检查输入的路径是否为现有目录。如果是目录,则返回True
>>> os.path.isdir('/home/student/work/sample.txt') False

比较数据

在这里,我们将学习如何在 Python 中比较数据。我们将使用pandas模块来实现这个目的。

Pandas 是一个开源的数据分析库,提供了易于使用的数据结构和数据分析工具。它使导入和分析数据变得更容易。

在开始示例之前,请确保您的系统上已安装了pandas。您可以按照以下方式安装 pandas:

pip3 install pandas     --- For Python3 
or
 pip install pandas       --- For python2

我们将学习使用 pandas 比较数据的一个例子。首先,我们将创建两个csv文件:student1.csvstudent2.csv。我们将比较这两个csv文件的数据,并且输出应该返回比较结果。创建两个csv文件如下:

创建student1.csv文件内容如下:

Id,Name,Gender,Age,Address 101,John,Male,20,New York 102,Mary,Female,18,London 103,Aditya,Male,22,Mumbai 104,Leo,Male,22,Chicago 105,Sam,Male,21,Paris 106,Tina,Female,23,Sydney

创建student2.csv文件内容如下:

Id,Name,Gender,Age,Address 101,John,Male,21,New York 102,Mary,Female,20,London 103,Aditya,Male,22,Mumbai 104,Leo,Male,23,Chicago 105,Sam,Male,21,Paris 106,Tina,Female,23,Sydney

现在,我们将创建一个compare_data.py脚本,并在其中写入以下内容:

import pandas as pd df1 = pd.read_csv("student1.csv") df2 = pd.read_csv("student2.csv") s1 = set([ tuple(values) for values in df1.values.tolist()]) s2 = set([ tuple(values) for values in df2.values.tolist()]) s1.symmetric_difference(s2) print (pd.DataFrame(list(s1.difference(s2))), '\n') print (pd.DataFrame(list(s2.difference(s1))), '\n')

按照以下方式运行脚本:

$ python3 compare_data.py Output:
 0     1       2   3         4 0  102  Mary  Female  18    London 1  104   Leo    Male  22   Chicago 2  101  John    Male  20  New York

 0     1       2   3         4 0  101  John    Male  21  New York 1  104   Leo    Male  23   Chicago 2  102  Mary  Female  20    London

在前面的例子中,我们正在比较两个csv文件之间的数据:student1.csvstudent2.csv。我们首先将我们的数据帧(df1df2)转换为集合(s1s2)。然后,我们使用symmetric_difference()集合。因此,它将检查s1s2之间的对称差异,然后我们将打印结果。

合并数据

我们将学习如何在 Python 中合并数据。为此,我们将使用 Python 的 pandas 库。为了合并数据,我们将使用在上一节中已创建的两个csv文件,student1.csvstudent2.csv

现在,创建一个merge_data.py脚本,并在其中写入以下代码:

import pandas as pd df1 = pd.read_csv("student1.csv") df2 = pd.read_csv("student2.csv") result = pd.concat([df1, df2]) print(result)

按如下方式运行脚本:

$ python3 merge_data.py Output:
 Id    Name  Gender  Age   Address 0  101    John    Male   20  New York 1  102    Mary  Female   18    London 2  103  Aditya    Male   22    Mumbai 3  104     Leo    Male   22   Chicago 4  105     Sam    Male   21     Paris 5  106    Tina  Female   23    Sydney 0  101    John    Male   21  New York 1  102    Mary  Female   20    London 2  103  Aditya    Male   22    Mumbai 3  104     Leo    Male   23   Chicago 4  105     Sam    Male   21     Paris 5  106    Tina  Female   23    Sydney

模式匹配文件和目录

在本节中,我们将学习有关文件和目录的模式匹配。Python 有glob模块,用于查找与特定模式匹配的文件和目录的名称。

现在,我们将看一个例子。首先,创建一个pattern_match.py脚本,并在其中写入以下内容:

import glob file_match = glob.glob('*.txt') print(file_match) file_match = glob.glob('[0-9].txt') print(file_match) file_match = glob.glob('**/*.txt', recursive=True) print(file_match) file_match = glob.glob('**/', recursive=True) print(file_match)

按照以下方式运行脚本:

$ python3 pattern_match.py Output: ['file1.txt', 'filea.txt', 'fileb.txt', 'file2.txt', '2.txt', '1.txt', 'file.txt'] ['2.txt', '1.txt'] ['file1.txt', 'filea.txt', 'fileb.txt', 'file2.txt', '2.txt', '1.txt', 'file.txt', 'dir1/3.txt', 'dir1/4.txt'] ['dir1/']

在上一个例子中,我们使用了 Python 的glob模块进行模式匹配。glob(路径名)将返回与路径名匹配的名称列表。在我们的脚本中,我们在三个不同的glob()函数中传递了三个路径名。在第一个glob()中,我们传递了路径名*.txt;,这将返回所有具有.txt扩展名的文件名。在第二个glob()中,我们传递了[0-9].txt,这将返回以数字开头的文件名。在第三个glob()中,我们传递了**/*.txt,它将返回文件名以及目录名。它还将返回这些目录中的文件名。在第四个glob()中,我们传递了**/,它将仅返回目录名。

元数据:关于数据的数据

在本节中,我们将学习pyPdf模块,该模块有助于从pdf文件中提取元数据。但首先,什么是元数据?元数据是关于数据的数据。元数据是描述主要数据的结构化信息。元数据是数据的摘要。它包含有关实际数据的基本信息。它有助于找到数据的特定实例。

确保您的目录中有pdf文件,您想从中提取信息。

首先,我们必须安装pyPdf模块,如下所示:

pip install pyPdf

现在,我们将编写一个metadata_example.py脚本,并查看如何从中获取元数据信息。我们将在 Python 2 中编写此脚本:

import pyPdf def main():
 file_name = '/home/student/sample_pdf.pdf' pdfFile = pyPdf.PdfFileReader(file(file_name,'rb')) pdf_data = pdfFile.getDocumentInfo() print ("----Metadata of the file----") for md in pdf_data: print (md+ ":" +pdf_data[md]) if __name__ == '__main__':
 main()

按照以下方式运行脚本:

student@ubuntu:~$ python metadata_example.py ----Metadata of the file---- /Producer:Acrobat Distiller Command 3.0 for SunOS 4.1.3 and later (SPARC) /CreationDate:D:19980930143358

在前面的脚本中,我们使用了 Python 2 的pyPdf模块。首先,我们创建了一个file_name变量,用于存储我们的pdf的路径。使用PdfFileReader(),数据被读取。pdf_data变量将保存有关您的pdf的信息。最后,我们编写了一个 for 循环来获取元数据信息。

压缩和恢复

在本节中,我们将学习shutil模块的make_archive()函数,该函数将压缩整个目录。为此,我们将编写一个compress_a_directory.py脚本,并在其中写入以下内容:

import shutil shutil.make_archive('work', 'zip', 'work/')

按照以下方式运行脚本:

$ python3 compress_a_directory.py

在前面的脚本中,在shutil.make_archive()函数中,我们将第一个参数作为我们压缩文件的名称。zip将是我们的压缩技术。然后,work/将是我们要压缩的目录的名称。

现在,要从压缩文件中恢复数据,我们将使用shutil模块的unpack_archive()函数。创建一个unzip_a_directory.py脚本,并在其中写入以下内容:

import shutil shutil.unpack_archive('work1.zip')

按照以下方式运行脚本:

$ python3 unzip_a_directory.py

现在,检查您的目录。解压目录后,您将获得所有内容。

使用 tarfile 模块创建 TAR 存档

本节将帮助您了解如何使用 Python 的tarfile模块创建 tar 存档。

tarfile模块用于使用gzipbz2压缩技术读取和写入 tar 存档。确保必要的文件和目录存在。现在,创建一个tarfile_example.py脚本,并在其中写入以下内容:

import tarfile tar_file = tarfile.open("work.tar.gz", "w:gz") for name in ["welcome.py", "hello.py", "hello.txt", "sample.txt", "sample1.txt"]:
 tar_file.add(name) tar_file.close()

按照以下方式运行脚本:

$ python3 tarfile_example.py

现在,检查您当前的工作目录;您会看到work.tar.gz已经被创建。

使用 tarfile 模块检查 TAR 文件的内容

在本节中,我们将学习如何在不实际提取 tar 文件的情况下检查已创建的 tar 存档的内容。我们将使用 Python 的tarfile模块进行操作。

创建一个examine_tar_file_content.py脚本,并在其中写入以下内容:

import tarfile tar_file = tarfile.open("work.tar.gz", "r:gz") print(tar_file.getnames())

按照以下方式运行脚本:

$ python3 examine_tar_file_content.py Output: ['welcome.py', 'hello.py', 'hello.txt', 'sample.txt', 'sample1.txt']

在先前的示例中,我们使用了tarfile模块来检查创建的 tar 文件的内容。我们使用了getnames()函数来读取数据。

总结

在本章中,我们学习了处理文件和目录的 Python 脚本。我们还学习了如何使用os模块处理目录。我们学习了如何复制、移动、重命名和删除文件和目录。我们还学习了 Python 中的 pandas 模块,用于比较和合并数据。我们学习了如何创建 tar 文件并使用tarfile模块读取 tar 文件的内容。我们还在搜索文件和目录时进行了模式匹配。

在下一章中,我们将学习tar存档和 ZIP 创建。

问题

  1. 如何处理不同路径,而不考虑不同的操作系统(Windows,Llinux)?

  2. Python 中print()的不同参数是什么?

  3. 在 Python 中,dir()关键字的用途是什么?

  4. pandas中的数据框,系列是什么?

  5. 什么是列表推导?

  6. 我们可以使用集合推导和字典推导吗?如果可以,如何操作?

  7. 如何使用 pandas dataframe 打印第一个/最后一个N行?

  8. 使用列表推导编写一个打印奇数的程序

  9. sys.argv 的类型是什么?

  10. a) 集合

  11. b) 列表

  12. c) 元组

  13. d) 字符串

进一步阅读

第六章:文件存档、加密和解密

在上一章中,我们学习了如何处理文件、目录和数据。我们还学习了tarfile模块。在本章中,我们将学习文件存档、加密和解密。存档在管理文件、目录和数据方面起着重要作用。但首先,什么是存档?存档是将文件和目录存储到单个文件中的过程。Python 有tarfile模块用于创建这样的存档文件。

在本章中,我们将涵盖以下主题:

  • 创建和解压存档

  • Tar 存档

  • ZIP 创建

  • 文件加密和解密

创建和解压存档

在本节中,我们将学习如何使用 Python 的shutil模块创建和解压存档。shutil模块有make_archive()函数,用于创建新的存档文件。使用make_archive(),我们可以存档整个目录及其内容。

创建存档

现在,我们将编写一个名为shutil_make_archive.py的脚本,并在其中编写以下内容:

import tarfile
import shutil
import sys

shutil.make_archive(
 'work_sample', 'gztar',
 root_dir='..',
 base_dir='work',
)
print('Archive contents:')
with tarfile.open('work_sample.tar.gz', 'r') as t_file:
 for names in t_file.getnames():
 print(names)

运行程序,您将得到以下输出:

$ python3 shutil_make_archive.py
Archive contents:
work
work/bye.py
work/shutil_make_archive.py
work/welcome.py
work/hello.py

在前面的例子中,为了创建一个存档文件,我们使用了 Python 的shutiltarfile模块。在shutil.make_archive()中,我们指定了work_sample,这将是存档文件的名称,并且将以gz格式。我们在基本目录属性中指定了我们的工作目录名称。最后,我们打印了已存档的文件的名称。

解压存档

要解压缩存档,shutil模块有unpack_archive()函数。使用此函数,我们可以提取存档文件。我们传递了存档文件名和我们想要提取内容的目录。如果没有传递目录名称,则它将提取内容到您当前的工作目录中。

现在,创建一个名为shutil_unpack_archive.py的脚本,并在其中编写以下代码:

import pathlib
import shutil
import sys
import tempfile
with tempfile.TemporaryDirectory() as d:
 shutil.unpack_archive('work_sample.tar.gz', extract_dir='/home/student/work',)
 prefix_len = len(d) + 1
 for extracted in pathlib.Path(d).rglob('*'):
 print(str(extracted)[prefix_len:])

按照以下方式运行脚本:

student@ubuntu:~/work$ python3 shutil_unpack_archive.py

现在,检查您的work/目录,您将在其中找到work/文件夹,其中将有提取的文件。

Tar 存档

在本节中,我们将学习tarfile模块。我们还将学习如何测试输入的文件名,评估它是否是有效的存档文件。我们将看看如何将新文件添加到已存档的文件中,如何使用tarfile模块读取元数据,以及如何使用extractall()函数从存档中提取文件。

首先,我们将测试输入的文件名是否是有效的存档文件。为了测试这一点,tarfile模块有is_tarfile()函数,它返回一个布尔值。

创建一个名为check_archive_file.py的脚本,并在其中编写以下内容:

import tarfile

for f_name in ['hello.py', 'work.tar.gz', 'welcome.py', 'nofile.tar', 'sample.tar.xz']:
 try:
 print('{:} {}'.format(f_name, tarfile.is_tarfile(f_name)))
 except IOError as err:
 print('{:} {}'.format(f_name, err))

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 check_archive_file.py
hello.py          False
work.tar.gz      True
welcome.py     False
nofile.tar         [Errno 2] No such file or directory: 'nofile.tar'
sample.tar.xz   True

因此,tarfile.is_tarfile()将检查列表中提到的每个文件名。hello.py,welcome.py文件不是 tar 文件,所以我们得到了一个布尔值Falsework.tar.gzsample.tar.xz是 tar 文件,所以我们得到了布尔值True。而我们的目录中没有nofile.tar这样的文件,所以我们得到了一个异常,因为我们在脚本中写了它。

现在,我们将在已创建的存档文件中添加一个新文件。创建一个名为add_to_archive.py的脚本,并在其中编写以下代码:

import shutil
import os
import tarfile
print('creating archive')
shutil.make_archive('work', 'tar', root_dir='..', base_dir='work',)
print('\nArchive contents:')
with tarfile.open('work.tar', 'r') as t_file:
 for names in t_file.getnames():
 print(names)
os.system('touch sample.txt')
print('adding sample.txt')
with tarfile.open('work.tar', mode='a') as t:
 t.add('sample.txt')
print('contents:',)
with tarfile.open('work.tar', mode='r') as t:
 print([m.name for m in t.getmembers()])

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 add_to_archive.py
Output :
creating archive
Archive contents:
work
work/bye.py
work/shutil_make_archive.py
work/check_archive_file.py
work/welcome.py
work/add_to_archive.py
work/shutil_unpack_archive.py
work/hello.py
adding sample.txt
contents:
['work', 'work/bye.py', 'work/shutil_make_archive.py', 'work/check_archive_file.py', 'work/welcome.py', 'work/add_to_archive.py', 'work/shutil_unpack_archive.py', 'work/hello.py', 'sample.txt']

在这个例子中,我们首先使用shutil.make_archive()创建了一个存档文件,然后打印了存档文件的内容。然后我们在下一个语句中创建了一个sample.txt文件。现在,我们想要将sample.txt添加到已创建的work.tar中。在这里,我们使用了追加模式a。接下来,我们再次显示存档文件的内容。

现在,我们将学习如何从存档文件中读取元数据。getmembers()函数将加载文件的元数据。创建一个名为read_metadata.py的脚本,并在其中编写以下内容:

import tarfile
import time
with tarfile.open('work.tar', 'r') as t:
 for file_info in t.getmembers():
 print(file_info.name)
 print("Size   :", file_info.size, 'bytes')
 print("Type   :", file_info.type)
 print()

运行脚本,你将得到以下输出:

student@ubuntu:~/work$ python3 read_metadata.py
Output:
work/bye.py
Size : 30 bytes
Type : b'0' 
work/shutil_make_archive.py
Size : 243 bytes
Type : b'0'
work/check_archive_file.py
Size : 233 bytes
Type : b'0'

work/welcome.py
Size : 48 bytes
Type : b'0'

work/add_to_archive.py
Size : 491 bytes
Type : b'0'

work/shutil_unpack_archive.py
Size : 279 bytes
Type : b'0'

现在,我们将使用extractall()函数从存档中提取内容。为此,创建一个名为extract_contents.py的脚本,并在其中写入以下代码:

import tarfile
import os
os.mkdir('work')
with tarfile.open('work.tar', 'r') as t:
 t.extractall('work')
print(os.listdir('work'))

运行脚本,你将得到以下输出:

student@ubuntu:~/work$ python3 extract_contents.py

检查你的当前工作目录,你会发现work/目录。导航到该目录,你可以找到你提取的文件。

ZIP 创建

在本节中,我们将学习关于 ZIP 文件的知识。我们将学习pythonzipfile模块,如何创建 ZIP 文件,如何测试输入的文件名是否是有效的zip文件名,读取元数据等等。

首先,我们将学习如何使用shutil模块的make_archive()函数创建一个zip文件。创建一个名为make_zip_file.py的脚本,并在其中写入以下代码:

import shutil
shutil.make_archive('work', 'zip', 'work')

按如下方式运行脚本:

student@ubuntu:~$ python3 make_zip_file.py

现在检查你的当前工作目录,你会看到work.zip

现在,我们将测试输入的文件名是否是一个zip文件。为此,zipfile模块有is_zipfile()函数。

创建一个名为check_zip_file.py的脚本,并在其中写入以下内容:

import zipfile
for f_name in ['hello.py', 'work.zip', 'welcome.py', 'sample.txt', 'test.zip']:
 try:
 print('{:}           {}'.format(f_name, zipfile.is_zipfile(f_name)))
 except IOError as err:
 print('{:}           {}'.format(f_name, err))

按如下方式运行脚本:

student@ubuntu:~$ python3 check_zip_file.py
Output :
hello.py          False
work.zip         True
welcome.py     False
sample.txt       False
test.zip            True

在这个例子中,我们使用了一个for循环,我们在其中检查列表中的文件名。is_zipfile()函数将逐个检查文件名,并将布尔值作为结果。

现在,我们将看看如何使用 Python 的zipfile模块从存档的 ZIP 文件中读取元数据。创建一个名为read_metadata.py的脚本,并在其中写入以下内容:

import zipfile

def meta_info(names):
 with zipfile.ZipFile(names) as zf:
 for info in zf.infolist():
 print(info.filename)
 if info.create_system == 0:
 system = 'Windows'
 elif info.create_system == 3:
 system = 'Unix'
 else:
 system = 'UNKNOWN'
 print("System         :", system)
 print("Zip Version    :", info.create_version)
 print("Compressed     :", info.compress_size, 'bytes')
 print("Uncompressed   :", info.file_size, 'bytes')
 print()

if __name__ == '__main__':
 meta_info('work.zip')

按如下方式执行脚本:

student@ubuntu:~$ python3 read_metadata.py
Output:
sample.txt
System         : Unix
Zip Version    : 20
Compressed     : 2 bytes
Uncompressed   : 0 bytes

bye.py
System         : Unix
Zip Version    : 20
Compressed     : 32 bytes
Uncompressed   : 30 bytes

extract_contents.py
System         : Unix
Zip Version    : 20
Compressed     : 95 bytes
Uncompressed   : 132 bytes

shutil_make_archive.py
System         : Unix
Zip Version    : 20
Compressed     : 160 bytes
Uncompressed   : 243 bytes

为了获取zip文件的元数据信息,我们使用了ZipFile类的infolist()方法。

文件加密和解密

在本节中,我们将学习 Python 的pyAesCrypt模块。pyAesCrypt是一个文件加密模块,它使用AES256-CBC来加密/解密文件和二进制流。

按如下方式安装pyAesCrypt

pip3 install pyAesCrypt

创建一个名为file_encrypt.py的脚本,并在其中写入以下代码:

import pyAesCrypt

from os import stat, remove
# encryption/decryption buffer size - 64K
bufferSize = 64 * 1024
password = "#Training"
with open("sample.txt", "rb") as fIn:
 with open("sample.txt.aes", "wb") as fOut:
 pyAesCrypt.encryptStream(fIn, fOut, password, bufferSize)
# get encrypted file size
encFileSize = stat("sample.txt.aes").st_size 

按如下方式运行脚本:

student@ubuntu:~/work$ python3 file_encrypt.py
Output :

请检查你的当前工作目录。你会在其中找到加密文件sample.txt.aes

在这个例子中,我们已经提到了缓冲区大小和密码。接下来,我们提到了要加密的文件名。在encryptStream中,我们提到了fIn,这是我们要加密的文件,以及fOut,这是我们加密后的文件名。我们将加密后的文件存储为sample.txt.aes

现在,我们将解密sample.txt.aes文件以获取文件内容。创建一个名为file_decrypt.py的脚本,并在其中写入以下内容:

import pyAesCrypt
from os import stat, remove
bufferSize = 64 * 1024
password = "#Training"
encFileSize = stat("sample.txt.aes").st_size
with open("sample.txt.aes", "rb") as fIn:
 with open("sampleout.txt", "wb") as fOut:
 try:
 pyAesCrypt.decryptStream(fIn, fOut, password, bufferSize, encFileSize)
 except ValueError:
 remove("sampleout.txt")

按如下方式运行脚本:

student@ubuntu:~/work$ python3 file_decrypt.py

现在,检查你的当前工作目录。将会创建一个名为sampleout.txt的文件。那就是你的解密文件。

在这个例子中,我们提到了要解密的文件名,即sample.txt.aes。接下来,我们的解密文件将是sampleout.txt。在decryptStream()中,我们提到了fIn,这是我们要解密的文件,以及fOut,这是解密文件的名称。

总结

在本章中,我们学习了如何创建和提取存档文件。存档在管理文件、目录和数据方面起着重要作用。它还将文件和目录存储到一个单一文件中。

我们详细学习了 Python 模块tarfilezipfile,它们使你能够创建、提取和测试存档文件。你将能够将一个新文件添加到已存档的文件中,读取元数据,从存档中提取文件。你还学习了使用pyAescrypt模块进行文件加密和解密。

在下一章中,你将学习 Python 中的文本处理和正则表达式。Python 有一个非常强大的库叫做正则表达式,它可以执行搜索和提取数据等任务。

问题

  1. 我们能使用密码保护来压缩数据吗?如果可以,怎么做?

  2. 什么是 Python 中的上下文管理器?

  3. 什么是 pickling 和 unpickling?

  4. Python 中有哪些不同类型的函数?

进一步阅读

第七章:文本处理和正则表达式

在本章中,我们将学习有关文本处理和正则表达式的知识。文本处理是创建或修改文本的过程。Python 有一个非常强大的名为正则表达式的库,可以执行搜索和提取数据等任务。您将学习如何在文件中执行此操作,还将学习读取和写入文件。

我们将学习有关 Python 正则表达式和处理文本的re模块。我们将学习re模块的match()search()findall()sub()函数。我们还将学习使用textwrap模块在 Python 中进行文本包装。最后,我们将学习有关 Unicode 字符。

在本章中,我们将涵盖以下主题:

  • 文本包装

  • 正则表达式

  • Unicode 字符串

文本包装

在本节中,我们将学习有关textwrap Python 模块。该模块提供了执行所有工作的TextWrapper类。textwrap模块用于格式化和包装纯文本。该模块提供了五个主要函数:wrap()fill()dedent()indent()shorten()。我们现在将逐一学习这些函数。

wrap()函数

wrap()函数用于将整个段落包装成单个字符串。输出将是输出行的列表。

语法是textwrap.wrap(text, width)

  • text:要包装的文本。

  • width:包装行的最大长度。默认值为70

现在,我们将看到wrap()的一个示例。创建一个wrap_example.py脚本,并在其中写入以下内容:

import textwrap

sample_string = '''Python is an interpreted high-level programming language for general-purpose programming. Created by Guido van Rossum and first released in 1991, Python has a design philosophy that emphasizes code readability, notably using significant whitespace.'''

w = textwrap.wrap(text=sample_string, width=30)
print(w)

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 wrap_example.py
['Python is an interpreted high-', 'level programming language for', 'general-purpose programming.', 'Created by Guido van Rossum', 'and first released in', '1991, Python has a design', 'philosophy that emphasizes', 'code readability,  notably', 'using significant whitespace.']

在前面的示例中,我们使用了 Python 的textwrap模块。首先,我们创建了一个名为sample_string的字符串。接下来,使用TextWrapper类指定了宽度。然后,使用wrap函数将字符串包装到宽度为30。然后,我们打印了这些行。

fill()函数

fill()函数与textwrap.wrap类似,只是它返回连接成单个以换行符分隔的字符串的数据。此函数将文本包装并返回包含包装文本的单个字符串。

此函数的语法是:

textwrap.fill(text, width)
  • text:要包装的文本。

  • width:包装行的最大长度。默认值为70

现在,我们将看到fill()的一个示例。创建一个fill_example.py脚本,并在其中写入以下内容:

import textwrap  sample_string = '''Python is an interpreted high-level programming language.'''  w = textwrap.fill(text=sample_string, width=50) print(w)

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 fill_example.py
Python is an interpreted high-level programming
language.

在前面的示例中,我们使用了fill()函数。过程与我们在wrap()中所做的相同。首先,我们创建了一个字符串变量。接下来,我们创建了textwrap对象。然后,我们应用了fill()函数。最后,我们打印了输出。

dedent()函数

dedent()textwrap模块的另一个函数。此函数从文本的每一行中删除常见的前导空格

此函数的语法如下:

 textwrap.dedent(text)

text是要dedent的文本。

现在,我们将看到dedent()的一个示例。创建一个dedent_example.py脚本,并在其中写入以下内容:

import textwrap  str1 = ''' Hello Python World \tThis is Python 101 Scripting language\n Python is an interpreted high-level programming language for general-purpose programming. ''' print("Original: \n", str1) print()  t = textwrap.dedent(str1) print("Dedented: \n", t)

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 dedent_example.py 
Hello Python World   This is Python 101
Scripting language

Python is an interpreted high-level programming language for general-purpose programming.

在前面的示例中,我们创建了一个str1字符串变量。然后我们使用textwrap.dedent()来删除常见的前导空格。制表符和空格被视为空格,但它们不相等。因此,唯一的常见空格,在我们的情况下是tab,被移除。

indent()函数

indent()函数用于在文本的选定行开头添加指定的前缀。

此函数的语法是:

 textwrap.indent(text, prefix)
  • text:主字符串

  • prefix:要添加的前缀

创建一个indent_example.py脚本,并在其中写入以下内容:

import textwrap  str1 = "Python is an interpreted high-level programming language for general-purpose programming. Created by Guido van Rossum and first released in 1991, \n\nPython has a design philosophy that emphasizes code readability, notably using significant whitespace."  w = textwrap.fill(str1, width=30) i = textwrap.indent(w, '*') print(i)

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 indent_example.py *Python is an interpreted high- *level programming language for *general-purpose programming. *Created by Guido van Rossum *and first released in 1991, *Python has a design philosophy *that emphasizes code *readability, notably using *significant whitespace.

在上面的示例中,我们使用了textwrap模块的fill()indent()函数。首先,我们使用fill方法将数据存储到变量w中。接下来,我们使用了indent方法。使用indent(),输出中的每一行都将有一个*前缀。然后,我们打印了输出。

shorten()函数

textwrap模块的这个函数用于将文本截断以适应指定的宽度。例如,如果您想要创建摘要或预览,请使用shorten()函数。使用shorten(),文本中的所有空格将被标准化为单个空格。

此函数的语法是:

            textwrap.shorten(text, width)

现在我们将看一个shorten()的例子。创建一个shorten_example.py脚本,并在其中写入以下内容:

import textwrap str1 = "Python is an interpreted high-level programming language for general-purpose programming. Created by Guido van Rossum and first released in 1991, \n\nPython has a design philosophy that emphasizes code readability, notably using significant whitespace." s = textwrap.shorten(str1, width=50) print(s)

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 shorten_example.py Python is an interpreted high-level [...]

在上面的示例中,我们使用了shorten()函数来截断我们的文本,并将该文本适应指定的宽度。首先,所有空格都被截断为单个空格。如果结果适合指定的宽度,则结果将显示在屏幕上。如果不适合,则指定宽度的单词将显示在屏幕上,其余部分将放在占位符中。

正则表达式

在本节中,我们将学习 Python 中的正则表达式。正则表达式是一种专门的编程语言,它嵌入在 Python 中,并通过re模块提供给用户使用。我们可以定义要匹配的字符串集的规则。使用正则表达式,我们可以从文件、代码、文档、电子表格等中提取特定信息。

在 Python 中,正则表达式表示为re,可以通过re模块导入。正则表达式支持四种功能:

  • 标识符

  • 修饰符

  • 空白字符

  • 标志

下表列出了标识符,并对每个标识符进行了描述:

标识符 描述
\w 匹配字母数字字符,包括下划线(_)
\W 匹配非字母数字字符,不包括下划线(_)
\d 匹配数字
\D 匹配非数字
\s 匹配空格
\S 匹配除空格之外的任何字符
. 匹配句号(.)
\b 匹配除换行符之外的任何字符

下表列出了修饰符,并对每个修饰符进行了描述:

修饰符 描述
^ 匹配字符串的开头
` 修饰符
--- ---
^ 匹配字符串的开头
匹配字符串的结尾
? 匹配01
* 匹配0或更多
+ 匹配1或更多
&#124; 匹配x/y中的任意一个
[ ] 匹配范围
{x} 前置代码的数量

下表列出了空白字符,并对每个字符进行了描述:

字符 描述
\s 空格
\t 制表符
\n 换行
\e 转义
\f 换页符
\r 回车

下表列出了标志,并对每个标志进行了描述:

标志 描述
re.IGNORECASE 不区分大小写匹配
re.DOTALL 匹配包括换行符在内的任何字符
re.MULTILINE 多行匹配
Re.ASCII 仅使转义匹配 ASCII 字符

现在我们将看一些正则表达式的示例。我们将学习match()search()findall()sub()函数。

要在 Python 中使用正则表达式,必须在脚本中导入re模块,以便能够使用正则表达式的所有函数和方法。

现在我们将逐一学习这些功能。

match()函数

match()函数是re模块的一个函数。此函数将使用指定的re模式与字符串匹配。如果找到匹配项,将返回一个match对象。match对象将包含有关匹配的信息。如果找不到匹配项,我们将得到结果为Nonematch对象有两种方法:

  • group(num): 返回整个匹配

  • groups(): 返回一个元组中的所有匹配子组

这个函数的语法如下:

re.match(pattern, string)

现在,我们要看一个re.match()的例子。创建一个re_match.py脚本,并在其中写入以下内容:

import re  str_line = "This is python tutorial. Do you enjoy learning python ?" obj = re.match(r'(.*) enjoy (.*?) .*', str_line) if obj:
 print(obj.groups())

运行脚本,你会得到以下输出:

student@ubuntu:~/work$ python3 re_match.py
('This is python tutorial. Do you', 'learning')

在前面的脚本中,我们导入了re模块以在 Python 中使用正则表达式。然后我们创建了一个str_line字符串。接下来,我们创建了一个obj匹配对象,并将匹配模式的结果存储在其中。在这个例子中,(.*) enjoy (.*?) .*模式将打印enjoy关键字之前的所有内容,并且只会打印enjoy关键字之后的一个单词。接下来,我们使用了match对象的groups()方法。它将以元组的形式打印所有匹配的子字符串。因此,你将得到的输出是,('This is python tutorial. Do you', 'learning')

search()函数

re模块的search()函数将在字符串中搜索。它将寻找指定的re模式的任何位置。search()将接受一个模式和文本,并在我们指定的字符串中搜索匹配项。当找到匹配项时,它将返回一个match对象。如果找不到匹配项,它将返回Nonematch对象有两个方法:

  • group(num): 返回整个匹配

  • groups(): 返回一个元组中的所有匹配子组

这个函数的语法如下:

re.search(pattern, string)

创建一个re_search.py脚本,并在其中写入以下内容:

import re pattern = ['programming', 'hello'] str_line = 'Python programming is fun' for p in pattern:
 print("Searching for %s in %s" % (p, str_line)) if re.search(p, str_line): print("Match found") else: print("No match found")

运行脚本,你会得到以下输出:

student@ubuntu:~/work$ python3 re_search.py Searching for programming in Python programming is fun Match found Searching for hello in Python programming is fun No match found

在前面的例子中,我们使用了match对象的search()方法来查找re模式。在导入 re 模块之后,我们在列表中指定了模式。在那个列表中,我们写了两个字符串:programminghello。接下来,我们创建了一个字符串:Python programming is fun。我们写了一个 for 循环,它将逐个检查指定的模式。如果找到匹配项,将执行if块。如果找不到匹配项,将执行else块。

findall()函数

这是match对象的方法之一。findall()方法找到所有匹配项,然后将它们作为字符串列表返回。列表的每个元素表示一个匹配项。此方法搜索模式而不重叠。

创建一个re_findall_example.py脚本,并在其中写入以下内容:

import re pattern = 'Red' colors = 'Red, Blue, Black, Red, Green' p = re.findall(pattern, colors) print(p) str_line = 'Peter Piper picked a peck of pickled peppers. How many pickled peppers did Peter Piper pick?' pt = re.findall('pe\w+', str_line) pt1 = re.findall('pic\w+', str_line) print(pt) print(pt1) line = 'Hello hello HELLO bye' p = re.findall('he\w+', line, re.IGNORECASE) print(p)

运行脚本,你会得到以下输出:

student@ubuntu:~/work$ python3 re_findall_example.py
['Red', 'Red']
['per', 'peck', 'peppers', 'peppers', 'per']
['picked', 'pickled', 'pickled', 'pick']
['Hello', 'hello', 'HELLO']

在前面的脚本中,我们写了findall()方法的三个例子。在第一个例子中,我们定义了一个模式和一个字符串。我们使用findall()方法从字符串中找到该模式,然后打印它。在第二个例子中,我们创建了一个字符串,然后使用findall()找到前两个字母是pe的单词,并打印它们。我们将得到前两个字母是pe的单词列表。

此外,我们找到了前三个字母是pic的单词,然后打印它们。在这里,我们也会得到字符串列表。在第三个例子中,我们创建了一个字符串,在其中我们指定了大写和小写的hello,还有一个单词:bye。使用findall(),我们找到了前两个字母是he的单词。同样在findall()中,我们使用了一个re.IGNORECASE标志,它会忽略单词的大小写并打印它们。

sub()函数

这是 re 模块中最重要的函数之一。sub()用于用指定的替换字符串替换re模式。它将用替换字符串替换re模式的所有出现。语法如下:

   re.sub(pattern, repl_str, string, count=0)
  • pattern: re模式。

  • repl_str: 替换字符串。

  • string: 主字符串。

  • count: 要替换的出现次数。默认值为0,表示替换所有出现。

现在我们要创建一个re_sub.py脚本,并在其中写入以下内容:

import re

str_line = 'Peter Piper picked a peck of pickled peppers. How many pickled peppers did Peter Piper pick?'

print("Original: ", str_line)
p = re.sub('Peter', 'Mary', str_line)
print("Replaced: ", p)

p = re.sub('Peter', 'Mary', str_line, count=1)
print("Replacing only one occurrence of Peter… ")
print("Replaced: ", p)

运行脚本,你会得到以下输出:

student@ubuntu:~/work$ python3 re_sub.py
Original:  Peter Piper picked a peck of pickled peppers. How many pickled peppers did Peter Piper pick?
Replaced:  Mary Piper picked a peck of pickled peppers. How many pickled peppers did Mary Piper pick?
Replacing only one occurrence of Peter...
Replaced:  Mary Piper picked a peck of pickled peppers. How many pickled peppers did Peter Piper pick?

在上面的例子中,我们使用sub()来用指定的替换字符串替换re模式。我们用 Mary 替换了 Peter。所以,所有的 Peter 都将被替换为 Mary。接下来,我们还包括了count参数。我们提到了count=1:这意味着只有一个 Peter 的出现将被替换,其他的 Peter 的出现将保持不变。

现在,我们将学习 re 模块的subn()函数。subn()函数与sub()的功能相同,但还有额外的功能。subn()函数将返回一个包含新字符串和执行的替换次数的元组。让我们看一个subn()的例子。创建一个re_subn.py脚本,并在其中写入以下内容:

import re

print("str1:- ")
str1 = "Sky is blue. Sky is beautiful."

print("Original: ", str1)
p = re.subn('beautiful', 'stunning', str1)
print("Replaced: ", p)
print()

print("str_line:- ")
str_line = 'Peter Piper picked a peck of pickled peppers. How many pickled peppers did Peter Piper pick?'

print("Original: ", str_line)
p = re.subn('Peter', 'Mary', str_line)
print("Replaced: ", p)

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 re_subn.py
str1:-
Original:  Sky is blue. Sky is beautiful.
Replaced:  ('Sky is blue. Sky is stunning.', 1)

str_line:-
Original:  Peter Piper picked a peck of pickled peppers. How many pickled peppers did Peter Piper pick?
Replaced:  ('Mary Piper picked a peck of pickled peppers. How many pickled peppers did Mary Piper pick?', 2)

在上面的例子中,我们使用了subn()函数来替换 RE 模式。结果,我们得到了一个包含替换后的字符串和替换次数的元组。

Unicode 字符串

在本节中,我们将学习如何在 Python 中打印 Unicode 字符串。Python 以一种非常简单的方式处理 Unicode 字符串。字符串类型实际上保存的是 Unicode 字符串,而不是字节序列。

在您的系统中启动python3控制台,并开始编写以下内容:

student@ubuntu:~/work$ python3
Python 3.6.6 (default, Sep 12 2018, 18:26:19)
[GCC 8.0.1 20180414 (experimental) [trunk revision 259383]] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 
>>> print ('\u2713')

>>> print ('\u2724')

>>> print ('\u2750')

>>> print ('\u2780')

>>> chinese = '\u4e16\u754c\u60a8\u597d!
>>> chinese
![](https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/ms-py-sc-sys-adm/img/5088de25-a7d1-4cde-8821-03151178533d.png) ----- (Meaning “Hello world!”)
>>>
>>> s = '\u092E\u0941\u0902\u092C\u0908'
>>> s
'मुंबई'                            ------(Unicode translated in Marathi)
>>>
>>> s = '\u10d2\u10d0\u10db\u10d0\u10e0\u10ef\u10dd\u10d1\u10d0'
>>> s
'გამარჯობა'                 ------(Meaning “Hello” in Georgian)
>>>
>>> s = '\u03b3\u03b5\u03b9\u03b1\u03c3\u03b1\u03c2'
>>> s
'γειασας'                     ------(Meaning “Hello” in Greek)
>>> 

Unicode 代码点

在本节中,我们将学习 Unicode 代码点。Python 有一个强大的内置函数ord(),用于从给定字符获取 Unicode 代码点。因此,让我们看一个从字符获取 Unicode 代码点的例子,如下所示:

>>> str1 = u'Office'
>>> for char in str1:
... print('U+%04x' % ord(char))
...
U+004f
U+0066
U+0066
U+0069
U+0063
U+0065
>>> str2 = ![](https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/ms-py-sc-sys-adm/img/89322582-8eec-4421-a610-31da6e1876bf.png)
>>> for char in str2:
... print('U+%04x' % ord(char))
...
U+4e2d
U+6587

编码

从 Unicode 代码点到字节字符串的转换称为编码。因此,让我们看一个将 Unicode 代码点编码的例子,如下所示:

>>> str = u'Office'
>>> enc_str = type(str.encode('utf-8'))
>>> enc_str
<class 'bytes'>

解码

从字节字符串到 Unicode 代码点的转换称为解码。因此,让我们看一个将字节字符串解码为 Unicode 代码点的例子,如下所示:

>>> str = bytes('Office', encoding='utf-8')
>>> dec_str = str.decode('utf-8')
>>> dec_str
'Office'

避免 UnicodeDecodeError

每当字节字符串无法解码为 Unicode 代码点时,就会发生UnicodeDecodeError。为了避免这种异常,我们可以在decodeerror参数中传递replacebackslashreplaceignore,如下所示:

>>> str = b"\xaf"
>>> str.decode('utf-8', 'strict')
 Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xaf in position 0: invalid start byte

>>> str.decode('utf-8', "replace")
'\ufffd'
>>> str.decode('utf-8', "backslashreplace")
'\\xaf'
>>> str.decode('utf-8', "ignore")
' '

摘要

在本章中,我们学习了正则表达式,使用它可以定义一组我们想要匹配的字符串的规则。我们学习了re模块的四个函数:match()search()findall()sub()

我们学习了textwrap模块,它用于格式化和包装纯文本。我们还学习了textwrap模块的wrap()fill()dedent()indent()shorten()函数。最后,我们学习了 Unicode 字符以及如何在 Python 中打印 Unicode 字符串。

在下一章中,我们将学习如何使用 Python 对信息进行标准文档化和报告。

问题

  1. Python 中的正则表达式是什么?

  2. 编写一个 Python 程序来检查一个字符串是否只包含某个字符集(在本例中为a–zA–Z0–9)。

  3. Python 中的哪个模块支持正则表达式?

a) re

b) regex

c) pyregex

d) 以上都不是

  1. re.match函数的作用是什么?

a) 在字符串的开头匹配模式

b) 在字符串的任何位置匹配模式

c) 这样的函数不存在

d) 以上都不是

  1. 以下的输出是什么?

句子:"we are humans"

匹配:re.match(r'(.*) (.*?) (.*)', sentence)

print(matched.group())

a) ('we', 'are', 'humans')

b) (we, are, humans)

c) ('we', 'humans')

d) 'we are humans'

进一步阅读

第八章:文档和报告

在本章中,您将学习如何使用 Python 记录和报告信息。您还将学习如何使用 Python 脚本获取输入以及如何打印输出。在 Python 中编写接收电子邮件的脚本更容易。您将学习如何格式化信息。

在本章中,您将学习以下内容:

  • 标准输入和输出

  • 信息格式化

  • 发送电子邮件

标准输入和输出

在本节中,我们将学习 Python 中的输入和输出。我们将学习stdinstdout,以及input()函数。

stdinstdout是类似文件的对象。这些对象由操作系统提供。每当用户在交互会话中运行程序时,stdin充当输入,stdout将是用户的终端。由于stdin是类似文件的对象,我们必须从stdin读取数据而不是在运行时读取数据。stdout用于输出。它用作表达式和print()函数的输出,以及input()函数的提示。

现在,我们将看一个stdinstdout的例子。为此,请创建一个名为stdin_stdout_example.py的脚本,并在其中写入以下内容:

import sys print("Enter number1: ") a = int(sys.stdin.readline()) print("Enter number2: ") b = int(sys.stdin.readline()) c = a + b sys.stdout.write("Result: %d " % c)

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 stdin_stdout_example.py Enter number1: 10 Enter number2: 20 Result: 30

在上面的例子中,我们使用了stdinstdout来获取输入和显示输出。sys.stdin.readline()将从stdin读取数据。将写入数据。

现在,我们将学习input()print()函数。input()函数用于从用户那里获取输入。该函数有一个可选参数:提示字符串。

语法:

 input(prompt)

input()函数返回一个字符串值。如果您想要一个数字值,只需在input()之前写入int关键字。您可以这样做:

 int(input(prompt))

同样,您可以为浮点值写入float。现在,我们将看一个例子。创建一个input_example.py脚本,并在其中写入以下代码:

str1 = input("Enter a string: ") print("Entered string is: ", str1) print() a = int(input("Enter the value of a: ")) b = int(input("Enter the value of b: ")) c = a + b print("Value of c is: ", c) print() num1 = float(input("Enter num 1: ")) num2 = float(input("Enter num 2: ")) num3 = num1/num2 print("Value of num 3 is: ", num3)

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 input_example.py Output: Enter a string: Hello Entered string is:  Hello Enter the value of a: 10 Enter the value of b: 20 Value of c is:  30Enter num 1: 10.50 Enter num 2: 2.0 Value of num 3 is:  5.25

在上面的例子中,我们使用input()函数获取了三个不同的值。首先是字符串,第二个是整数值,第三个是float值。要将input()用于整数和浮点数,我们必须使用int()float()类型转换函数将接收到的字符串转换为整数和浮点数。

现在,print()函数用于输出数据。我们必须输入一个以逗号分隔的参数列表。在input_example.py中,我们使用了print()函数来获取输出。使用print()函数,您可以通过将数据括在""''中简单地将数据写入屏幕上。要仅访问值,只需在print()函数中写入变量名。如果您想在同一个print()函数中写一些文本并访问一个值,那么请用逗号将这两者分开。

我们将看一个print()函数的简单例子。创建一个print_example.py脚本,并在其中写入以下内容:

# printing a simple string on the screen. print("Hello Python") # Accessing only a value. a = 80 print(a)  # printing a string on screen as well as accessing a value. a = 50 b = 30 c = a/b print("The value of c is: ", c)

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 print_example.py Hello Python 80 The value of c is:  1.6666666666666667

在上面的例子中,首先我们简单地在屏幕上打印了一个字符串。接下来,我们只是访问了a的值并将其打印在屏幕上。最后,我们输入了ab的值,然后将它们相加并将结果存储在变量c中,然后我们打印了一个语句并从同一个print()函数中访问了一个值。

信息格式化

在本节中,我们将学习字符串格式化。我们将学习两种格式化信息的方法:一种是使用字符串format()方法,另一种是使用%运算符。

首先,我们将学习使用字符串format()方法进行字符串格式化。string类的这种方法允许我们进行值格式化。它还允许我们进行变量替换。这将通过位置参数连接元素。

现在,我们将学习如何使用格式化程序进行格式化。调用此方法的字符串可以包含文字或由大括号{}分隔的替换字段。在格式化字符串时可以使用多对{}。此替换字段包含参数的索引或参数的名称。结果,您将获得一个字符串副本,其中每个替换字段都替换为参数的字符串值。

现在,我们将看一个字符串格式化的例子。

创建一个format_example.py脚本,并在其中写入以下内容:

# Using single formatter print("{}, My name is John".format("Hi")) str1 = "This is John. I am learning {} scripting language." print(str1.format("Python")) print("Hi, My name is Sara and I am {} years old !!".format(26)) # Using multiple formatters str2 = "This is Mary {}. I work at {} Resource department. I am {} years old !!" print(str2.format("Jacobs", "Human", 30)) print("Hello {}, Nice to meet you. I am {}.".format("Emily", "Jennifer"))

按以下方式运行脚本:

student@ubuntu:~/work$ python3 format_example.py Output: Hi, My name is John This is John. I am learning Python scripting language. Hi, My name is Sara and I am 26 years old !! This is Mary Jacobs. I work at Human Resource department. I am 30 years old !! Hello Emily, Nice to meet you. I am Jennifer.

在前面的例子中,我们使用string类的format()方法进行了字符串格式化,使用了单个和多个格式化程序。

现在,我们将学习如何使用运算符进行字符串格式化。运算符与格式符一起使用。以下是一些常用的符号:

  • %d:十进制整数

  • %s:字符串

  • %f:浮点数

  • %c:字符

现在,我们将看一个例子。创建一个string_formatting.py脚本,并在其中写入以下内容:

# Basic formatting a = 10 b = 30 print("The values of a and b are %d %d" % (a, b)) c = a + b print("The value of c is %d" % c) str1 = 'John' print("My name is %s" % str1)  x = 10.5 y = 33.5 z = x * y print("The value of z is %f" % z) print() # aligning name = 'Mary' print("Normal: Hello, I am %s !!" % name) print("Right aligned: Hello, I am %10s !!" % name) print("Left aligned: Hello, I am %-10s !!" % name) print() # truncating print("The truncated string is %.4s" % ('Examination')) print() # formatting placeholders students = {'Name' : 'John', 'Address' : 'New York'} print("Student details: Name:%(Name)s Address:%(Address)s" % students) 

运行脚本,您将获得以下输出:

student@ubuntu:~/work$ python3 string_formatting.py The values of a and b are 10 30 The value of c is 40 My name is John The value of z is 351.750000Normal: Hello, I am Mary !! Right aligned: Hello, I am       Mary !! Left aligned: Hello, I am Mary       !!
The truncated string is Exam
Student details: Name:John Address:New York

在前面的例子中,我们使用运算符来格式化字符串:%d表示数字,%s表示字符串,%f表示浮点数。然后,我们将字符串左对齐和右对齐。我们还学会了如何使用运算符截断字符串。%.4s将仅显示前四个字符。接下来,我们创建了一个名为students的字典,并输入了NameAddress键值对。然后,我们在运算符后放置了我们的键名以获取字符串。

发送电子邮件

在本节中,我们将学习如何通过 Python 脚本从 Gmail 发送电子邮件。为此,Python 有一个名为smtplib的模块。Python 中的smtplib模块提供了用于向具有 SMTP 侦听器的任何互联网机器发送电子邮件的 SMTP 客户端会话对象。

我们将看一个例子。在这个例子中,我们将从 Gmail 向接收者发送包含简单文本的电子邮件。

创建一个send_email.py脚本,并在其中写入以下内容:

import smtplib from email.mime.text import MIMEText import getpass host_name = 'smtp.gmail.com' port = 465 u_name = 'username/emailid' password = getpass.getpass() sender = 'sender_name' receivers = ['receiver1_email_address', 'receiver2_email_address'] text = MIMEText('Test mail') text['Subject'] = 'Test' text['From'] = sender text['To'] = ', '.join(receivers) s_obj = smtplib.SMTP_SSL(host_name, port) s_obj.login(u_name, password) s_obj.sendmail(sender, receivers, text.as_string()) s_obj.quit() print("Mail sent successfully")

按以下方式运行脚本:

student@ubuntu:~/work$ python3 send_text.py

输出:

Password: Mail sent successfully

在前面的例子中,我们从我们的 Gmail ID 向接收者发送了一封电子邮件。用户名变量将存储您的电子邮件 ID。在密码变量中,您可以输入密码,或者您可以使用getpass模块提示密码。在这里,我们提示输入密码。接下来,发件人变量将有您的名字。现在,我们将向多个接收者发送此电子邮件。然后,我们为该电子邮件包括了主题,发件人和收件人。然后在login()中,我们提到了我们的用户名和密码变量。接下来,在sendmail()中,我们提到了发件人,接收者和文本变量。因此,使用此过程,我们成功发送了电子邮件。

现在,我们将看一个发送带附件的电子邮件的例子。在这个例子中,我们将向收件人发送一张图片。我们将通过 Gmail 发送此邮件。创建一个send_email_attachment.py脚本,并在其中写入以下内容:

import os import smtplib from email.mime.text import MIMEText from email.mime.image import MIMEImage from email.mime.multipart import MIMEMultipart import getpass host_name = 'smtp.gmail.com' port = 465  u_name = 'username/emailid' password = getpass.getpass() sender = 'sender_name' receivers = ['receiver1_email_address', 'receiver2_email_address'] text = MIMEMultipart() text['Subject'] = 'Test Attachment' text['From'] = sender text['To'] = ', '.join(receivers) txt = MIMEText('Sending a sample image.') text.attach(txt) f_path = '/home/student/Desktop/mountain.jpg' with open(f_path, 'rb') as f:
 img = MIMEImage(f.read()) img.add_header('Content-Disposition',
 'attachment', filename=os.path.basename(f_path)) text.attach(img) server = smtplib.SMTP_SSL(host_name, port) server.login(u_name, password) server.sendmail(sender, receivers, text.as_string()) print("Email with attachment sent successfully !!")server.quit()

按以下方式运行脚本:

student@ubuntu:~/work$ python3 send_email_attachment.py

输出:

Password: Email with attachment sent successfully!!

在前面的例子中,我们将图像作为附件发送给接收者。我们提到了发件人和收件人的电子邮件 ID。接下来,在f_path中,我们提到了我们发送为附件的图像的路径。接下来,我们将该图像作为附件发送给接收者。

在前面的两个例子——send_text.pysend_email_attachment.py——我们通过 Gmail 发送了电子邮件。您可以通过任何其他电子邮件提供商发送。要使用任何其他电子邮件提供商,只需在host_name中写入该提供商名称。不要忘记在其前面添加smtp。在这些示例中,我们使用了smtp.gmail.com;对于 Yahoo!您可以使用smtp.mail.yahoo.com。因此,您可以根据您的电子邮件提供商更改主机名以及端口。

摘要

在本章中,我们学习了标准输入和输出。我们了解了stdinstdout分别作为键盘输入和用户终端。我们还学习了input()print()函数。除此之外,我们还学习了如何从 Gmail 发送电子邮件给接收者。我们发送了一封包含简单文本的电子邮件,还发送了附件。此外,我们还学习了使用format()方法和%运算符进行字符串格式化。

在下一章中,您将学习如何处理不同类型的文件,如 PDF、Excel 和“csv”。

问题

  1. stdin和输入之间有什么区别?

  2. SMTP 是什么?

  3. 以下内容的输出将是什么?

>>> name = "Eric"
>>> profession = "comedian"
>>> affiliation = "Monty Python"
>>> age = 25
>>> message = (
...     f"Hi {name}. "
...     f"You are a {profession}. "
...     f"You were in {affiliation}."
... )
>>> message
  1. 以下内容的输出将是什么?
str1 = 'Hello'
str2 ='World!'
print('str1 + str2 = ', str1 + str2)
print('str1 * 3 =', str1 * 3)

进一步阅读

  1. string文档:docs.python.org/3.1/library/string.html

  2. smptplib文档:docs.python.org/3/library/smtplib.html

第九章:处理各种文件

在这一章中,您将学习如何处理各种类型的文件,如 PDF 文件、Excel 文件、CSV 文件和txt文件。Python 有用于在这些文件上执行操作的模块。您将学习如何使用 Python 打开、编辑和获取这些文件中的数据。

在本章中,将涵盖以下主题:

  • 处理 PDF 文件

  • 处理 Excel 文件

  • 处理 CSV 文件

  • 处理txt文件

处理 PDF 文件

在本节中,我们将学习如何使用 Python 模块处理 PDF 文件。PDF 是一种广泛使用的文档格式,PDF 文件的扩展名为.pdf。Python 有一个名为PyPDF2的模块,对pdf文件进行各种操作非常有用。它是一个第三方模块,是作为 PDF 工具包构建的 Python 库。

我们必须首先安装这个模块。要安装PyPDF2,请在终端中运行以下命令:

pip3 install PyPDF2

现在,我们将看一些操作来处理 PDF 文件,比如读取 PDF、获取页面数、提取文本和旋转 PDF 页面。

阅读 PDF 文档并获取页面数

在本节中,我们将使用PyPDF2模块读取 PDF 文件。此外,我们将获取该 PDF 的页面数。该模块有一个名为PdfFileReader()的函数,可以帮助读取 PDF 文件。确保您的系统中有一个 PDF 文件。现在,我在我的系统中有test.pdf文件,所以我将在本节中使用这个文件。在test.pdf的位置输入您的 PDF 文件名。创建一个名为read_pdf.py的脚本,并在其中编写以下内容:

import PyPDF2 with open('test.pdf', 'rb') as pdf:
 read_pdf= PyPDF2.PdfFileReader(pdf)
    print("Number of pages in pdf : ", read_pdf.numPages)

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 read_pdf.py

以下是输出:

Number of pages in pdf :  20

在前面的示例中,我们使用了PyPDF2模块。接下来,我们创建了一个pdf文件对象。PdfFileReader()将读取创建的对象。读取 PDF 文件后,我们将使用numPages属性获取该pdf文件的页面数。在这种情况下,有20页。

提取文本

要提取pdf文件的页面,PyPDF2模块有extractText()方法。创建一个名为extract_text.py的脚本,并在其中编写以下内容:

import PyPDF2 with open('test.pdf', 'rb') as pdf:
 read_pdf = PyPDF2.PdfFileReader(pdf) pdf_page = read_pdf.getPage(1) pdf_content = pdf_page.extractText() print(pdf_content) 

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 extract_text.py

以下是输出:

3Pythoncommands 9 3.1Comments........................................ .9 3.2Numbersandotherdatatypes........................ ......9 3.2.1The type function................................9 3.2.2Strings....................................... 10 3.2.3Listsandtuples................................ ..10 3.2.4The range function................................11 3.2.5Booleanvalues................................. .11 3.3Expressions..................................... ...11 3.4Operators.......................................

在前面的示例中,我们创建了一个文件阅读器对象。pdf阅读器对象有一个名为getPage()的函数,它以页面编号(从第 0 页开始)作为参数,并返回页面对象。接下来,我们使用extractText()方法,它将从我们在getPage()中提到的页面编号中提取文本。页面索引从0开始。

旋转 PDF 页面

在本节中,我们将看到如何旋转 PDF 页面。为此,我们将使用PDF对象的rotate.Clockwise()方法。创建一个名为rotate_pdf.py的脚本,并在其中编写以下内容:

import PyPDF2

with open('test.pdf', 'rb') as pdf:
 rd_pdf = PyPDF2.PdfFileReader(pdf)
 wr_pdf = PyPDF2.PdfFileWriter()
 for pg_num in range(rd_pdf.numPages):
 pdf_page = rd_pdf.getPage(pg_num)
 pdf_page.rotateClockwise(90)
 wr_pdf.addPage(pdf_page)

 with open('rotated.pdf', 'wb') as pdf_out:
 wr_pdf.write(pdf_out)

print("pdf successfully rotated")

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 rotate_pdf.py

以下是输出:

pdf successfully rotated

在前面的示例中,为了旋转pdf,我们首先创建了原始pdf文件的pdf文件阅读器对象。然后旋转的页面将被写入一个新的pdf文件。因此,为了写入新的pdf,我们使用PyPDF2模块的PdfFileWriter()函数。新的pdf文件将以名称rotated.pdf保存。现在,我们将使用rotateClockwise()方法旋转pdf文件的页面。然后,使用addPage()方法将页面添加到旋转后的pdf中。现在,我们必须将这些pdf页面写入新的pdf文件。因此,首先我们必须打开新的文件对象(pdf_out),并使用pdf写入对象的write()方法将pdf页面写入其中。在所有这些之后,我们将关闭原始(test.pdf)文件对象和新的(pdf_out)文件对象。

处理 Excel 文件

在本节中,我们将处理具有.xlsx扩展名的 Excel 文件。这个文件扩展名是用于 Microsoft Excel 使用的一种开放的 XML 电子表格文件格式。

Python 有不同的模块:xlrd,pandas 和openpyxl用于处理 Excel 文件。在本节中,我们将学习如何使用这三个模块处理 Excel 文件。

首先,我们将看一个使用xlrd模块的例子。xlrd模块用于读取、写入和修改 Excel 电子表格以及执行大量工作。

使用 xlrd 模块

首先,我们必须安装xlrd模块。在终端中运行以下命令以安装xlrd模块:

   pip3 install xlrd

注意:确保您的系统中有一个 Excel 文件。我在我的系统中有sample.xlsx。所以我将在本节中始终使用该文件。

我们将学习如何读取 Excel 文件以及如何从 Excel 文件中提取行和列。

读取 Excel 文件

在本节中,我们将学习如何读取 Excel 文件。我们将使用xlrd模块。创建一个名为read_excel.py的脚本,并在其中写入以下内容:

import xlrd excel_file = (r"/home/student/sample.xlsx") book_obj = xlrd.open_workbook(excel_file) excel_sheet = book_obj.sheet_by_index(0) result = excel_sheet.cell_value(0, 1)
print(result)

运行脚本,您将获得以下输出:

student@ubuntu:~$ python3 read_excel.py

以下是输出:

First Name

在前面的例子中,我们导入了xlrd模块来读取 Excel 文件。我们还提到了 Excel 文件的位置。然后,我们创建了一个文件对象,然后我们提到了索引值,以便从该索引开始阅读。最后,我们打印了结果。

提取列名

在本节中,我们正在从 Excel 表中提取列名。创建一个名为extract_column_names.py的脚本,并在其中写入以下内容:

import xlrd excel_file = ("/home/student/work/sample.xlsx") book_obj = xlrd.open_workbook(excel_file) excel_sheet = book_obj.sheet_by_index(0) excel_sheet.cell_value(0, 0) for i in range(excel_sheet.ncols):
 print(excel_sheet.cell_value(0, i))

运行脚本,您将获得以下输出:

student@ubuntu:~/work$ python3 extract_column_names.py

以下是输出:

Id First Name Last Name Gender Age Country

在前面的例子中,我们正在从 Excel 表中提取列名。我们使用ncols属性获取了列名。

使用 pandas

在使用 Pandas 读取 Excel 文件之前,我们首先必须安装pandas模块。我们可以使用以下命令安装pandas

 pip3 install pandas

注意:确保您的系统中有一个 Excel 文件。我在我的系统中有sample.xlsx。所以我将在本节中始终使用该文件。

现在,我们将看一些使用pandas的例子。

读取 Excel 文件

在本节中,我们将使用pandas模块读取 Excel 文件。现在,让我们看一个读取 Excel 文件的例子。

创建一个名为rd_excel_pandas.py的脚本,并在其中写入以下内容:

import pandas as pd 
excel_file = 'sample.xlsx'
df = pd.read_excel(excel_file)
print(df.head())

运行上述脚本,您将获得以下输出:

student@ubuntu:~/test$ python3 rd_excel_pandas.py

以下是输出:

 OrderDate     Region  ...   Unit Cost     Total
0  2014-01-09   Central  ...    125.00      250.00
1   6/17/15     Central    ...  125.00      625.00
2  2015-10-09   Central    ...    1.29        9.03
3  11/17/15     Central   ...     4.99       54.89
4  10/31/15     Central   ...     1.29       18.06

在前面的例子中,我们正在使用pandas模块读取 Excel 文件。首先,我们导入了pandas模块。然后,我们创建了一个名为excel_file的字符串,用于保存要打开的文件的名称,我们希望使用 pandas 进行操作。随后,我们创建了一个df 数据框对象。在这个例子中,我们使用了 pandas 的read_excel方法来从 Excel 文件中读取数据。读取从索引零开始。最后,我们打印了pandas数据框。

在 Excel 文件中读取特定列

当我们使用 pandas 模块使用read_excel方法读取 Excel 文件时,我们还可以读取该文件中的特定列。要读取特定列,我们需要在read_excel方法中使用usecols参数。

现在,让我们看一个示例,读取 Excel 文件中的特定列。创建一个名为rd_excel_pandas1.py的脚本,并在其中写入以下内容:

import pandas as pd

excel_file = 'sample.xlsx'
cols = [1, 2, 3]
df = pd.read_excel(excel_file , sheet_names='sheet1', usecols=cols)

print(df.head())

运行上述脚本,您将获得以下输出:

student@ubuntu:~/test$ python3 rd_excel_pandas1.py

以下是输出:

 Region      Rep    Item
0  Central    Smith    Desk
1  Central   Kivell    Desk
2  Central     Gill  Pencil
3  Central  Jardine  Binder
4  Central  Andrews  Pencil

在前面的例子中,首先我们导入了 pandas 模块。然后,我们创建了一个名为excel_file的字符串来保存文件名。然后我们定义了cols变量,并将列的索引值放在其中。因此,当我们使用read_excel方法时,在该方法内部,我们还提供了usecols参数,通过该参数可以通过之前在cols变量中定义的索引获取特定列。因此,在运行脚本后,我们只从 Excel 文件中获取特定列。

我们还可以使用 pandas 模块对 Excel 文件执行各种操作,例如读取具有缺失数据的 Excel 文件,跳过特定行以及读取多个 Excel 工作表。

使用 openpyxl

openpyxl是一个用于读写xlsxxlsmxltxxltm文件的 Python 库。首先,我们必须安装openpyxl。运行以下命令:

 pip3 install openpyxl

现在,我们将看一些使用openpyxl的示例。

创建新的 Excel 文件

在本节中,我们将学习使用openpyxl创建新的 Excel 文件。创建一个名为create_excel.py的脚本,并在其中写入以下内容:

from openpyxl import Workbook book_obj = Workbook() excel_sheet = book_obj.active excel_sheet['A1'] = 'Name' excel_sheet['A2'] = 'student' excel_sheet['B1'] = 'age' excel_sheet['B2'] = '24' book_obj.save("test.xlsx") print("Excel created successfully")

运行脚本,您将获得以下输出:

student@ubuntu:~/work$ python3 create_excel.py

以下是输出:

Excel created successfully

现在,检查您当前的工作目录,您会发现test.xlsx已成功创建。在前面的示例中,我们将数据写入了四个单元格。然后,从openpyxl模块中导入Workbook类。工作簿是文档的所有其他部分的容器。接下来,我们将引用对象设置为活动工作表,并在单元格A1A2B1B2中写入数值。最后,我们使用save()方法将内容写入test.xlsx文件。

追加数值

在本节中,我们将在 Excel 中追加数值。为此,我们将使用append()方法。我们可以在当前工作表的底部添加一组数值。创建一个名为append_values.py的脚本,并在其中写入以下内容:

from openpyxl import Workbookbook_obj = Workbook() excel_sheet = book_obj.active rows = (
 (11, 12, 13), (21, 22, 23), (31, 32, 33), (41, 42, 43) ) for values in rows: excel_sheet.append(values) print() print("values are successfully appended") book_obj.save('test.xlsx')wb.save('append_values.xlsx')

运行脚本,您将获得以下输出:

student@ubuntu:~/work$ python3 append_values.py

以下是输出:

values are successfully appended

在前面的示例中,我们在append_values.xlsx文件的工作表中追加了三列数据。我们存储的数据是元组的元组,并且为了追加这些数据,我们逐行通过容器并使用append()方法插入它。

读取多个单元格

在本节中,我们将读取多个单元格。我们将使用openpyxl模块。创建一个名为read_multiple.py的脚本,并在其中写入以下内容:

import openpyxl book_obj = openpyxl.load_workbook('sample.xlsx') excel_sheet = book_obj.active cells = excel_sheet['A1': 'C6'] for c1, c2, c3 in cells:
 print("{0:6} {1:6} {2:6}".format(c1.value, c2.value, c3.value))

运行脚本,您将获得以下输出:

student@ubuntu:~/work$ python3 read_multiple.py

以下是输出:

Id     First Name Last Name
 101 John   Smith 102 Mary   Williams 103 Rakesh Sharma 104 Amit   Roy105 Sandra Ace 

在前面的示例中,我们使用range操作读取了三列数据。然后,我们从单元格A1 – C6中读取数据。

同样地,我们可以使用openpyxl模块在 Excel 文件上执行许多操作,比如合并和拆分单元格。

处理 CSV 文件

CSV格式代表逗号分隔值。逗号用于分隔记录中的字段。这些通常用于导入和导出电子表格和数据库的格式。

CSV 文件是使用特定类型的结构来排列表格数据的纯文本文件。Python 具有内置的csv模块,允许 Python 解析这些类型的文件。csv模块主要用于处理从电子表格以及数据库以文本文件格式导出的数据,包括字段和记录。

csv模块具有所有必需的内置函数,如下所示:

  • csv.reader:此函数用于返回一个reader对象,该对象迭代 CSV 文件的行

  • csv.writer:此函数用于返回一个writer对象,该对象将数据写入 CSV 文件

  • csv.register_dialect:此函数用于注册 CSV 方言

  • csv.unregister_dialect:此函数用于取消注册 CSV 方言

  • csv.get_dialect:此函数用于返回具有给定名称的方言

  • csv.list_dialects:此函数用于返回所有已注册的方言

  • csv.field_size_limit:此函数用于返回解析器允许的当前最大字段大小

在本节中,我们将只看csv.readercsv.writer

读取 CSV 文件

Python 具有内置模块csv,我们将在此处使用它来处理 CSV 文件。我们将使用csv.reader模块来读取 CSV 文件。创建一个名为csv_read.py的脚本,并在其中写入以下内容:

import csv csv_file = open('test.csv', 'r') with csv_file:
 read_csv = csv.reader(csv_file) for row in read_csv: print(row)

运行脚本,您将获得以下输出:

student@ubuntu:~$ python3 csv_read.py

以下是输出:

['Region', 'Country', 'Item Type', 'Sales Channel', 'Order Priority', 'Order Date', 'Order ID', 'Ship Date', 'Units Sold'] ['Sub-Saharan Africa', 'Senegal', 'Cereal', 'Online', 'H', '4/18/2014', '616607081', '5/30/2014', '6593'] ['Asia', 'Kyrgyzstan', 'Vegetables', 'Online', 'H', '6/24/2011', '814711606', '7/12/2011', '124'] ['Sub-Saharan Africa', 'Cape Verde', 'Clothes', 'Offline', 'H', '8/2/2014', '939825713', '8/19/2014', '4168'] ['Asia', 'Bangladesh', 'Clothes', 'Online', 'L', '1/13/2017', '187310731', '3/1/2017', '8263'] ['Central America and the Caribbean', 'Honduras', 'Household', 'Offline', 'H', '2/8/2017', '522840487', '2/13/2017', '8974'] ['Asia', 'Mongolia', 'Personal Care', 'Offline', 'C', '2/19/2014', '832401311', '2/23/2014', '4901'] ['Europe', 'Bulgaria', 'Clothes', 'Online', 'M', '4/23/2012', '972292029', '6/3/2012', '1673'] ['Asia', 'Sri Lanka', 'Cosmetics', 'Offline', 'M', '11/19/2016', '419123971', '12/18/2016', '6952'] ['Sub-Saharan Africa', 'Cameroon', 'Beverages', 'Offline', 'C', '4/1/2015', '519820964', '4/18/2015', '5430'] ['Asia', 'Turkmenistan', 'Household', 'Offline', 'L', '12/30/2010', '441619336', '1/20/2011', '3830']

在上述程序中,我们将test.csv文件作为csv_file打开。然后,我们使用csv.reader()函数将数据提取到reader对象中,我们可以迭代以获取数据的每一行。现在,我们将看一下第二个函数csv.Writer()

写入 CSV 文件

要在csv文件中写入数据,我们使用csv.writer模块。在本节中,我们将一些数据存储到 Python 列表中,然后将该数据放入csv文件中。创建一个名为csv_write.py的脚本,并在其中写入以下内容:

import csv write_csv = [['Name', 'Sport'], ['Andres Iniesta', 'Football'], ['AB de Villiers', 'Cricket'], ['Virat Kohli', 'Cricket'], ['Lionel Messi', 'Football']] with open('csv_write.csv', 'w') as csvFile:
 writer = csv.writer(csvFile) writer.writerows(write_csv) print(write_csv)

运行脚本,您将获得以下输出:

student@ubuntu:~$ python3 csv_write.py

以下是输出:

[['Name', 'Sport'], ['Andres Iniesta', 'Football'], ['AB de Villiers', 'Cricket'], ['Virat Kohli', 'Cricket'], ['Lionel Messi', 'Football']]

在上述程序中,我们创建了一个名为write_csv的列表,其中包含NameSport。然后,在创建列表后,我们打开了新创建的csv_write.csv文件,并使用csvWriter()函数将write_csv列表插入其中。

处理 txt 文件

纯文本文件用于存储仅表示字符或字符串的数据,并且不考虑任何结构化元数据。在 Python 中,无需导入任何外部库来读写文本文件。Python 提供了一个内置函数来创建、打开、关闭、写入和读取文本文件。为了执行操作,有不同的访问模式来管理在打开文件中可能的操作类型。

Python 中的访问模式如下:

  • 仅读取模式('r':此模式打开文本文件以供读取。如果文件不存在,它会引发 I/O 错误。我们也可以称此模式为文件将打开的默认模式。

  • 读写模式('r+':此模式打开文本文件以供读取和写入,并在文件不存在时引发 I/O 错误。

  • 仅写入模式('w':此模式将打开文本文件以供写入。如果文件不存在,则创建文件,并且对于现有文件,数据将被覆盖。

  • 写入和读取模式('w+':此模式将打开文本文件以供读取和写入。对于现有文件,数据将被覆盖。

  • 仅追加模式('a':此模式将打开文本文件以供写入。如果文件不存在,则创建文件,并且数据将被插入到现有数据的末尾。

  • 追加和读取模式('a+':此模式将打开文本文件以供读取和写入。如果文件不存在,则会创建文件,并且数据将被插入到现有数据的末尾。

open()函数

此函数用于打开文件,不需要导入任何外部模块。

语法如下:

 Name_of_file_object = open("Name of file","Access_Mode")

对于前面的语法,文件必须在我们的 Python 程序所在的相同目录中。如果文件不在同一目录中,那么在打开文件时我们还必须定义文件路径。这种情况的语法如下所示:

Name_of_file_object = open("/home/……/Name of file","Access_Mode")

文件打开

打开文件的open函数为"test.txt"

文件与追加模式相同的目录中:

text_file = open("test.txt","a")

如果文件不在相同的目录中,我们必须在追加模式中定义路径:

text_file = open("/home/…../test.txt","a")

close()函数

此函数用于关闭文件,释放文件获取的内存。当文件不再需要或将以不同的文件模式打开时使用此函数。

语法如下:

 Name_of_file_object.close()

以下代码语法可用于简单地打开和关闭文件:

#Opening and closing a file test.txt:
text_file = open("test.txt","a") text_file.close()

写入文本文件

通过使用 Python,您可以创建一个文本文件(test.txt)。通过使用代码,写入文本文件很容易。要打开一个文件进行写入,我们将第二个参数设置为访问模式中的"w"。要将数据写入test.txt文件,我们使用file handle对象的write()方法。创建一个名为text_write.py的脚本,并在其中写入以下内容:

text_file = open("test.txt", "w") text_file.write("Monday\nTuesday\nWednesday\nThursday\nFriday\nSaturday\n") text_file.close()

运行上述脚本,您将获得以下输出:

现在,检查您的当前工作目录。您会发现一个我们创建的test.txt文件。现在,检查文件的内容。您会发现我们在write()函数中写入的日期将保存在test.txt中。

在上述程序中,我们声明了text_file变量来打开名为test.txt的文件。open函数接受两个参数:第一个是我们要打开的文件,第二个是表示我们要在文件上执行的权限或操作的访问模式。在我们的程序中,我们在第二个参数中使用了"w"字母,表示写入。然后,我们使用text_file.close()来关闭存储的test.txt文件的实例。

读取文本文件

读取文件和写入文件一样容易。要打开一个文件进行读取,我们将第二个参数即访问模式设置为"r",而不是"w"。要从该文件中读取数据,我们使用文件句柄对象的read()方法。创建一个名为text_read.py的脚本,并在其中写入以下内容:

text_file = open("test.txt", "r") data = text_file.read() print(data) text_file.close()

以下是输出:

student@ubuntu:~$ python3 text_read.py Monday Tuesday Wednesday Thursday Friday Saturday

在上述程序中,我们声明了text_file变量来打开名为test.txt的文件。open函数接受两个参数:第一个是我们要打开的文件,第二个是表示我们要在文件上执行的权限或操作的访问模式。在我们的程序中,我们在第二个参数中使用了"r"字母,表示读取操作。然后,我们使用text_file.close()来关闭存储的test.txt文件的实例。运行 Python 程序后,我们可以在终端中轻松看到文本文件中的内容。

总结

在本章中,我们学习了各种文件。我们学习了 PDF、Excel、CSV 和文本文件。我们使用 Python 模块对这些类型的文件执行了一些操作。

在下一章中,我们将学习 Python 中的基本网络和互联网模块。

问题

  1. readline()readlines()之间有什么区别?

  2. open()with open()之间有什么区别?

  3. r c:\\Downloads的意义是什么?

  4. 生成器对象是什么?

  5. pass的用途是什么?

  6. 什么是 lambda 表达式?

进一步阅读

第十章:基本网络 - 套接字编程

在本章中,您将学习套接字和三种互联网协议:httpftpliburllib。您还将学习 Python 中用于网络的socket模块。http是一个用于处理超文本传输协议HTTP)的包。ftplib模块用于执行自动化的与 FTP 相关的工作。urllib是一个处理与 URL 相关的工作的包。

在本章中,您将学习以下内容:

  • 套接字

  • http

  • ftplib模块

  • urllib

套接字

在本节中,我们将学习套接字。我们将使用 Python 的 socket 模块。套接字是用于机器之间通信的端点,无论是在本地还是通过互联网。套接字模块有一个套接字类,用于处理数据通道。它还具有用于网络相关任务的函数。要使用套接字模块的功能,我们首先需要导入套接字模块。

让我们看看如何创建套接字。套接字类有一个套接字函数,带有两个参数:address_familysocket 类型

以下是语法:

 import socket            s = socket.socket(address_family, socket type)

address_family 控制 OSI 网络层协议。

socket 类型 控制传输层协议。

Python 支持三种地址族:AF_INETAF_INET6AF_UNIX。最常用的是AF_INET,用于互联网寻址。AF_INET6用于 IPv6 互联网寻址。AF_UNIX用于Unix 域套接字UDS),这是一种进程间通信协议。

有两种套接字类型:SOCK_DGRAMSOCK_STREAMSOCK_DGRAM 套接字类型用于面向消息的数据报传输;这些与 UDP 相关联。数据报套接字传递单个消息。SOCK_STREAM 用于面向流的传输;这些与 TCP 相关联。流套接字在客户端和服务器之间提供字节流。

套接字可以配置为服务器套接字和客户端套接字。当 TCP/IP 套接字都连接时,通信将是双向的。现在我们将探讨一个客户端-服务器通信的示例。我们将创建两个脚本:server.pyclient.py

server.py脚本如下:

import socket host_name = socket.gethostname() port = 5000 s_socket = socket.socket() s_socket.bind((host_name, port)) s_socket.listen(2) conn, address = s_socket.accept() print("Connection from: " + str(address)) while True:
 recv_data = conn.recv(1024).decode() if not recv_data: break print("from connected user: " + str(recv_data)) recv_data = input(' -> ') conn.send(recv_data.encode()) conn.close()

现在我们将为客户端编写一个脚本。

client.py脚本如下:

import socket host_name = socket.gethostname() port = 5000 c_socket = socket.socket() c_socket.connect((host_name, port)) msg = input(" -> ")  while msg.lower().strip() != 'bye': c_socket.send(msg.encode()) recv_data = c_socket.recv(1024).decode() print('Received from server: ' + recv_data) msg = input(" -> ") c_socket.close()

现在我们将在两个不同的终端中运行这两个程序。在第一个终端中,我们将运行server.py,在第二个终端中,运行client.py

输出将如下所示:

终端 1: python3 server.py 终端 2: python3 client.py
student@ubuntu:~/work$ python3 server.py``连接来自:('127.0.0.1',35120)``来自连接的用户:来自客户端的问候`` -> 来自服务器的问候! | student@ubuntu:~/work$ python3 client.py``-> 来自客户端的问候``从服务器接收:来自服务器的问候!`` ->

http 包

在本节中,我们将学习http包。http包有四个模块:

  • http.client:这是一个低级 HTTP 协议客户端

  • http.server:这包含基本的 HTTP 服务器类

  • http.cookies:这用于使用 cookie 实现状态管理

  • http.cookiejar:此模块提供 cookie 持久性

在本节中,我们将学习http.clienthttp.server模块。

http.client 模块

我们将看到两个http请求:GETPOST。我们还将建立一个http连接。

首先,我们将探讨一个创建http连接的示例。为此,创建一个make_connection.py脚本,并在其中编写以下内容:

import http.client con_obj = http.client.HTTPConnection('Enter_URL_name', 80, timeout=20) print(con_obj)

运行脚本,您将获得以下输出:

student@ubuntu:~/work$ python3 make_connection.py <http.client.HTTPConnection object at 0x7f2c365dd898>

在上面的示例中,我们使用了指定超时的端口 80 上的 URL 建立了连接。

现在我们将看到httpGET请求方法;使用这个GET请求方法,我们将看到一个示例,其中我们获得响应代码以及头列表。创建一个get_example.py脚本,并在其中编写以下内容:

import http.client con_obj = http.client.HTTPSConnection("www.imdb.com") con_obj.request("GET", "/") response = con_obj.getresponse()  print("Status: {}".format(response.status))  headers_list = response.getheaders()
print("Headers: {}".format(headers_list))  con_obj.close()

按照以下方式运行脚本:

student@ubuntu:~/work$ python3 get_example.py

输出应该如下:

Status: 200 Headers: [('Server', 'Server'), ('Date', 'Fri, 23 Nov 2018 09:49:12 GMT'), ('Content-Type', 'text/html;charset=UTF-8'), ('Transfer-Encoding', 'chunked'), ('Connection', 'keep-alive'), ('X-Frame-Options', 'SAMEORIGIN'), ('Content-Security-Policy', "frame-ancestors 'self' imdb.com *.imdb.com *.media-imdb.com withoutabox.com *.withoutabox.com amazon.com *.amazon.com amazon.co.uk *.amazon.co.uk amazon.de *.amazon.de translate.google.com images.google.com www.google.com www.google.co.uk search.aol.com bing.com www.bing.com"), ('Ad-Unit', 'imdb.home.homepage'), ('Entity-Id', ''), ('Section-Id', 'homepage'), ('Page-Id', 'homepage'), ('Content-Language', 'en-US'), ('Set-Cookie', 'uu=BCYsgIz6VTPefAjQB9YlJiZhwogwHmoU3sLx9YK-A61kPgvXEKwHSJKU3XeaxIoL8DBQGhYLuFvR%0D%0AqPV6VVvx70AV6eL_sGzVaRQQAKf-PUz2y0sTx9H4Yvib9iSYRPOzR5qHQkwuoHPKmpu2KsSbPaCb%0D%0AYbc-R6nz9ObkbQf6RAYm5sTAdf5lSqM2ZzCEhfIt_H3tWQqnK5WlihYwfMZS2AJdtGXGRnRvEHlv%0D%0AyA4Dcn9NyeX44-hAnS64zkDfDeGXoCUic_kH6ZnD5vv21HOiVodVKA%0D%0A; Domain=.imdb.com; Expires=Wed, 11-Dec-2086 13:03:18 GMT; Path=/; Secure'), ('Set-Cookie', 'session-id=134-6809939-6044806; Domain=.imdb.com; Expires=Wed, 11-Dec-2086 13:03:18 GMT; Path=/; Secure'), ('Set-Cookie', 'session-id-time=2173686551; Domain=.imdb.com; Expires=Wed, 11-Dec-2086 13:03:18 GMT; Path=/; Secure'), ('Vary', 'Accept-Encoding,X-Amzn-CDN-Cache,User-Agent'), ('x-amz-rid', '7SWEYTYH4TX8YR2CF5JT')]

在前面的示例中,我们使用了HTTPSConnection,因为该网站是通过HTTPS协议提供的。您可以根据您使用的网站使用HTTPSConnectionHTTPConnection。我们提供了一个 URL,并使用连接对象检查了状态。之后,我们得到了一个标题列表。这个标题列表包含了从服务器返回的数据类型的信息。getheaders()方法将获取标题列表。

现在我们将看到一个POST请求的示例。我们可以使用HTTP POST将数据发布到 URL。为此,创建一个post_example.py脚本,并在其中写入以下内容:

import http.client import json con_obj = http.client.HTTPSConnection('www.httpbin.org') headers_list = {'Content-type': 'application/json'} post_text = {'text': 'Hello World !!'} json_data = json.dumps(post_text) con_obj.request('POST', '/post', json_data, headers_list) response = con_obj.getresponse() print(response.read().decode())

按照以下方式运行脚本:

student@ubuntu:~/work$ python3 post_example.py

您应该得到以下输出:

{
 "args": {}, "data": "{\"text\": \"Hello World !!\"}", "files": {}, "form": {}, "headers": { "Accept-Encoding": "identity", "Connection": "close", "Content-Length": "26", "Content-Type": "application/json", "Host": "www.httpbin.org" }, "json": { "text": "Hello World !!" }, "origin": "1.186.106.115", "url": "https://www.httpbin.org/post" }

在前面的示例中,我们首先创建了一个HTTPSConnection对象。接下来,我们创建了一个post_text对象,它发布了Hello World。之后,我们写了一个POST请求,得到了一个响应。

http.server 模块

在本节中,我们将学习http包中的一个模块,即http.server模块。这个模块定义了用于实现HTTP服务器的类。它有两种方法:GETHEAD。通过使用这个模块,我们可以在网络上共享文件。您可以在任何端口上运行http服务器。确保端口号大于1024。默认端口号是8000

您可以按照以下方式使用http.server

首先,导航到您想要的目录,然后运行以下命令:

student@ubuntu:~/Desktop$ python3 -m http.server 9000

现在打开您的浏览器,在地址栏中输入localhost:9000,然后按Enter。您将得到以下输出:

student@ubuntu:~/Desktop$ python3 -m http.server 9000 Serving HTTP on 0.0.0.0 port 9000 (http://0.0.0.0:9000/) ... 127.0.0.1 - - [23/Nov/2018 16:08:14] code 404, message File not found 127.0.0.1 - - [23/Nov/2018 16:08:14] "GET /Downloads/ HTTP/1.1" 404 - 127.0.0.1 - - [23/Nov/2018 16:08:14] code 404, message File not found 127.0.0.1 - - [23/Nov/2018 16:08:14] "GET /favicon.ico HTTP/1.1" 404 - 127.0.0.1 - - [23/Nov/2018 16:08:21] "GET / HTTP/1.1" 200 - 127.0.0.1 - - [23/Nov/2018 16:08:21] code 404, message File not found 127.0.0.1 - - [23/Nov/2018 16:08:21] "GET /favicon.ico HTTP/1.1" 404 - 127.0.0.1 - - [23/Nov/2018 16:08:26] "GET /hello/ HTTP/1.1" 200 - 127.0.0.1 - - [23/Nov/2018 16:08:26] code 404, message File not found 127.0.0.1 - - [23/Nov/2018 16:08:26] "GET /favicon.ico HTTP/1.1" 404 - 127.0.0.1 - - [23/Nov/2018 16:08:27] code 404, message File not found 127.0.0.1 - - [23/Nov/2018 16:08:27] "GET /favicon.ico HTTP/1.1" 404 -

ftplib 模块

ftplib是 Python 中的一个模块,它提供了执行 FTP 协议的各种操作所需的所有功能。ftplib包含 FTP 客户端类,以及一些辅助函数。使用这个模块,我们可以轻松地连接到 FTP 服务器,检索多个文件并处理它们。通过导入ftplib模块,我们可以使用它提供的所有功能。

在本节中,我们将介绍如何使用ftplib模块进行 FTP 传输。我们将看到各种 FTP 对象。

下载文件

在本节中,我们将学习如何使用ftplib模块从另一台机器下载文件。为此,创建一个get_ftp_files.py脚本,并在其中写入以下内容:

import os
from ftplib import FTP ftp = FTP('your-ftp-domain-or-ip')
with ftp:
 ftp.login('your-username','your-password') ftp.cwd('/home/student/work/') files = ftp.nlst()
    print(files) # Print the files for file in files:
        if os.path.isfile(file): print("Downloading..." + file) ftp.retrbinary("RETR " + file ,open("/home/student/testing/" + file, 'wb').write) ftp.close()

按照以下方式运行脚本:

student@ubuntu:~/work$ python3 get_ftp_files.py

您应该得到以下输出:

Downloading...hello Downloading...hello.c Downloading...sample.txt Downloading...strip_hello Downloading...test.py

在前面的示例中,我们使用ftplib模块从主机检索了多个文件。首先,我们提到了另一台机器的 IP 地址、用户名和密码。为了从主机获取所有文件,我们使用了ftp.nlst()函数,为了将这些文件下载到我们的计算机,我们使用了ftp.retrbinary()函数。

使用 getwelcome()获取欢迎消息:

一旦建立了初始连接,服务器通常会返回一个欢迎消息。这条消息通过getwelcome()函数传递,有时包括免责声明或对用户相关的有用信息。

现在我们将看到一个getwelcome()的示例。创建一个get_welcome_msg.py脚本,并在其中写入以下内容:

from ftplib import FTP ftp = FTP('your-ftp-domain-or-ip') ftp.login('your-username','your-password') welcome_msg = ftp.getwelcome() print(welcome_msg) ftp.close()

按照以下方式运行脚本:

student@ubuntu:~/work$ python3 get_welcome_msg.py 220 (vsFTPd 3.0.3)

在前面的代码中,我们首先提到了另一台机器的 IP 地址、用户名和密码。我们使用了getwelcome()函数在建立初始连接后获取信息。

使用 sendcmd()函数向服务器发送命令

在本节中,我们将学习sendcmd()函数。我们可以使用sendcmd()函数向服务器发送一个简单的string命令以获取字符串响应。客户端可以发送 FTP 命令,如STATPWDRETRSTORftplib模块有多个方法可以包装这些命令。这些命令可以使用sendcmd()voidcmd()方法发送。例如,我们将发送一个STAT命令来检查服务器的状态。

创建一个send_command.py脚本,并在其中写入以下内容:

from ftplib import FTP ftp = FTP('your-ftp-domain-or-ip') ftp.login('your-username','your-password') ftp.cwd('/home/student/') s_cmd_stat = ftp.sendcmd('STAT') print(s_cmd_stat) print() s_cmd_pwd = ftp.sendcmd('PWD') print(s_cmd_pwd) print() ftp.close()

运行脚本如下:

student@ubuntu:~/work$ python3 send_command.py

您将获得以下输出:

211-FTP server status:
 Connected to ::ffff:192.168.2.109 Logged in as student TYPE: ASCII No session bandwidth limit Session timeout in seconds is 300 Control connection is plain text Data connections will be plain text At session startup, client count was 1 vsFTPd 3.0.3 - secure, fast, stable 211 End of status
257 "/home/student" is the current directory

在上面的代码中,我们首先提到了另一台机器的 IP 地址,用户名和密码。接下来,我们使用sendcmd()方法发送STAT命令到另一台机器。然后,我们使用sendcmd()发送PWD命令。

urllib 包

http一样,urllib也是一个包,其中包含用于处理 URL 的各种模块。urllib模块允许您通过脚本访问多个网站。我们还可以使用该模块下载数据,解析数据,修改标头等。

urllib有一些不同的模块,列在这里:

  • urllib.request:用于打开和读取 URL。

  • urllib.error:包含urllib.request引发的异常。

  • urllib.parse:用于解析 URL。

  • urllib.robotparser:用于解析robots.txt文件。

在本节中,我们将学习如何使用urllib打开 URL 以及如何从 URL 读取html文件。我们将看到一个简单的urllib使用示例。我们将导入urllib.requests。然后我们将打开 URL 的操作赋给一个变量,然后我们将使用.read()命令从 URL 读取数据。

创建一个url_requests_example.py脚本,并在其中写入以下内容:

import urllib.request x = urllib.request.urlopen('https://www.imdb.com/') print(x.read())

运行脚本如下:

student@ubuntu:~/work$ python3 url_requests_example.py

以下是输出:

b'\n\n<!DOCTYPE html>\n<html\n    \n    >\n    <head>\n         \n        <meta charset="utf-8">\n        <meta http-equiv="X-UA-Compatible" content="IE=edge">\n\n    \n    \n    \n\n    \n    \n    \n\n    <meta name="apple-itunes-app" content="app-id=342792525, app-argument=imdb:///?src=mdot">\n\n\n\n        <script type="text/javascript">var IMDbTimer={starttime: new Date().getTime(),pt:\'java\'};</script>\n\n<script>\n    if (typeof uet == \'function\') {\n      uet("bb", "LoadTitle", {wb: 1});\n    }\n</script>\n  <script>(function(t){ (t.events = t.events || {})["csm_head_pre_title"] = new Date().getTime(); })(IMDbTimer);</script>\n        <title>IMDb - Movies, TV and Celebrities - IMDb</title>\n  <script>(function(t){ (t.events = t.events || {})["csm_head_post_title"] = new Date().getTime(); })(IMDbTimer);</script>\n<script>\n    if (typeof uet == \'function\') {\n      uet("be", "LoadTitle", {wb: 1});\n    }\n</script>\n<script>\n    if (typeof uex == \'function\') {\n      uex("ld", "LoadTitle", {wb: 1});\n    }\n</script>\n\n        <link rel="canonical" href="https://www.imdb.com/" />\n        <meta property="og:url" content="http://www.imdb.com/" />\n        <link rel="alternate" media="only screen and (max-width: 640px)" href="https://m.imdb.com/">\n\n<script>\n    if (typeof uet == \'function\') {\n      uet("bb", "LoadIcons", {wb: 1});\n    }\n</script>\n  <script>(function(t){ (t.events = t.events || {})["csm_head_pre_icon"] = new Date().getTime(); })(IMDbTimer);</script>\n        <link href="https://m.media-amazon.com/images/G/01/imdb/images/safari-favicon-517611381._CB483525257_.svg" mask rel="icon" sizes="any">\n        <link rel="icon" type="image/ico" href="https://m.media-amazon.com/images/G/01/imdb/images/favicon-2165806970._CB470047330_.ico" />\n        <meta name="theme-color" content="#000000" />\n        <link rel="shortcut icon" type="image/x-icon" href="https://m.media-amazon.com/images/G/01/imdb/images/desktop-favicon-2165806970._CB484110913_.ico" />\n        <link href="https://m.media-amazon.com/images/G/01/imdb/images/mobile/apple-touch-icon-web-4151659188._CB483525313_.png" rel="apple-touch-icon"> \n

在上面的示例中,我们使用了read()方法,该方法返回字节数组。这会以非人类可读的格式打印Imdb主页返回的 HTML 数据,但我们可以使用 HTML 解析器从中提取一些有用的信息。

Python urllib 响应标头

我们可以通过在响应对象上调用info()函数来获取响应标头。这将返回一个字典,因此我们还可以从响应中提取特定的标头数据。创建一个url_response_header.py脚本,并在其中写入以下内容:

import urllib.request x = urllib.request.urlopen('https://www.imdb.com/') print(x.info())

运行脚本如下:

student@ubuntu:~/work$ python3 url_response_header.py

以下是输出:

Server: Server Date: Fri, 23 Nov 2018 11:22:48 GMT Content-Type: text/html;charset=UTF-8 Transfer-Encoding: chunked Connection: close X-Frame-Options: SAMEORIGIN Content-Security-Policy: frame-ancestors 'self' imdb.com *.imdb.com *.media-imdb.com withoutabox.com *.withoutabox.com amazon.com *.amazon.com amazon.co.uk *.amazon.co.uk amazon.de *.amazon.de translate.google.com images.google.com www.google.com www.google.co.uk search.aol.com bing.com www.bing.com Content-Language: en-US Set-Cookie: uu=BCYsJu-IKhmmXuZWHgogzgofKfB8CXXLkNXdfKrrvsCP-RkcSn29epJviE8uRML4Xl4E7Iw9V09w%0D%0Anl3qKv1bEVJ-hHWVeDFH6BF8j_MMf8pdVA2NWzguWQ2XbKvDXFa_rK1ymzWc-Q35RCk_Z6jTj-Mk%0D%0AlEMrKkFyxbDYxLMe4hSjUo7NGrmV61LY3Aohaq7zE-ZE8a6DhgdlcLfXsILNXTkv7L3hvbxmr4An%0D%0Af73atPNPOgyLTB2S615MnlZ3QpOeNH6E2fElDYXZnsIFEAb9FW2XfQ%0D%0A; Domain=.imdb.com; Expires=Wed, 11-Dec-2086 14:36:55 GMT; Path=/; Secure Set-Cookie: session-id=000-0000000-0000000; Domain=.imdb.com; Expires=Wed, 11-Dec-2086 14:36:55 GMT; Path=/; Secure Set-Cookie: session-id-time=2173692168; Domain=.imdb.com; Expires=Wed, 11-Dec-2086 14:36:55 GMT; Path=/; Secure Vary: Accept-Encoding,X-Amzn-CDN-Cache,User-Agent x-amz-rid: GJDGQQTNA4MH7S3KJJKV

总结

在本章中,我们学习了套接字,用于双向客户端-服务器通信。我们学习了三个互联网模块:httpftpliburllibhttp包具有客户端和服务器的模块:http.clienthttp.server。使用ftplib,我们从另一台机器下载文件。我们还查看了欢迎消息和发送send命令。

在下一章中,我们将介绍构建和发送电子邮件。我们将学习有关消息格式和添加多媒体内容。此外,我们将学习有关 SMTP,POP 和 IMAP 服务器的知识。

问题

  1. 什么是套接字编程?

  2. 什么是 RPC?

  3. 导入用户定义模块或文件的不同方式是什么?

  4. 列表和元组之间有什么区别?

  5. 字典中是否可以有重复的键?

  6. urlliburllib2requests模块之间有什么区别?

进一步阅读

第十一章:使用 Python 脚本处理电子邮件

在本章中,您将学习如何使用 Python 脚本处理电子邮件。您将学习电子邮件消息格式。我们将探索smtplib模块用于发送和接收电子邮件。我们将使用 Python 电子邮件包发送带有附件和 HTML 内容的电子邮件。您还将学习用于处理电子邮件的不同协议。

在本章中,您将学习以下内容:

  • 电子邮件消息格式

  • 添加 HTML 和多媒体内容

  • POP3 和 IMAP 服务器

电子邮件消息格式

在本节中,我们将学习电子邮件消息格式。电子邮件消息由三个主要组件组成:

  • 接收者的电子邮件地址

  • 发件人的电子邮件地址

  • 消息

消息格式中还包括其他组件,如主题行、电子邮件签名和附件。

现在,我们将看一个简单的例子,从您的 Gmail 地址发送纯文本电子邮件,在其中您将学习如何编写电子邮件消息并发送它。现在,请创建一个名为write_email_message.py的脚本,并在其中编写以下内容:

import smtplib import getpass host_name = "smtp.gmail.com" port = 465 sender = 'sender_emil_id'
receiver = 'receiver_email_id' password = getpass.getpass() msg = """\ Subject: Test Mail Hello from Sender !!""" s = smtplib.SMTP_SSL(host_name, port) s.login(sender, password) s.sendmail(sender, receiver, msg) s.quit() print("Mail sent successfully")

运行脚本,您将得到以下输出:

student@ubuntu:~/work/Chapter_11$ python3 write_email_message.py Output: Password: Mail sent successfully

在上面的例子中,我们使用了smtplib Python 模块来发送电子邮件。确保您从 Gmail ID 向接收者发送电子邮件。sender变量保存了发件人的电子邮件地址。在password变量中,您可以输入密码,或者您可以使用getpass模块提示输入密码。在这里,我们提示输入密码。接下来,我们创建了一个名为msg的变量,这将是我们实际的电子邮件消息。在其中,我们首先提到了一个主题,然后是我们想要发送的消息。然后,在login()中,我们提到了senderpassword变量。接下来,在sendmail()中,我们提到了senderreceiverstext变量。因此,通过这个过程,我们成功地发送了电子邮件。

添加 HTML 和多媒体内容

在本节中,我们将看到如何将多媒体内容作为附件发送以及如何添加 HTML 内容。为此,我们将使用 Python 的email包。

首先,我们将看如何添加 HTML 内容。为此,请创建一个名为add_html_content.py的脚本,并在其中编写以下内容:

import os import smtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart import getpass host_name = 'smtp.gmail.com' port = 465 sender = '*sender_emailid*' password = getpass.getpass() receiver = '*receiver_emailid*' text = MIMEMultipart() text['Subject'] = 'Test HTML Content' text['From'] = sender text['To'] = receiver msg = """\ <html>
 <body> <p>Hello there, <br> Good day !!<br> <a href="http://www.imdb.com">Home</a> </p> </body> </html> """ html_content = MIMEText(msg, "html") text.attach(html_content) s = smtplib.SMTP_SSL(host_name, port) print("Mail sent successfully !!")  s.login(sender, password) s.sendmail(sender, receiver, text.as_string()) s.quit()

运行脚本,您将得到以下输出:

student@ubuntu:~/work/Chapter_11$ python3 add_html_content.py Output: Password: Mail sent successfully !!

在上面的例子中,我们使用了电子邮件包通过 Python 脚本发送 HTML 内容作为消息。我们创建了一个msg变量,其中存储了 HTML 内容。

现在,我们将看如何添加附件并通过 Python 脚本发送它。为此,请创建一个名为add_attachment.py的脚本,并在其中编写以下内容:

import os import smtplib from email.mime.text import MIMEText from email.mime.image import MIMEImage from email.mime.multipart import MIMEMultipart import getpass host_name = 'smtp.gmail.com' port = 465 sender = '*sender_emailid*' password = getpass.getpass() receiver = '*receiver_emailid*' text = MIMEMultipart() text['Subject'] = 'Test Attachment' text['From'] = sender text['To'] = receiver txt = MIMEText('Sending a sample image.') text.attach(txt) f_path = 'path_of_file' with open(f_path, 'rb') as f:
 img = MIMEImage(f.read()) img.add_header('Content-Disposition',
 'attachment', filename=os.path.basename(f_path)) text.attach(img) s = smtplib.SMTP_SSL(host_name, port) print("Attachment sent successfully !!") s.login(sender, password) s.sendmail(sender, receiver, text.as_string()) s.quit()

运行脚本,您将得到以下输出:

student@ubuntu:~/work/Chapter_11$ python3 add_attachment.py Output: Password: Attachment sent successfully !!

在上面的例子中,我们将一张图片作为附件发送给接收者。我们提到了发件人和收件人的电子邮件 ID。接下来,在f_path中,我们提到了我们要发送的图片的路径。接下来,我们将该图片作为附件发送给接收者。

POP3 和 IMAP 服务器

在本节中,您将学习如何通过 POP 和 IMAP 服务器接收电子邮件。Python 提供了poplibimaplib库,用于通过 Python 脚本接收电子邮件。

使用 poplib 库接收电子邮件

POP3代表邮局协议第 3 版。这个标准协议帮助您从远程服务器接收电子邮件到我们的本地计算机。POP3 的主要优势在于它允许我们将电子邮件下载到本地计算机上,并离线阅读已下载的电子邮件。

POP3 协议在两个端口上运行:

  • 端口110:默认的非加密端口

  • 端口995:加密端口

现在,我们将看一些例子。首先,我们将看一个例子,其中我们收到了一些电子邮件。为此,请创建一个名为number_of_emails.py的脚本,并在其中编写以下内容:

import poplib import getpass pop3_server = 'pop.gmail.com' username = 'Emaild_address'
password = getpass.getpass()
email_obj = poplib.POP3_SSL(pop3_server) print(email_obj.getwelcome()) email_obj.user(username) email_obj.pass_(password) email_stat = email_obj.stat() print("New arrived e-Mails are : %s (%s bytes)" % email_stat)

运行脚本,如下所示:

student@ubuntu:~$ python3 number_of_emails.py

作为输出,您将得到邮箱中存在的电子邮件数量。

在上面的示例中,首先我们导入了poplib库,该库用于 Python 的 POP3 协议,以安全地接收电子邮件。然后,我们声明了特定的电子邮件服务器和我们的电子邮件凭据,即我们的用户名和密码。之后,我们打印来自服务器的响应消息,并向 POP3 SSL 服务器提供用户名和密码。登录后,我们获取邮箱统计信息并将其以电子邮件数量的形式打印到终端。

现在,我们将编写一个脚本来获取最新的电子邮件。为此,请创建一个名为latest_email.py的脚本,并在其中编写以下内容:

import poplib
import getpass pop3_server = 'pop.gmail.com' username = 'Emaild_address' password = getpass.getpass() email_obj = poplib.POP3_SSL(pop3_server) print(email_obj.getwelcome()) email_obj.user(username) email_obj.pass_(password) print("\nLatest Mail\n") latest_email = email_obj.retr(1) print(latest_email[1])

运行脚本,如下所示:

student@ubuntu:~$ python3 latest_email.py

作为输出,您将获得您收件箱中收到的最新邮件。

在上面的示例中,我们导入了用于 Python 的poplib库,以安全地提供 POP3 协议以接收电子邮件。在声明了特定的电子邮件服务器和用户名和密码之后,我们打印了来自服务器的响应消息,并向 POP3 SSL 服务器提供了用户名和密码。然后,我们从邮箱中获取了最新的电子邮件。

现在,我们将编写一个脚本来获取所有的电子邮件。为此,请创建一个名为all_emails.py的脚本,并在其中编写以下内容:

import poplib
import getpass pop3_server = 'pop.gmail.com' username = 'Emaild_address' password = getpass.getpass() email_obj = poplib.POP3_SSL(pop3_server) print(email_obj.getwelcome()) email_obj.user(username) email_obj.pass_(password) email_stat = email_obj.stat() NumofMsgs = email_stat[0] for i in range(NumofMsgs):
 for mail in email_obj.retr(i+1)[1]: print(mail)

运行脚本,如下所示:

student@ubuntu:~$ python3 latest_email.py

作为输出,您将获得您收件箱中收到的所有电子邮件。

使用 imaplib 库接收电子邮件

IMAP 代表 Internet 消息访问协议。它用于通过本地计算机访问远程服务器上的电子邮件。IMAP 允许多个客户端同时访问您的电子邮件。当您通过不同位置访问电子邮件时,IMAP 更适用。

IMAP 协议在两个端口上运行:

  • 端口143:默认非加密端口

  • 端口993:加密端口

现在,我们将看到使用imaplib库的示例。创建一个名为imap_email.py的脚本,并在其中编写以下内容:

import imaplib import pprint
import getpass imap_server = 'imap.gmail.com' username = 'Emaild_address'
password = getpass.getpass()imap_obj = imaplib.IMAP4_SSL(imap_server) imap_obj.login(username, password) imap_obj.select('Inbox') temp, data_obj = imap_obj.search(None, 'ALL') for data in data_obj[0].split():
 temp, data_obj = imap_obj.fetch(data, '(RFC822)') print('Message: {0}\n'.format(data)) pprint.pprint(data_obj[0][1]) break imap_obj.close()

运行脚本,如下所示:

student@ubuntu:~$ python3 imap_email.py

作为输出,您将获得指定文件夹中的所有电子邮件。

在上面的示例中,首先我们导入了imaplib库,该库用于 Python 通过 IMAP 协议安全地接收电子邮件。然后,我们声明了特定的电子邮件服务器和我们的用户凭据,即我们的用户名和密码。之后,我们向 IMAP SSL 服务器提供了用户名和密码。我们使用'select('Inbox')'函数在imap_obj上显示收件箱中的消息。然后,我们使用for循环逐个显示已获取的消息。为了显示消息,我们使用“pretty print”——即pprint.pprint()函数——因为它会格式化您的对象,将其写入数据流,并将其作为参数传递。最后,连接被关闭。

摘要

在本章中,我们学习了如何在 Python 脚本中编写电子邮件消息。我们还学习了 Python 的smtplib模块,该模块用于通过 Python 脚本发送和接收电子邮件。我们还学习了如何通过 POP3 和 IMAP 协议接收电子邮件。Python 提供了poplibimaplib库,我们可以使用这些库执行任务。

在下一章中,您将学习有关 Telnet 和 SSH 的知识。

问题

  1. POP3 和 IMAP 是什么?

  2. break 和 continue 分别用于什么?给出一个适当的例子。

  3. pprint 是什么?

  4. 什么是负索引,为什么要使用它们?

  5. pycpy文件扩展名之间有什么区别?

  6. 使用循环生成以下模式:

 1010101
 10101 
 101 
 1  

第十二章:Telnet 和 SSH 上的主机远程监控

在本章中,您将学习如何在配置了 Telnet 和 SSH 的服务器上进行基本配置。我们将首先使用 Telnet 模块,然后使用首选方法实现相同的配置:使用 Python 中的不同模块进行 SSH。您还将了解telnetlibsubprocessfabricNetmikoparamiko模块的工作原理。在本章中,您必须具备基本的网络知识。

在本章中,我们将涵盖以下主题:

  • telnetlib()模块

  • subprocess.Popen()模块

  • 使用 fabric 模块的 SSH

  • 使用 Paramiko 库的 SSH

  • 使用 Netmiko 库的 SSH

telnetlib()模块

在本节中,我们将学习有关 Telnet 协议,然后我们将使用telnetlib模块在远程服务器上执行 Telnet 操作。

Telnet 是一种网络协议,允许用户与远程服务器通信。网络管理员通常使用它来远程访问和管理设备。要访问设备,请在终端中使用 Telnet 命令和远程服务器的 IP 地址或主机名。

Telnet 在默认端口号23上使用 TCP。要使用 Telnet,请确保它已安装在您的系统上。如果没有,请运行以下命令进行安装:

$ sudo apt-get install telnetd

要使用简单的终端运行 Telnet,您只需输入以下命令:

$ telnet ip_address_of_your_remote_server

Python 具有telnetlib模块,可通过 Python 脚本执行 Telnet 功能。在对远程设备或路由器进行 Telnet 之前,请确保它们已正确配置,如果没有,您可以通过在路由器的终端中使用以下命令进行基本配置:

configure terminal
enable password 'set_Your_password_to_access_router'
username 'set_username' password 'set_password_for_remote_access'
line vty 0 4 
login local 
transport input all 
interface f0/0 
ip add 'set_ip_address_to_the_router' 'put_subnet_mask'
no shut 
end 
show ip interface brief 

现在,让我们看一下远程设备的 Telnet 示例。为此,请创建一个telnet_example.py脚本,并在其中写入以下内容:

import telnetlib
import getpass
import sys

HOST_IP = "your host ip address"
host_user = input("Enter your telnet username: ")
password = getpass.getpass()

t = telnetlib.Telnet(HOST_IP)
t.read_until(b"Username:")
t.write(host_user.encode("ascii") + b"\n")
if password:
 t.read_until(b"Password:") t.write(password.encode("ascii") + b"\n")

t.write(b"enable\n")
t.write(b"enter_remote_device_password\n") #password of your remote device
t.write(b"conf t\n")
t.write(b"int loop 1\n")
t.write(b"ip add 10.1.1.1 255.255.255.255\n") t.write(b"int loop 2\n") t.write(b"ip add 20.2.2.2 255.255.255.255\n") t.write(b"end\n") t.write(b"exit\n") print(t.read_all().decode("ascii") )

运行脚本,您将获得以下输出:

student@ubuntu:~$ python3 telnet_example.py Output: Enter your telnet username: student Password: 

server>enable Password: server#conf t Enter configuration commands, one per line.  End with CNTL/Z. server(config)#int loop 1 server(config-if)#ip add 10.1.1.1 255.255.255.255 server(config-if)#int loop 23 server(config-if)#ip add 20.2.2.2 255.255.255.255 server(config-if)#end server#exit

在前面的示例中,我们使用telnetlib模块访问并配置了 Cisco 路由器。在此脚本中,首先我们从用户那里获取用户名和密码,以初始化与远程设备的 Telnet 连接。当连接建立时,我们对远程设备进行了进一步的配置。Telnet 之后,我们将能够访问远程服务器或设备。但是 Telnet 协议有一个非常重要的缺点,那就是所有数据,包括用户名和密码都以文本方式通过网络发送,这可能会造成安全风险。因此,现在 Telnet 很少使用,并已被一个名为安全外壳(SSH)的非常安全的协议所取代。

SSH

SSH 是一种网络协议,用于通过远程访问管理设备或服务器。SSH 使用公钥加密来确保安全。Telnet 和 SSH 之间的重要区别在于 SSH 使用加密,这意味着所有通过网络传输的数据都受到未经授权的实时拦截的保护。

用户访问远程服务器或设备必须安装 SSH 客户端。通过在终端中运行以下命令来安装 SSH:

$ sudo apt install ssh

此外,在用户希望通信的远程服务器上,必须安装并运行 SSH 服务器。SSH 使用 TCP 协议,默认情况下在端口号22上运行。

您可以通过终端运行ssh命令如下:

$ ssh host_name@host_ip_address

现在,您将学习如何使用 Python 中的不同模块进行 SSH,例如 subprocess、fabric、Netmiko 和 Paramiko。现在,我们将依次看到这些模块。

subprocess.Popen()模块

Popen类处理进程的创建和管理。使用此模块,开发人员可以处理较少的常见情况。子程序执行将在新进程中完成。要在 Unix/Linux 上执行子程序,该类将使用os.execvp()函数。要在 Windows 中执行子程序,该类将使用CreateProcess()函数。

现在,让我们看一些subprocess.Popen()的有用参数:

class subprocess.Popen(args, bufsize=0, executable=None, stdin=None, stdout=None,
 stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0)

让我们看看每个参数:

  • args:它可以是程序参数的序列或单个字符串。如果args是一个序列,则将执行 args 中的第一项。如果 args 是一个字符串,则建议将 args 作为序列传递。

  • shell:shell 参数默认设置为False,它指定是否使用 shell 来执行程序。如果 shell 为True,则建议将 args 作为字符串传递。在 Linux 中,如果shell=True,shell 默认为/bin/sh。如果args是一个字符串,则该字符串指定要通过 shell 执行的命令。

  • bufsize:如果bufsize0(默认为0),则表示无缓冲,如果bufsize1,则表示行缓冲。如果bufsize是任何其他正值,则使用给定大小的缓冲区。如果bufsize是任何其他负值,则表示完全缓冲。

  • executable:它指定要执行的替换程序。

  • stdinstdoutstderr:这些参数分别定义了标准输入、标准输出和标准错误。

  • preexec_fn:这是设置为可调用对象的,将在子进程中执行之前调用。

  • close_fds:在 Linux 中,如果close_fds为 true,则在执行子进程之前,除了012之外的所有文件描述符都将被关闭。在 Windows 中,如果close_fdstrue,则子进程将不会继承任何句柄。

  • env:如果值不是None,则映射将为新进程定义环境变量。

  • universal_newlines:如果值为True,则stdoutstderr将以换行模式打开为文本文件。

现在,我们将看一个subprocess.Popen()的例子。为此,创建一个ssh_using_sub.py脚本,并在其中写入以下内容:

import subprocess
import sys

HOST="your host username@host ip"
COMMAND= "ls"

ssh_obj = subprocess.Popen(["ssh", "%s" % HOST, COMMAND],
 shell=False,
 stdout=subprocess.PIPE,
 stderr=subprocess.PIPE)

result = ssh_obj.stdout.readlines()
if result == []:
 err = ssh_obj.stderr.readlines()
 print(sys.stderr, "ERROR: %s" % err)
else:
 print(result)

运行脚本,您将得到以下输出:

student@ubuntu:~$ python3 ssh_using_sub.py Output : student@192.168.0.106's password: [b'Desktop\n', b'Documents\n', b'Downloads\n', b'examples.desktop\n', b'Music\n', b'Pictures\n', b'Public\n', b'sample.py\n', b'spark\n', b'spark-2.3.1-bin-hadoop2.7\n', b'spark-2.3.1-bin-hadoop2.7.tgz\n', b'ssh\n', b'Templates\n', b'test_folder\n', b'test.txt\n', b'Untitled1.ipynb\n', b'Untitled.ipynb\n', b'Videos\n', b'work\n']

在前面的例子中,首先我们导入了 subprocess 模块,然后定义了要建立 SSH 连接的主机地址。之后,我们给出了一个在远程设备上执行的简单命令。在所有这些设置完成后,我们将这些信息放入subprocess.Popen()函数中。该函数执行函数内定义的参数,以创建与远程设备的连接。建立 SSH 连接后,执行我们定义的命令并提供结果。然后我们在终端上打印 SSH 的结果,如输出所示。

使用 fabric 模块的 SSH

Fabric 是一个 Python 库,也是一个用于 SSH 的命令行工具。它用于系统管理和应用程序在网络上的部署。我们还可以通过 SSH 执行 shell 命令。

要使用 fabric 模块,首先您必须使用以下命令安装它:

$ pip3 install fabric3

现在,我们将看一个例子。创建一个fabfile.py脚本,并在其中写入以下内容:

from fabric.api import * env.hosts=["host_name@host_ip"] env.password='your password'  def dir(): run('mkdir fabric') print('Directory named fabric has been created on your host network') def diskspace():
 run('df') 

运行脚本,您将得到以下输出:

student@ubuntu:~$ fab dir Output: [student@192.168.0.106] Executing task 'dir' [student@192.168.0.106] run: mkdir fabric
Done. Disconnecting from 192.168.0.106... done.

在前面的例子中,首先我们导入了fabric.api模块,然后设置了主机名和密码以连接到主机网络。之后,我们设置了不同的任务以通过 SSH 执行。因此,为了执行我们的程序而不是 Python3 的fabfile.py,我们使用了fab实用程序(fab dir),然后我们声明应该从我们的fabfile.py执行所需的任务。在我们的情况下,我们执行了dir任务,在您的远程网络上创建了一个名为'fabric'的目录。您可以在您的 Python 文件中添加您的特定任务。它可以使用 fabric 模块的fab实用程序执行。

使用 Paramiko 库的 SSH

Paramiko 是一个实现 SSHv2 协议用于远程设备安全连接的库。Paramiko 是围绕 SSH 的纯 Python 接口。

在使用 Paramiko 之前,请确保您已经在系统上正确安装了它。如果尚未安装,可以通过在终端中运行以下命令来安装它:

$ sudo pip3 install paramiko

现在,我们将看一个使用paramiko的例子。对于这个paramiko连接,我们使用的是 Cisco 设备。Paramiko 支持基于密码和基于密钥对的身份验证,以确保与服务器的安全连接。在我们的脚本中,我们使用基于密码的身份验证,这意味着我们检查密码,如果可用,将尝试使用普通用户名/密码身份验证。在对远程设备或多层路由器进行 SSH 之前,请确保它们已经正确配置,如果没有,您可以使用以下命令在多层路由器终端中进行基本配置:

configure t
ip domain-name cciepython.com
crypto key generate rsa
How many bits in the modulus [512]: 1024
interface range f0/0 - 1
switchport mode access
switchport access vlan 1
no shut
int vlan 1
ip add 'set_ip_address_to_the_router' 'put_subnet_mask'
no shut
exit
enable password 'set_Your_password_to_access_router'
username 'set_username' password 'set_password_for_remote_access'
username 'username' privilege 15
line vty 0 4
login local
transport input all
end

现在,创建一个pmiko.py脚本,并在其中写入以下内容:

import paramiko
import time

ip_address = "host_ip_address"
usr = "host_username"
pwd = "host_password"

c = paramiko.SSHClient()
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
c.connect(hostname=ip_address,username=usr,password=pwd)

print("SSH connection is successfully established with ", ip_address)
rc = c.invoke_shell() for n in range (2,6):
 print("Creating VLAN " + str(n)) rc.send("vlan database\n") rc.send("vlan " + str(n) +  "\n") rc.send("exit\n") time.sleep(0.5) time.sleep(1) output = rc.recv(65535) print(output) c.close

运行脚本,您将得到以下输出:

student@ubuntu:~$ python3 pmiko.py Output: SSH connection is successfuly established with  192.168.0.70 Creating VLAN 2 Creating VLAN 3 Creating VLAN 4 Creating VLAN 5

在上面的例子中,首先我们导入了paramiko模块,然后定义了连接到远程设备所需的 SSH 凭据。提供凭据后,我们创建了paramiko.SSHclient()的实例'c',这是用于与远程设备建立连接并执行命令或操作的主要客户端。创建SSHClient对象允许我们使用.connect()函数建立远程连接。然后,我们设置了paramiko连接的策略,因为默认情况下,paramiko.SSHclient将 SSH 策略设置为拒绝策略状态。这会导致策略拒绝任何未经验证的 SSH 连接。在我们的脚本中,我们使用AutoAddPolicy()函数来忽略 SSH 连接中断的可能性,该函数会自动添加服务器的主机密钥而无需提示。我们只能在测试目的中使用此策略,但出于安全目的,这不是生产环境中的好选择。

当建立 SSH 连接时,您可以在设备上进行任何配置或操作。在这里,我们在远程设备上创建了一些虚拟局域网。创建 VLAN 后,我们只是关闭了连接。

使用 Netmiko 库进行 SSH

在本节中,我们将学习 Netmiko。Netmiko 库是 Paramiko 的高级版本。它是一个基于 Paramiko 的multi_vendor库。Netmiko 简化了与网络设备的 SSH 连接,并对设备进行特定操作。在对远程设备或多层路由器进行 SSH 之前,请确保它们已经正确配置,如果没有,您可以使用 Paramiko 部分中提到的命令进行基本配置。

现在,让我们看一个例子。创建一个nmiko.py脚本,并在其中写入以下代码:

from netmiko import ConnectHandler

remote_device={
 'device_type': 'cisco_ios',
 'ip':  'your remote_device ip address',
 'username': 'username',
 'password': 'password',
}

remote_connection = ConnectHandler(**remote_device)
#net_connect.find_prompt()

for n in range (2,6):
 print("Creating VLAN " + str(n))
 commands = ['exit','vlan database','vlan ' + str(n), 'exit']
 output = remote_connection.send_config_set(commands)
 print(output)

command = remote_connection.send_command('show vlan-switch brief')
print(command)

运行脚本,您将得到以下输出:

student@ubuntu:~$ python3 nmiko.py Output: Creating VLAN 2 config term Enter configuration commands, one per line.  End with CNTL/Z. server(config)#exit server #vlan database server (vlan)#vlan 2 VLAN 2 modified: server (vlan)#exit APPLY completed. Exiting.... server # .. .. .. .. switch# Creating VLAN 5 config term Enter configuration commands, one per line.  End with CNTL/Z. server (config)#exit server #vlan database server (vlan)#vlan 5 VLAN 5 modified: server (vlan)#exit APPLY completed. Exiting.... VLAN Name                             Status    Ports ---- -------------------------------- --------- ------------------------------- 1    default                          active    Fa0/0, Fa0/1, Fa0/2, Fa0/3, Fa0/4, Fa0/5, Fa0/6, Fa0/7, Fa0/8, Fa0/9, Fa0/10, Fa0/11, Fa0/12, Fa0/13, Fa0/14, Fa0/15 2    VLAN0002                         active 3    VLAN0003                         active 4    VLAN0004                         active 5    VLAN0005                         active 1002 fddi-default                    active 1003 token-ring-default         active 1004 fddinet-default               active 1005 trnet-default                    active

在上面的例子中,我们使用 Netmiko 库来进行 SSH,而不是 Paramiko。在这个脚本中,首先我们从 Netmiko 库中导入ConnectHandler,然后通过传递设备字典(在我们的情况下是remote_device)来建立与远程网络设备的 SSH 连接。连接建立后,我们执行配置命令,使用send_config_set()函数创建了多个虚拟局域网。

当我们使用这种类型(.send_config_set())的函数在远程设备上传递命令时,它会自动将我们的设备设置为配置模式。在发送配置命令后,我们还传递了一个简单的命令来获取有关配置设备的信息。

摘要

在本章中,您学习了 Telnet 和 SSH。您还学习了不同的 Python 模块,如 telnetlib、subprocess、fabric、Netmiko 和 Paramiko,使用这些模块可以执行 Telnet 和 SSH。SSH 使用公钥加密以确保安全,并且比 Telnet 更安全。

在下一章中,我们将使用各种 Python 库,您可以使用这些库创建图形用户界面。

问题

  1. 什么是客户端-服务器架构?

  2. 如何在 Python 代码中运行特定于操作系统的命令?

  3. 局域网和虚拟局域网之间有什么区别?

  4. 以下代码的输出是什么?

 List = [‘a’, ‘b’, ‘c’, ‘d’, ‘e’]
 Print(list [10:])
  1. 编写一个 Python 程序来显示日历(提示:使用calendar模块)。

  2. 编写一个 Python 程序来计算文本文件中的行数。

进一步阅读

第十三章:构建图形用户界面

在本章中,您将学习图形用户界面GUI)开发。有各种 Python 库可用于创建 GUI。我们将学习 PyQt5 Python 库用于 GUI 创建。

在本章中,您将学习以下主题:

  • GUI 简介

  • 使用库创建基于 GUI 的应用程序

  • 安装和使用 Apache Log Viewer 应用程序

GUI 简介

在本节中,我们将学习 GUI。Python 有各种 GUI 框架。在本节中,我们将看看 PyQt5。PyQt5 具有不同的图形组件,也称为对象小部件,可以显示在屏幕上并与用户交互。以下是这些组件的列表:

  • PyQt5 窗口:PyQt5 窗口将创建一个简单的应用程序窗口。

  • PyQt5 按钮:PyQt5 按钮是一个在点击时会引发动作的按钮。

  • PyQt5 文本框:PyQt5 文本框小部件允许用户输入文本。

  • PyQt5 标签:PyQt5 标签小部件显示单行文本或图像。

  • PyQt5 组合框:PyQt5 组合框小部件是一个组合按钮和弹出列表。

  • PyQt5 复选框:PyQt5 复选框小部件是一个可以选中和取消选中的选项按钮。

  • PyQt5 单选按钮:PyQt5 单选按钮小部件是一个可以选中或取消选中的选项按钮。在一组单选按钮中,只能同时选中一个按钮。

  • PyQt5 消息框:PyQt5 消息框小部件显示一条消息。

  • PyQt5 菜单:PyQt5 菜单小部件提供显示的不同选择。

  • PyQt5 表格:PyQt5 表格小部件为应用程序提供标准表格显示功能,可以构建具有多行和列的表格。

  • PyQt5 信号/槽:信号将让您对发生的事件做出反应,而槽只是在信号发生时调用的函数。

  • PyQt5 布局:PyQt5 布局由多个小部件组成。

有几个 PyQt5 类可用,分为不同的模块。这些模块在这里列出:

  • QtGuiQtGui包含用于事件处理、图形、字体、文本和基本图像的类。

  • QtWidgetsQtWidgets包含用于创建桌面样式用户界面的类。

  • QtCoreQtCore包含核心非 GUI 功能,如时间、目录、文件、流、URL、数据类型、线程和进程。

  • QtBluetoothQtBluetooth包含用于连接设备和与其交互的类。

  • QtPositioningQtPositioning包含用于确定位置的类。

  • QtMultimediaQtMultimedia包含用于 API 和多媒体内容的类。

  • QtNetworkQtNetwork包含用于网络编程的类。

  • QtWebKitQtWebkit包含用于 Web 浏览器实现的类。

  • QtXmlQtXml包含用于 XML 文件的类。

  • QtSqlQtSql包含用于数据库的类。

GUI 由事件驱动。现在,什么是事件?事件是指示程序中发生了某些事情的信号,例如菜单选择、鼠标移动或按钮点击。事件由函数处理,并在用户对对象执行某些操作时触发。监听器将监听事件,然后在事件发生时调用事件处理程序。

使用库创建基于 GUI 的应用程序

现在,我们实际上将使用 PyQt5 库创建一个简单的 GUI 应用程序。在本节中,我们将创建一个简单的窗口。在该窗口中,我们将有一个按钮和一个标签。单击该按钮后,标签中将打印一些消息。

首先,我们将看看如何创建按钮小部件。以下行将创建一个按钮小部件:

            b = QPushButton('Click', self)

现在,我们将看看如何创建标签。以下行将创建一个标签:

 l = QLabel(self)

现在,我们将看到如何创建按钮和标签,以及如何在点击按钮后执行操作。为此,创建一个print_message.py脚本,并在其中编写以下代码:

import sys from PyQt5.QtWidgets import QApplication, QLabel, QPushButton, QWidget from PyQt5.QtCore import pyqtSlot from PyQt5.QtGui import QIcon class simple_app(QWidget):
 def __init__(self): super().__init__() self.title = 'Main app window' self.left = 20 self.top = 20 self.height = 300 self.width = 400 self.app_initialize() def app_initialize(self): self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.height, self.width) b = QPushButton('Click', self) b.setToolTip('Click on the button !!') b.move(100,70) self.l = QLabel(self) self.l.resize(100,50) self.l.move(100,200) b.clicked.connect(self.on_click) self.show() @pyqtSlot() def on_click(self):self.l.setText("Hello World") if __name__ == '__main__':
 appl = QApplication(sys.argv) ex = simple_app() sys.exit(appl.exec_())

运行脚本,您将得到以下输出:

student@ubuntu:~/gui_example$ python3 print_message.py

在上面的例子中,我们导入了必要的 PyQt5 模块。然后,我们创建了应用程序。QPushButton创建了小部件,我们输入的第一个参数是将在按钮上打印的文本。接下来,我们有一个QLabel小部件,我们在上面打印一条消息,当我们点击按钮时将打印出来。接下来,我们创建了一个on_click()函数,它将在点击按钮后执行打印操作。on_click()是我们创建的槽。

现在,我们将看到一个框布局的示例。为此,创建一个box_layout.py脚本,并在其中编写以下代码:

from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout appl = QApplication([]) make_window = QWidget() layout = QVBoxLayout() layout.addWidget(QPushButton('Button 1')) layout.addWidget(QPushButton('Button 2')) make_window.setLayout(l) make_window.show() appl.exec_()

运行脚本,您将得到以下输出:

student@ubuntu:~/gui_example$ python3 box_layout.py

在上面的例子中,我们创建了一个框布局。在其中,我们放置了两个按钮。这个脚本只是为了解释框布局。l = QVBoxLayout()将创建一个框布局。

安装和使用 Apache 日志查看器应用程序

由于我们已经有了 Apache 日志查看器应用程序,请从以下链接下载 Apache 日志查看器应用程序:www.apacheviewer.com/download/

下载后,在您的计算机上安装该应用程序。该应用程序可用于根据其连接状态、IP 地址等分析日志文件。因此,要分析日志文件,我们可以简单地浏览访问日志文件或错误日志文件。获得文件后,我们对日志文件应用不同的操作,例如应用筛选器,例如仅对access.log中的未成功连接进行排序,或者按特定 IP 地址进行筛选。

以下截图显示了 Apache 日志查看器与access.log文件,没有应用筛选器:

以下截图显示了应用筛选器后的 Apache 日志查看器与access.log文件:

在第一种情况下,我们取得了访问日志文件,并在 Apache 日志查看器中打开了它。我们可以很容易地看到,在 Apache 日志查看器中打开的访问文件包含各种条目,如授权和未授权的,以及它们的状态、IP 地址、请求等。然而,在第二种情况下,我们对访问日志文件应用了筛选器,以便只能看到未经授权请求的日志条目,如截图所示。

摘要

在本节中,我们学习了 GUI。我们学习了 GUI 中使用的组件。我们学习了 Python 中的 PyQt5 模块。使用 PyQt5 模块,我们创建了一个简单的应用程序,在点击按钮后将在标签中打印一条消息。

在下一章中,您将学习如何处理 Apache 日志文件。

问题

  1. 什么是 GUI?

  2. Python 中的构造函数和析构函数是什么?

  3. self的用途是什么?

  4. 比较 Tkinter、PyQt 和 wxPython。

  5. 创建一个 Python 程序,将一个文件的内容复制到另一个文件中

  6. 创建一个 Python 程序,读取文本文件并计算文本文件中某个字母出现的次数。

进一步阅读

第十四章:使用 Apache 和其他日志文件

在本章中,您将学习有关日志文件的知识。您将学习如何解析日志文件。您还将了解为什么需要在程序中编写异常。解析不同文件的不同方法也很重要。您还将了解ErrorLogAccessLog。最后,您将学习如何解析其他日志文件。

在本章中,您将学习以下内容:

  • 解析复杂的日志文件

  • 异常的需要

  • 解析不同文件的技巧

  • 错误日志

  • 访问日志

  • 解析其他日志文件

解析复杂的日志文件

首先,我们将研究解析复杂日志文件的概念。解析日志文件是一项具有挑战性的任务,因为大多数日志文件都是以纯文本格式,而且该格式没有遵循任何规则。这些文件可能会在不显示任何警告的情况下进行修改。用户可以决定他们将在日志文件中存储什么类型的数据以及以何种格式存储,以及谁将开发应用程序。

在进行日志解析示例或更改日志文件中的配置之前,我们首先必须了解典型日志文件中包含什么。根据这一点,我们必须决定我们将学习如何操作或从中获取信息。我们还可以在日志文件中查找常见术语,以便我们可以使用这些常见术语来获取数据。

通常,您会发现日志文件中生成的大部分内容是由应用程序容器生成的,还有系统访问状态的条目(换句话说,注销和登录)或通过网络访问的系统的条目。因此,当您的系统通过网络远程访问时,这种远程连接的条目将保存在日志文件中。让我们以这种情况为例。我们已经有一个名为access.log的文件,其中包含一些日志信息。

因此,让我们创建一个名为read_apache_log.py的脚本,并在其中写入以下内容:

def read_apache_log(logfile):
 with open(logfile) as f: log_obj = f.read() print(log_obj) if __name__ == '__main__':
 read_apache_log("access.log")

运行脚本,您将得到以下输出:

student@ubuntu:~$ python3 read_apache_log.py Output: 64.242.88.10 - - [07/Mar/2004:16:05:49 -0800] "GET /twiki/bin/edit/Main/Double_bounce_sender?topicparent=Main.ConfigurationVariables HTTP/1.1" 401 12846 64.242.88.10 - - [07/Mar/2004:16:06:51 -0800] "GET /twiki/bin/rdiff/TWiki/NewUserTemplate?rev1=1.3&rev2=1.2 HTTP/1.1" 200 4523 64.242.88.10 - - [07/Mar/2004:16:10:02 -0800] "GET /mailman/listinfo/hsdivision HTTP/1.1" 200 6291 64.242.88.10 - - [07/Mar/2004:16:11:58 -0800] "GET /twiki/bin/view/TWiki/WikiSyntax HTTP/1.1" 200 7352 64.242.88.10 - - [07/Mar/2004:16:20:55 -0800] "GET /twiki/bin/view/Main/DCCAndPostFix HTTP/1.1" 200 5253 64.242.88.10 - - [07/Mar/2004:16:23:12 -0800] "GET /twiki/bin/oops/TWiki/AppendixFileSystem?template=oopsmore&param1=1.12&param2=1.12 HTTP/1.1" 200 11382 64.242.88.10 - - [07/Mar/2004:16:24:16 -0800] "GET /twiki/bin/view/Main/PeterThoeny HTTP/1.1" 200 4924 64.242.88.10 - - [07/Mar/2004:16:29:16 -0800] "GET /twiki/bin/edit/Main/Header_checks?topicparent=Main.ConfigurationVariables HTTP/1.1" 401 12851 64.242.88.10 - - [07/Mar/2004:16:30:29 -0800] "GET /twiki/bin/attach/Main/OfficeLocations HTTP/1.1" 401 12851 64.242.88.10 - - [07/Mar/2004:16:31:48 -0800] "GET /twiki/bin/view/TWiki/WebTopicEditTemplate HTTP/1.1" 200 3732 64.242.88.10 - - [07/Mar/2004:16:32:50 -0800] "GET /twiki/bin/view/Main/WebChanges HTTP/1.1" 200 40520 64.242.88.10 - - [07/Mar/2004:16:33:53 -0800] "GET /twiki/bin/edit/Main/Smtpd_etrn_restrictions?topicparent=Main.ConfigurationVariables HTTP/1.1" 401 12851 64.242.88.10 - - [07/Mar/2004:16:35:19 -0800] "GET /mailman/listinfo/business HTTP/1.1" 200 6379 …..

在前面的示例中,我们创建了一个read_apache_log函数来读取 Apache 日志文件。在其中,我们打开了一个日志文件,然后打印了其中的日志条目。在定义了read_apache_log()函数之后,我们在主函数中调用了它,并传入了 Apache 日志文件的名称。在我们的案例中,Apache 日志文件的名称是access.log

access.log文件中读取日志条目后,现在我们将从日志文件中解析 IP 地址。为此,请创建一个名为parse_ip_address.py的脚本,并在其中写入以下内容:

import re from collections import Counter r_e = r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' with open("access.log") as f:
 print("Reading Apache log file") Apache_log = f.read() get_ip = re.findall(r_e,Apache_log) no_of_ip = Counter(get_ip) for k, v in no_of_ip.items(): print("Available IP Address in log file " + "=> " + str(k) + " " + "Count "  + "=> " + str(v))

运行脚本,您将得到以下输出:

student@ubuntu:~/work/Chapter_15$ python3 parse_ip_address.py Output: Reading Apache log file Available IP Address in log file => 64.242.88.1 Count => 452 Available IP Address in log file => 213.181.81.4 Count => 1 Available IP Address in log file => 213.54.168.1 Count => 12 Available IP Address in log file => 200.160.249.6 Count => 2 Available IP Address in log file => 128.227.88.7 Count => 14 Available IP Address in log file => 61.9.4.6 Count => 3 Available IP Address in log file => 212.92.37.6 Count => 14 Available IP Address in log file => 219.95.17.5 Count => 1 3Available IP Address in log file => 10.0.0.1 Count => 270 Available IP Address in log file => 66.213.206.2 Count => 1 Available IP Address in log file => 64.246.94.1 Count => 2 Available IP Address in log file => 195.246.13.1 Count => 12 Available IP Address in log file => 195.230.181.1 Count => 1 Available IP Address in log file => 207.195.59.1 Count => 20 Available IP Address in log file => 80.58.35.1 Count => 1 Available IP Address in log file => 200.222.33.3 Count => 1 Available IP Address in log file => 203.147.138.2 Count => 13 Available IP Address in log file => 212.21.228.2 Count => 1 Available IP Address in log file => 80.58.14.2 Count => 4 Available IP Address in log file => 142.27.64.3 Count => 7 ……

在前面的示例中,我们创建了 Apache 日志解析器来确定服务器上一些特定 IP 地址及其请求次数。因此,很明显我们不想要 Apache 日志文件中的整个日志条目,我们只想从日志文件中获取 IP 地址。为此,我们必须定义一个模式来搜索 IP 地址,我们可以通过使用正则表达式来实现。因此,我们导入了re模块。然后我们导入了Collection模块作为 Python 内置数据类型dictlistsettuple的替代品。该模块具有专门的容器数据类型。在导入所需的模块后,我们使用正则表达式编写了一个模式,以匹配从日志文件中映射 IP 地址的特定条件。

在匹配模式中,\d可以是09之间的任何数字,\r代表原始字符串。然后,我们打开名为access.log的 Apache 日志文件并读取它。之后,我们在 Apache 日志文件上应用了正则表达式条件,然后使用collection模块的counter函数来获取我们根据re条件获取的每个 IP 地址的计数。最后,我们打印了操作的结果,如输出中所示。

异常的需要

在这一部分,我们将看看 Python 编程中异常的需要。正常的程序流程包括事件和信号。异常一词表明您的程序出了问题。这些异常可以是任何类型,比如零除错误、导入错误、属性错误或断言错误。这些异常会在指定的函数无法正常执行其任务时发生。一旦异常发生,程序执行就会停止,解释器将继续进行异常处理过程。异常处理过程包括在try…except块中编写代码。异常处理的原因是您的程序发生了意外情况。

分析异常

在这一部分,我们将了解分析异常。每个发生的异常都必须被处理。您的日志文件也应该包含一些异常。如果您多次遇到类似类型的异常,那么您的程序存在一些问题,您应该尽快进行必要的更改。

考虑以下例子:

f = open('logfile', 'r') print(f.read()) f.close()

运行程序后,您将得到以下输出:

Traceback (most recent call last):
 File "sample.py", line 1, in <module> f = open('logfile', 'r') FileNotFoundError: [Errno 2] No such file or directory: 'logfile'

在这个例子中,我们试图读取一个在我们目录中不存在的文件,结果显示了一个错误。因此,通过错误我们可以分析我们需要提供什么样的解决方案。为了处理这种情况,我们可以使用异常处理技术。所以,让我们看一个使用异常处理技术处理错误的例子。

考虑以下例子:

try:
    f = open('logfile', 'r')
 print(f.read()) f.close()
except:
    print("file not found. Please check whether the file is present in your directory or not.") 

运行程序后,您将得到以下输出:

file not found. Please check whether the file is present in your directory or not.

在这个例子中,我们试图读取一个在我们目录中不存在的文件。但是,在这个例子中,我们使用了文件异常技术,将我们的代码放在try:except:块中。因此,如果在try:块中发生任何错误或异常,它将跳过该错误并执行except:块中的代码。在我们的情况下,我们只在except:块中放置了一个print语句。因此,在运行脚本后,当异常发生在try:块中时,它会跳过该异常并执行except:块中的代码。因此,在except块中的print语句会被执行,正如我们在之前的输出中所看到的。

解析不同文件的技巧

在这一部分,我们将学习解析不同文件时使用的技巧。在开始实际解析之前,我们必须先读取数据。您需要了解您将从哪里获取所有数据。但是,您也必须记住所有的日志文件大小都不同。为了简化您的任务,这里有一个要遵循的清单:

  • 请记住,日志文件可以是纯文本或压缩文件。

  • 所有日志文件都有一个.log扩展名的纯文本文件和一个log.bz2扩展名的bzip2文件。

  • 您应该根据文件名处理文件集。

  • 所有日志文件的解析必须合并成一个报告。

  • 您使用的工具必须能够处理所有文件,无论是来自指定目录还是来自不同目录。所有子目录中的日志文件也应包括在内。

错误日志

在这一部分,我们将学习错误日志。错误日志的相关指令如下:

  • ErrorLog

  • LogLevel

服务器日志文件的位置和名称由ErrorLog指令设置。这是最重要的日志文件。Apache httpd发送的信息和处理过程中产生的记录都在其中。每当服务器出现问题时,这将是第一个需要查看的地方。它包含了出现问题的细节以及修复问题的过程。

错误日志被写入文件中。在 Unix 系统上,服务器可以将错误发送到syslog,或者您可以将它们传送到您的程序中。日志条目中的第一件事是消息的日期和时间。第二个条目记录了错误的严重程度。

LogLevel指令通过限制严重级别处理发送到错误日志的错误。第三个条目包含生成错误的客户端的信息。该信息将是 IP 地址。接下来是消息本身。它包含了服务器已配置为拒绝客户端访问的信息。服务器将报告所请求文档的文件系统路径。

错误日志文件中可能出现各种类型的消息。错误日志文件还包含来自 CGI 脚本的调试输出。无论信息写入stderr,都将直接复制到错误日志中。

错误日志文件是不可定制的。处理请求的错误日志中的条目将在访问日志中有相应的条目。您应该始终监视错误日志以解决测试期间的问题。在 Unix 系统上,您可以运行以下命令来完成这个任务:

$ tail -f error_log

访问日志

在本节中,您将学习访问日志。服务器访问日志将记录服务器处理的所有请求。CustomLog指令控制访问日志的位置和内容。LogFormat指令用于选择日志的内容。

将信息存储在访问日志中意味着开始日志管理。下一步将是分析帮助我们获得有用统计信息的信息。Apache httpd有各种版本,这些版本使用了一些其他模块和指令来控制访问日志记录。您可以配置访问日志的格式。这个格式是使用格式字符串指定的。

通用日志格式

在本节中,我们将学习通用日志格式。以下语法显示了访问日志的配置:

 LogFormat "%h %l %u %t \"%r\" %>s %b" nick_name
 CustomLog logs/access_log nick_name

这个字符串将定义一个昵称,然后将该昵称与日志格式字符串关联起来。日志格式字符串由百分比指令组成。每个百分比指令告诉服务器记录特定的信息。这个字符串可能包含文字字符。这些字符将直接复制到日志输出中。

CustomLog指令将使用定义的昵称设置一个新的日志文件。访问日志的文件名相对于ServerRoot,除非以斜杠开头。

我们之前提到的配置将以通用日志格式CLF)写入日志条目。这是一种标准格式,可以由许多不同的 Web 服务器生成。许多日志分析程序读取这种日志格式。

现在,我们将看到每个百分比指令的含义:

  • %h:这显示了向 Web 服务器发出请求的客户端的 IP 地址。如果HostnameLookups打开,那么服务器将确定主机名并将其记录在 IP 地址的位置。

  • %l:这个术语用于指示所请求的信息不可用。

  • %u:这是请求文档的用户 ID。相同的值将在REMOTE_USER环境变量中提供给 CGI 脚本。

  • %t:这个术语用于检测服务器处理请求完成的时间。格式如下:

            [day/month/year:hour:minute:second zone]

对于day参数,需要两位数字。对于month,我们必须定义三个字母。对于年份,由于年份有四个字符,我们必须取四位数字。现在,在daymonthyear之后,我们必须为hourminuteseconds各取两位数字。

  • \"%r\":这个术语用作请求行,客户端用双引号给出。这个请求行包含有用的信息。请求客户端使用GET方法,使用的协议是 HTTP。

  • %>s:这个术语定义了客户端的状态代码。状态代码非常重要和有用,因为它指示了客户端发送的请求是否成功地发送到服务器。

  • %b:这个术语定义了对象返回给客户端时的总大小。这个总大小不包括响应头的大小。

解析其他日志文件

我们的系统中还有其他不同的日志文件,包括 Apache 日志。在我们的 Linux 发行版中,日志文件位于根文件系统中的/var/log/文件夹中,如下所示:

在上面的屏幕截图中,我们可以很容易地看到不同类型的日志文件(例如,认证日志文件auth.log,系统日志文件syslog和内核日志kern.log)可用于不同的操作条目。当我们对 Apache 日志文件执行操作时,如前所示,我们也可以对本地日志文件执行相同类型的操作。让我们看一个以前解析日志文件的例子。在simple_log.py脚本中创建并写入以下内容:

f=open('/var/log/kern.log','r') lines = f.readlines() for line in lines:
 kern_log = line.split() print(kern_log) f.close()

运行脚本,您将得到以下输出:

student@ubuntu:~$ python3 simple_log.py Output:
 ['Dec', '26', '14:39:38', 'ubuntu', 'NetworkManager[795]:', '<info>', '[1545815378.2891]', 'device', '(ens33):', 'state', 'change:', 'prepare', '->', 'config', '(reason', "'none')", '[40', '50', '0]'] ['Dec', '26', '14:39:38', 'ubuntu', 'NetworkManager[795]:', '<info>', '[1545815378.2953]', 'device', '(ens33):', 'state', 'change:', 'config', '->', 'ip-config', '(reason', "'none')", '[50', '70', '0]'] ['Dec', '26', '14:39:38', 'ubuntu', 'NetworkManager[795]:', '<info>', '[1545815378.2997]', 'dhcp4', '(ens33):', 'activation:', 'beginning', 'transaction', '(timeout', 'in', '45', 'seconds)'] ['Dec', '26', '14:39:38', 'ubuntu', 'NetworkManager[795]:', '<info>', '[1545815378.3369]', 'dhcp4', '(ens33):', 'dhclient', 'started', 'with', 'pid', '5221'] ['Dec', '26', '14:39:39', 'ubuntu', 'NetworkManager[795]:', '<info>', '[1545815379.0008]', 'address', '192.168.0.108'] ['Dec', '26', '14:39:39', 'ubuntu', 'NetworkManager[795]:', '<info>', '[1545815379.0020]', 'plen', '24', '(255.255.255.0)'] ['Dec', '26', '14:39:39', 'ubuntu', 'NetworkManager[795]:', '<info>', '[1545815379.0028]', 'gateway', '192.168.0.1']

在上面的例子中,首先我们创建了一个简单的文件对象f,并以读模式在其中打开了kern.log文件。之后,我们在file对象上应用了readlines()函数,以便在for循环中逐行读取文件中的数据。然后我们对内核日志文件的每一行应用了split()函数,然后使用print函数打印整个文件,如输出所示。

像读取内核日志文件一样,我们也可以对其执行各种操作,就像我们现在要执行一些操作一样。现在,我们将通过索引访问内核日志文件中的内容。这是可能的,因为split函数将文件中的所有信息拆分为不同的迭代。因此,让我们看一个这样的条件的例子。创建一个simple_log1.py脚本,并将以下脚本放入其中:

f=open('/var/log/kern.log','r') lines = f.readlines() for line in lines:
 kern_log = line.split()[1:3] print(kern_log)

运行脚本,您将获得以下输出:

student@ubuntu:~$ python3 simple_log1.py Output: ['26', '14:37:20'] ['26', '14:37:20'] ['26', '14:37:32'] ['26', '14:39:38'] ['26', '14:39:38'] ['26', '14:39:38'] ['26', '14:39:38'] ['26', '14:39:38'] ['26', '14:39:38'] ['26', '14:39:38'] ['26', '14:39:38'] ['26', '14:39:38'] 

在上面的例子中,我们只是在split函数旁边添加了[1:3],换句话说,切片。序列的子序列称为切片,提取子序列的操作称为切片。在我们的例子中,我们使用方括号([ ])作为切片运算符,并在其中有两个整数值,用冒号(:)分隔。操作符[1:3]返回序列的第一个元素到第三个元素的部分,包括第一个但不包括最后一个。当我们对任何序列进行切片时,我们得到的子序列始终与从中派生的原始序列具有相同的类型。

然而,列表(或元组)的元素可以是任何类型;无论我们如何对其进行切片,列表的派生切片都是列表。因此,在对日志文件进行切片后,我们得到了先前显示的输出。

摘要

在本章中,您学习了如何处理不同类型的日志文件。您还了解了解析复杂日志文件以及在处理这些文件时异常处理的必要性。解析日志文件的技巧将有助于顺利进行解析。您还了解了ErrorLogAccessLog

在下一章中,您将学习有关 SOAP 和 REST 通信的内容。

问题

  1. Python 中运行时异常和编译时异常有什么区别?

  2. 什么是正则表达式?

  3. 探索 Linux 命令headtailcatawk

  4. 编写一个 Python 程序,将一个文件的内容追加到另一个文件中。

  5. 编写一个 Python 程序,以相反的顺序读取文件的内容。

  6. 以下表达式的输出将是什么?

  7. re.search(r'C\Wke', 'C@ke').group()

  8. re.search(r'Co+kie', 'Cooookie').group()

  9. re.match(r'<.*?>', '<h1>TITLE</h1>').group()

进一步阅读

第十五章:SOAP 和 REST API 通信

在本章中,我们将了解 SOAP 和 REST API 的基础知识。我们还将了解 Python 用于 SOAP 和 REST API 的库。我们将学习有关 SOAP 的 Zeep 库和 REST API 的请求。您将学习如何处理 JSON 数据。我们将看到处理 JSON 数据的简单示例,例如将 JSON 字符串转换为 Python 对象和将 Python 对象转换为 JSON 字符串。

在本章中,您将学习以下内容:

  • SOAP 是什么?

  • 使用 SOAP 的库

  • 什么是 RESTful API?

  • 使用标准库进行 RESTful API

  • 处理 JSON 数据

SOAP 是什么?

SOAP简单对象访问协议。SOAP 是允许进程使用不同操作系统的标准通信协议系统。这些通过 HTTP 和 XML 进行通信。它是一种 Web 服务技术。SOAP API 主要用于创建,更新,删除和恢复数据等任务。SOAP API 使用 Web 服务描述语言来描述 Web 服务提供的功能。SOAP 描述所有功能和数据类型。它构建了一个基于 XML 的协议。

使用 SOAP 的库

在本节中,我们将学习有关 Python 用于 SOAP 的库。以下是用于 SOAP 的各种库:

  • SOAPpy

  • Zeep

  • Ladon

  • suds-jurko

  • pysimplesoap

这些是 Python 的 SOAP API 库。在本节中,我们将只学习有关 Zeep 库的知识。

要使用 Zeep 的功能,您首先需要安装它。在终端中运行以下命令以安装 Zeep:

 $ pip3 install Zeep

Zeep模块用于 WSDL 文档。它为服务和文档生成代码,并为 SOAP 服务器提供编程接口。lxml库用于解析 XML 文档。

现在,我们将看一个例子。创建一个soap_example.py脚本,并在其中写入以下代码:

import zeep w = 'http://www.soapclient.com/xml/soapresponder.wsdl' c = zeep.Client(wsdl=w) print(c.service.Method1('Hello', 'World'))

运行脚本,您将得到以下输出:

student@ubuntu:~$ python3 soap_example.py Output : Your input parameters are Hello and World

在上面的例子中,我们首先导入了zeep模块。我们首先提到了网站名称。然后我们创建了zeep客户端对象。我们之前使用的 WSDL 定义了一个简单的Method1函数,通过zeep通过client.service.Method1提供。它接受两个参数并返回一个字符串。

什么是 RESTful API?

REST代表表述性状态转移。RESTful API 是在 Web 服务开发中使用的一种通信方法。它是一种作为互联网上不同系统之间通信渠道的 Web 服务风格。它是一个应用程序接口,用于使用HTTP请求GETPUTPOSTDELETE数据。

REST 的优势在于它使用的带宽较少,适合互联网使用。REST API 使用统一的接口。所有资源都由GETPOSTPUTDELETE操作处理。REST API 使用GET来检索资源,使用PUT来更新资源或更改资源状态,使用POST来创建资源,使用DELETE来删除资源。使用 REST API 的系统提供快速性能和可靠性。

REST API 独立处理每个请求。从客户端到服务器的请求必须包含理解该请求所需的所有信息。

使用标准库进行 RESTful API

在本节中,我们将学习如何使用 RESTful API。为此,我们将使用 Python 的requests和 JSON 模块。我们现在将看一个例子。首先,我们将使用requests模块从 API 获取信息。我们将看到GETPOST请求。

首先,您必须安装requests库,如下所示:

 $ pip3 install requests

现在,我们将看一个例子。创建一个rest_get_example.py脚本,并在其中写入以下内容:

import requests req_obj = requests.get('https://www.imdb.com/news/top?ref_=nv_tp_nw') print(req_obj)

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 rest_get_example.py Output: <Response [200]>

在前面的示例中,我们导入了requests模块来获取请求。接下来,我们创建了一个请求对象req_obj,并指定了我们想要获取请求的链接。然后,我们打印了它。我们得到的输出是状态码200,表示成功。

现在,我们将看到POST请求的示例。POST请求用于向服务器发送数据。创建一个rest_post_example.py脚本,并在其中写入以下内容:

import requests import json url_name = 'http://httpbin.org/post' data = {"Name" : "John"} data_json = json.dumps(data) headers = {'Content-type': 'application/json'} response = requests.post(url_name, data=data_json, headers=headers) print(response)

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 rest_post_example.py Output: <Response [200]>

在前面的示例中,我们学习了关于POST请求。首先,我们导入了必要的模块 requests 和 JSON。接下来,我们提到了 URL。此外,我们以字典格式输入了要发布的数据。接下来,我们提到了标头。然后,我们使用POST请求发布。我们得到的输出是状态码200,这是一个成功的代码。

处理 JSON 数据

在本节中,我们将学习有关 JSON 数据。JSON代表JavaScript 对象表示。JSON 是一种数据交换格式。它将 Python 对象编码为 JSON 字符串,并将 JSON 字符串解码为 Python 对象。Python 有一个 JSON 模块,用于格式化 JSON 输出。它具有用于序列化和反序列化 JSON 的函数。

  • json.dump(obj, fileObj): 这个函数将一个对象序列化为一个 JSON 格式的流。

  • json.dumps(obj): 这个函数将一个对象序列化为一个 JSON 格式的字符串。

  • json.load(JSONfile): 这个函数将一个 JSON 文件反序列化为一个 Python 对象。

  • json.loads(JSONfile): 这个函数将一个字符串类型的 JSON 文件反序列化为一个 Python 对象。

它还列出了编码和解码的两个类:

  • JSONEncoder: 用于将 Python 对象转换为 JSON 格式。

  • JSONDecoder: 用于将 JSON 格式的文件转换为 Python 对象。

现在,我们将看到一些使用 JSON 模块的示例。首先,我们将看到从 JSON 到 Python 的转换。为此,创建一个名为json_to_python.py的脚本,并在其中写入以下代码:

import json j_obj =  '{ "Name":"Harry", "Age":26, "Department":"HR"}' p_obj = json.loads(j_obj) print(p_obj["Name"]) print(p_obj["Department"])

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 json_to_python.py Output: Harry HR

在前面的示例中,我们编写了一个代码,将 JSON 字符串转换为 Python 对象。json.loads()函数用于将 JSON 字符串转换为 Python 对象。

现在,我们将看到如何将 Python 转换为 JSON。为此,创建一个python_to_json.py脚本,并在其中写入以下代码:

import json emp_dict1 =  '{ "Name":"Harry", "Age":26, "Department":"HR"}' json_obj = json.dumps(emp_dict1) print(json_obj)

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 python_to_json.py Output: "{ \"Name\":\"Harry\", \"Age\":26, \"Department\":\"HR\"}"

在前面的示例中,我们将 Python 对象转换为 JSON 字符串。json.dumps()函数用于这种转换。

现在,我们将看到如何将各种类型的 Python 对象转换为 JSON 字符串。为此,创建一个python_object_to_json.py脚本,并在其中写入以下内容:

import json python_dict =  {"Name": "Harry", "Age": 26} python_list =  ["Mumbai", "Pune"] python_tuple =  ("Basketball", "Cricket") python_str =  ("hello_world") python_int =  (150) python_float =  (59.66) python_T =  (True) python_F =  (False) python_N =  (None) json_obj = json.dumps(python_dict) json_arr1 = json.dumps(python_list) json_arr2 = json.dumps(python_tuple) json_str = json.dumps(python_str) json_num1 = json.dumps(python_int) json_num2 = json.dumps(python_float) json_t = json.dumps(python_T) json_f = json.dumps(python_F) json_n = json.dumps(python_N) print("json object : ", json_obj) print("json array1 : ", json_arr1) print("json array2 : ", json_arr2) print("json string : ", json_str) print("json number1 : ", json_num1) print("json number2 : ", json_num2) print("json true", json_t) print("json false", json_f) print("json null", json_n)

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 python_object_to_json.py Output: json object :  {"Name": "Harry", "Age": 26} json array1 :  ["Mumbai", "Pune"] json array2 :  ["Basketball", "Cricket"] json string :  "hello_world" json number1 :  150 json number2 :  59.66 json true true json false false json null null

在前面的示例中,我们使用json.dumps()函数将各种类型的 Python 对象转换为 JSON 字符串。转换后,Python 列表和元组被转换为数组。整数和浮点数在 JSON 中被视为数字。以下是从 Python 到 JSON 的转换图表:

Python JSON
dict Object
list Array
tuple Array
str String
int Number
float Number
True true
False false
None null

总结

在这一章中,您学习了关于 SOAP API 和 RESTful API。您学习了关于zeep Python 库用于 SOAP API 和 requests 库用于 REST API。您还学会了如何处理 JSON 数据,例如将 JSON 转换为 Python,反之亦然。

在下一章中,您将学习有关网页抓取和用于执行此任务的 Python 库。

问题

  1. SOAP 和 REST API 之间有什么区别?

  2. json.loadsjson.load之间有什么区别?

  3. JSON 支持所有平台吗?

  4. 以下代码片段的输出是什么?

boolean_value = False
print(json.dumps(boolean_value))
  1. 以下代码片段的输出是什么?
>> weird_json = '{"x": 1, "x": 2, "x": 3}'
>>> json.loads(weird_json)

进一步阅读

第十六章:网络爬虫-从网站提取有用的数据

在本章中,您将学习有关网络爬虫的知识。您还将学习 Python 中的beautifulsoup库,该库用于从网站提取信息。

在本章中,我们将涵盖以下主题:

  • 什么是网络爬虫?

  • 数据提取

  • 从维基百科提取信息

什么是网络爬虫?

网络爬虫是从网站提取信息的技术。这种技术用于将非结构化数据转换为结构化数据。

网络爬虫的用途是从网站提取数据。提取的信息以本地文件的形式保存在您的系统上,您也可以以表格格式将其存储到数据库中。网络爬虫软件直接使用 HTTP 或 Web 浏览器访问万维网WWW)。这是使用网络爬虫或机器人实施的自动化过程。

爬取网页涉及获取页面,然后提取数据。网络爬虫获取网页。网络爬虫是网络爬取中的一个必不可少的组件。获取后,进行提取。您可以搜索、解析、将数据保存到表中,并重新格式化页面。

数据提取

在本节中,我们将看到实际的数据提取过程。Python 具有beautifulsoup库来执行数据提取任务。我们还将使用 Python 的 requests 库。

首先,我们必须安装这两个库。运行以下命令以安装requestsbeautifulsoup库:

$ pip3 install requests $ pip3 install beautifulsoup4

requests 库

使用requests库是在我们的 Python 脚本中以人类可读的格式使用 HTTP。我们可以使用 Python 中的requests库下载页面。requests库有不同类型的请求。在这里,我们将学习GET请求。GET请求用于从 Web 服务器检索信息。GET请求下载指定网页的 HTML 内容。每个请求都有一个状态代码。状态代码与我们向服务器发出的每个请求一起返回。这些状态代码为我们提供了关于请求发生了什么的信息。状态代码的类型在此列出:

  • 200:表示一切正常,并返回结果(如果有的话)

  • 301:表示服务器正在重定向到不同的端点,如果已经切换了域名或端点名称必须更改

  • 400:表示您发出了一个错误的请求

  • 401:表示我们未经授权

  • 403:表示您正在尝试访问被禁止的资源

  • 404:表示您正在尝试访问的资源在服务器上不可用

beautifulsoup 库

beautifulsoup是 Python 中用于网络爬虫的库。它具有用于搜索、导航和修改的简单方法。它只是一个工具包,用于从网页中提取所需的数据。

现在,要在脚本中使用requestsbeautifulsoup功能,您必须使用import语句导入这两个库。现在,我们将看一个解析网页的例子。在这里,我们将解析一个网页,这是来自 IMDb 网站的头条新闻页面。为此,请创建一个parse_web_page.py脚本,并在其中编写以下内容:

import requests from bs4 import BeautifulSoup page_result = requests.get('https://www.imdb.com/news/top?ref_=nv_nw_tp') parse_obj = BeautifulSoup(page_result.content, 'html.parser') print(parse_obj)

运行脚本,您将获得以下输出:

student@ubuntu:~/work$ python3 parse_web_page.py Output: <!DOCTYPE html> <html  > <head> <meta charset="utf-8"/> <meta content="IE=edge" http-equiv="X-UA-Compatible"/> <meta content="app-id=342792525, app-argument=imdb:///?src=mdot" name="apple-itunes-app"/> <script type="text/javascript">var IMDbTimer={starttime: new Date().getTime(),pt:'java'};</script> <script>
 if (typeof uet == 'function') { uet("bb", "LoadTitle", {wb: 1}); } </script> <script>(function(t){ (t.events = t.events || {})["csm_head_pre_title"] = new Date().getTime(); })(IMDbTimer);</script> <title>Top News - IMDb</title> <script>(function(t){ (t.events = t.events || {})["csm_head_post_title"] = new Date().getTime(); })(IMDbTimer);</script> <script>
 if (typeof uet == 'function') { uet("be", "LoadTitle", {wb: 1}); } </script> <script>
 if (typeof uex == 'function') { uex("ld", "LoadTitle", {wb: 1}); } </script> <link href="https://www.imdb.com/news/top" rel="canonical"/> <meta content="http://www.imdb.com/news/top" property="og:url"> <script>
 if (typeof uet == 'function') { uet("bb", "LoadIcons", {wb: 1}); }

在前面的示例中,我们收集了一个页面并使用beautifulsoup解析了它。首先,我们导入了requestsbeautifulsoup模块。然后,我们使用GET请求收集了 URL,并将该 URL 分配给page_result变量。接下来,我们创建了一个beautifulsoup对象parse_obj。这个对象将使用来自 requests 的page_result.content 作为参数,然后使用html.parser解析页面。

现在,我们将从一个类和一个标签中提取内容。要执行此操作,请转到您的网络浏览器,右键单击要提取的内容,然后向下滚动,直到您看到检查选项。单击它,您将获得类名。在程序中提到它并运行您的脚本。为此,请创建一个extract_from_class.py脚本,并在其中编写以下内容:

import requests from bs4 import BeautifulSoup page_result = requests.get('https://www.imdb.com/news/top?ref_=nv_nw_tp') parse_obj = BeautifulSoup(page_result.content, 'html.parser') top_news = parse_obj.find(class_='news-article__content') print(top_news)

运行脚本,您将获得以下输出:

student@ubuntu:~/work$ python3 extract_from_class.py Output : <div class="news-article__content"> <a href="/name/nm4793987/">Issa Rae</a> and <a href="/name/nm0000368/">Laura Dern</a> are teaming up to star in a limited series called “The Dolls” currently in development at <a href="/company/co0700043/">HBO</a>.<br/><br/>Inspired by true events, the series recounts the aftermath of Christmas Eve riots in two small Arkansas towns in 1983, riots which erupted over Cabbage Patch Dolls. The series explores class, race, privilege and what it takes to be a “good mother.”<br/><br/>Rae will serve as a writer and executive producer on the series in addition to starring, with Dern also executive producing. <a href="/name/nm3308450/">Laura Kittrell</a> and <a href="/name/nm4276354/">Amy Aniobi</a> will also serve as writers and co-executive producers. <a href="/name/nm0501536/">Jayme Lemons</a> of Dern’s <a href="/company/co0641481/">Jaywalker Pictures</a> and <a href="/name/nm3973260/">Deniese Davis</a> of <a href="/company/co0363033/">Issa Rae Productions</a> will also executive produce.<br/><br/>Both Rae and Dern currently star in HBO shows, with Dern appearing in the acclaimed drama “<a href="/title/tt3920596/">Big Little Lies</a>” and Rae starring in and having created the hit comedy “<a href="/title/tt5024912/">Insecure</a>.” Dern also recently starred in the film “<a href="/title/tt4015500/">The Tale</a>,
 </div>

在上面的例子中,我们首先导入了 requests 和beautifulsoup模块。然后,我们创建了一个请求对象并为其分配了一个 URL。接下来,我们创建了一个beautifulsoup对象parse_obj。这个对象以 requests 的page_result.content作为参数,然后使用html.parser解析页面。接下来,我们使用 beautifulsoup 的find()方法从'news-article__content'类中获取内容。

现在,我们将看到从特定标签中提取内容的示例。在这个例子中,我们将从<a>标签中提取内容。创建一个extract_from_tag.py脚本,并在其中编写以下内容:

import requests from bs4 import BeautifulSoup page_result = requests.get('https://www.imdb.com/news/top?ref_=nv_nw_tp') parse_obj = BeautifulSoup(page_result.content, 'html.parser') top_news = parse_obj.find(class_='news-article__content') top_news_a_content = top_news.find_all('a') print(top_news_a_content)

运行脚本,您将获得以下输出:

student@ubuntu:~/work$ python3 extract_from_tag.py Output: [<a href="/name/nm4793987/">Issa Rae</a>, <a href="/name/nm0000368/">Laura Dern</a>, <a href="/company/co0700043/">HBO</a>, <a href="/name/nm3308450/">Laura Kittrell</a>, <a href="/name/nm4276354/">Amy Aniobi</a>, <a href="/name/nm0501536/">Jayme Lemons</a>, <a href="/company/co0641481/">Jaywalker Pictures</a>, <a href="/name/nm3973260/">Deniese Davis</a>, <a href="/company/co0363033/">Issa Rae Productions</a>, <a href="/title/tt3920596/">Big Little Lies</a>, <a href="/title/tt5024912/">Insecure</a>, <a href="/title/tt4015500/">The Tale</a>]

在上面的例子中,我们正在从<a>标签中提取内容。我们使用find_all()方法从'news-article__content'类中提取所有<a>标签内容。

从维基百科中提取信息

在本节中,我们将看到维基百科上興舞形式列表的一个示例。我们将列出所有古典印度舞蹈。为此,请创建一个extract_from_wikipedia.py脚本,并在其中编写以下内容:

import requests from bs4 import BeautifulSoup page_result = requests.get('https://en.wikipedia.org/wiki/Portal:History') parse_obj = BeautifulSoup(page_result.content, 'html.parser') h_obj = parse_obj.find(class_='hlist noprint')
h_obj_a_content = h_obj.find_all('a') print(h_obj) print(h_obj_a_content)

运行脚本,您将获得以下输出:

student@ubuntu:~/work$ python3 extract_from_wikipedia.py
Output:
<div class="hlist noprint" id="portals-browsebar" style="text-align: center;">
<dl><dt><a href="/wiki/Portal:Contents/Portals" title="Portal:Contents/Portals">Portal topics</a></dt>
<dd><a href="/wiki/Portal:Contents/Portals#Human_activities" title="Portal:Contents/Portals">Activities</a></dd>
<dd><a href="/wiki/Portal:Contents/Portals#Culture_and_the_arts" title="Portal:Contents/Portals">Culture</a></dd>
<dd><a href="/wiki/Portal:Contents/Portals#Geography_and_places" title="Portal:Contents/Portals">Geography</a></dd>
<dd><a href="/wiki/Portal:Contents/Portals#Health_and_fitness" title="Portal:Contents/Portals">Health</a></dd>
<dd><a href="/wiki/Portal:Contents/Portals#History_and_events" title="Portal:Contents/Portals">History</a></dd>
<dd><a href="/wiki/Portal:Contents/Portals#Mathematics_and_logic" title="Portal:Contents/Portals">Mathematics</a></dd>
<dd><a href="/wiki/Portal:Contents/Portals#Natural_and_physical_sciences" title="Portal:Contents/Portals">Nature</a></dd>
<dd><a href="/wiki/Portal:Contents/Portals#People_and_self" title="Portal:Contents/Portals">People</a></dd>
In the preceding example, we extracted the content from Wikipedia. In this example also, we extracted the content from class as well as tag.
....

摘要

在本章中,您了解了网络爬取的内容。我们了解了用于从网页中提取数据的两个库。我们还从维基百科中提取了信息。

在下一章中,您将学习有关统计数据收集和报告的内容。您将学习有关 NumPy 模块、数据可视化以及使用图表、图形和图表显示数据的内容。

问题

  1. 什么是网络爬虫?

  2. 什么是网络爬虫?

  3. 您能够在登录页面后面抓取数据吗?

  4. 你能爬 Twitter 吗?

  5. 是否可能抓取 JavaScript 页面?如果是,如何?

进一步阅读

第十七章:统计数据收集和报告

在本章中,您将学习有关用于科学计算的统计学中使用的高级 Python 库。您将学习有关 Python 的 NumPY、Pandas、Matplotlib 和 Plotly 模块。您将学习有关数据可视化技术,以及如何绘制收集到的数据。

在本章中,我们将涵盖以下主题:

  • NumPY 模块

  • Pandas 模块

  • 数据可视化

NumPY 模块

NumPY 是一个提供数组高效操作的 Python 模块。NumPY 是 Python 科学计算的基本包。这个包通常用于 Python 数据分析。NumPY 数组是多个值的网格。

通过在终端中运行以下命令来安装 NumPY:

$ pip3 install numpy

我们将使用numpy库对numpy数组进行操作。现在我们将看看如何创建numpy数组。为此,请创建一个名为simple_array.py的脚本,并在其中编写以下代码:

import numpy as np my_list1 = [1,2,3,4] my_array1 = np.array(my_list1) print(my_list11, type(my_list1))
print(my_array1, type(my_array1))

运行脚本,您将获得以下输出:

student@ubuntu:~$ python3 simple_array.py

输出如下:

[1, 2, 3, 4] <class 'list'>
[1 2 3 4] <class 'numpy.ndarray'>

在前面的例子中,我们导入了numpy库作为np来使用numpy的功能。然后我们创建了一个简单的列表,将其转换为数组,我们使用了np.array()函数最后,我们打印了带有类型的numpy数组,以便更容易理解普通数组和numpy数组。

上一个例子是单维数组的例子。现在我们将看一个多维数组的例子。为此,我们必须创建另一个列表。让我们看另一个例子。创建一个名为mult_dim_array.py的脚本,并在其中编写以下内容:

import numpy as np my_list1 = [1,2,3,4] my_list2 = [11,22,33,44] my_lists = [my_list1, my_list2]
my_array = np.array(my_lists)
print(my_lists, type(my_lists)) print(my_array, type(my_array))

运行脚本,您将获得以下输出:

student@ubuntu:~$ python3 mult_dim_array.py

输出如下:

[[1, 2, 3, 4], [11, 22, 33, 44]] <class 'list'>
[[ 1 2 3 4]
 [11 22 33 44]] <class 'numpy.ndarray'>

在前面的例子中,我们导入了numpy模块。之后,我们创建了两个列表:my_list1my_list2。然后我们创建了另一个列表的列表(my_list1my_list2),并在列表(my_lists)上应用了np.array()函数,并将其存储在一个名为my_array的对象中。最后,我们打印了numpy数组。

现在,我们将看一下可以对数组进行的更多操作。我们将学习如何知道我们创建的数组my_array的大小和数据类型;也就是说,应用shape()函数我们将得到数组的size,应用dtype()函数我们将知道数组的数据类型。让我们看一个例子。创建一个名为size_and_dtype.py的脚本,并在其中编写以下内容:

import numpy as np my_list1 = [1,2,3,4] my_list2 = [11,22,33,44] my_lists = [my_list1,my_list2] my_array = np.array(my_lists) print(my_array) size = my_array.shape print(size) data_type = my_array.dtype print(data_type)

运行脚本,您将获得以下输出:

student@ubuntu:~$ python3 size_and_dtype.py

输出如下:

[[ 1  2  3  4]
 [11 22 33 44]] (2, 4) int64

在前面的例子中,我们应用了shape函数my_array.shape来获取数组的大小。输出是(2, 4)。然后我们在数组上应用了dtype函数my_array.dtype,输出是int64

现在,我们将看一些特殊情况数组的例子。

首先,我们将使用np.zeros()函数创建一个所有值为零的数组,如下所示:

student@ubuntu:~$ python3 Python 3.6.7 (default, Oct 22 2018, 11:32:17) [GCC 8.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import numpy as np >>> np.zeros(5) array([0., 0., 0., 0., 0.]) >>> 

在创建所有值为零的数组之后,我们将使用numpynp.ones()函数创建所有值为 1 的数组,如下所示:

>>> np.ones((5,5)) array([[1., 1., 1., 1., 1.],
 [1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.]]) >>> 

np.ones((5,5))创建一个所有值为15*5数组。

现在,我们将使用numpynp.empty()函数创建一个空数组,如下所示:

>>> np.empty([2,2]) array([[6.86506982e-317,  0.00000000e+000],
 [6.89930557e-310,  2.49398949e-306]]) >>> 

np.empty()不会像np.zeros()函数一样将数组值设置为零。因此,它可能更快。此外,它要求用户在数组中手动输入所有值,因此应谨慎使用。

现在,让我们看看如何使用np.eye()函数创建一个对角线值为1的单位矩阵,如下所示:

>>> np.eye(5) array([[1., 0., 0., 0., 0.],
 [0., 1., 0., 0., 0.], [0., 0., 1., 0., 0.], [0., 0., 0., 1., 0.], [0., 0., 0., 0., 1.]]) >>> 

现在,我们将看一下range函数,它用于使用numpynp.arange()函数创建数组,如下所示:

>>> np.arange(10) array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) >>> 

np.arange(10)函数创建了范围为0-9的数组。我们定义了范围值10,因此数组索引值从0开始。

使用数组和标量

在这一部分,我们将看一下使用numpy进行数组的各种算术运算。首先,我们将创建一个多维数组,如下所示:

student@ubuntu:~$ python3 Python 3.6.7 (default, Oct 22 2018, 11:32:17) [GCC 8.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import numpy as np >>> from __future__ import division >>> arr = np.array([[4,5,6],[7,8,9]]) >>> arr array([[4, 5, 6],
 [7, 8, 9]]) >>> 

在这里,我们导入了numpy模块来使用numpy的功能,然后我们导入了__future__模块,它将处理浮点数。之后,我们创建了一个二维数组arr,对其进行各种操作。

现在,让我们看一下对数组的一些算术运算。首先,我们将学习数组的乘法,如下所示:

>>> arr*arr array([[16, 25, 36],
 [49, 64, 81]]) >>> 

在上面的乘法操作中,我们将arr数组乘以两次以得到一个乘法数组。您也可以将两个不同的数组相乘。

现在,我们将看一下对数组进行减法操作,如下所示:

>>> arr-arr array([[0, 0, 0],
 [0, 0, 0]]) >>> 

如前面的例子所示,我们只需使用**-**运算符来对两个数组进行减法。在减法操作之后,我们得到了结果数组,如前面的代码所示。

现在我们将看一下对标量进行数组的算术运算。让我们看一些操作:

>>> 1 / arr array([[0.25             ,  0.2        ,   0.16666667],
 [0.14285714 ,   0.125     ,  0.11111111]]) >>> 

在上面的例子中,我们将1除以我们的数组并得到了输出。请记住,我们导入了__future__模块,它实际上对这样的操作非常有用,可以处理数组中的浮点值。

现在我们将看一下numpy数组的指数运算,如下所示:

>>> arr ** 3 array([[ 64, 125, 216],
 [343, 512, 729]]) >>> 

在上面的例子中,我们对数组取了立方,并得到了每个值的立方作为输出。

数组索引

使用数组作为索引来对数组进行索引。使用索引数组,将返回原始数组的副本。numpy数组可以使用任何其他序列或使用任何其他数组进行索引,但不包括元组。数组中的最后一个元素可以通过-1进行索引,倒数第二个元素可以通过-2进行索引,依此类推。

因此,要对数组进行索引操作,首先我们创建一个新的numpy数组,为此我们将使用range()函数来创建数组,如下所示:

student@ubuntu:~$ python3 Python 3.6.7 (default, Oct 22 2018, 11:32:17) [GCC 8.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import numpy as np >>> arr = np.arange(0,16) >>> arr array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15]) >>> 

在上面的例子中,我们创建了范围为16(即0-15)的数组arr

现在,我们将对数组arr执行不同的索引操作。首先,让我们获取数组中特定索引处的值:

>>> arr[7] 7 >>> 

在上面的例子中,我们通过其索引值访问了数组,并在将索引号传递给数组arr后,数组返回了值7,这是我们传递的特定索引号。

在获取特定索引处的值之后,我们将获取一定范围内的值。让我们看下面的例子:

>>> arr[2:10] array([2, 3, 4, 5, 6, 7, 8, 9]) >>> arr[2:10:2] array([2, 4, 6, 8])>>>

在上面的例子中,首先我们访问了数组并得到了范围为(2-10)的值。结果显示为array([2, 3, 4, 5, 6, 7, 8, 9])。在第二个术语中,arr[2:10:2],实际上是指定在范围2-10内以两步的间隔访问数组。这种索引的语法是arr[_start_value_:_stop_value_:_steps_]。因此,第二个术语的输出是array([2, 4, 6, 8])

我们还可以从索引值开始获取数组中的值直到末尾,如下例所示:

>>> arr[5:] array([ 5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15]) >>> 

正如我们在上面的例子中看到的,我们从第 5 个索引值开始访问数组中的值直到末尾。结果,我们得到的输出是array([ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])

现在我们将看一下numpy数组的切片。在切片中,我们实际上是取原始数组的一部分并将其存储在指定的数组名称中。让我们看一个例子:

>>> arr_slice = arr[0:8] >>> arr_slice array([0, 1, 2, 3, 4, 5, 6, 7]) >>> 

在上面的例子中,我们对原始数组进行了切片。结果,我们得到了一个包含值0,1,2,…..,7的数组切片。我们还可以给数组切片赋予更新后的值。让我们看一个例子:

>>> arr_slice[:] = 29 >>> arr_slice array([29, 29, 29, 29, 29, 29, 29, 29]) >>> 

在前面的例子中,我们将数组切片中的所有值设置为29。但在为数组切片分配值时,重要的是分配给切片的值也将分配给数组的原始集合。

让我们看看给数组的切片赋值后的结果,以及对我们原始数组的影响:

>>> arr array([29, 29, 29, 29, 29, 29, 29, 29,  8,  9, 10, 11, 12, 13, 14, 15]) >>>

现在,我们将看另一个操作;即,复制数组。对数组进行切片和复制的区别在于,当我们对数组进行切片时,所做的更改将应用于原始数组。当我们获得数组的副本时,它会给出原始数组的显式副本。因此,对数组的副本应用的更改不会影响原始数组。所以让我们看一个复制数组的例子:

>>> cpying_arr = arr.copy() >>> cpying_arr array([29, 29, 29, 29, 29, 29, 29, 29,  8,  9, 10, 11, 12, 13, 14, 15]) >>> 

在前面的例子中,我们只是复制了原始数组。为此,我们使用了array_name.copy()函数,输出是原始数组的副本。

对二维数组进行索引

二维数组是一个数组的数组。在这种情况下,数据元素的位置通常是指两个索引而不是一个,并且它表示具有行和列数据的表。现在我们将对这种类型的数组进行索引。

所以,让我们来看一个二维数组的例子:

>>> td_array = np.array(([5,6,7],[8,9,10],[11,12,13])) >>> td_array array([[  5,   6,    7],
 [  8,   9,  10], [11, 12,  13]]) >>> 

在前面的例子中,我们创建了一个名为td_array的二维数组。创建数组后,我们打印了td_array。现在我们还将通过索引获取td_array中的值。让我们看一个通过索引访问值的例子:

>>> td_array[1] array([ 8,  9, 10]) >>>

在前面的例子中,我们访问了数组的第一个索引值,并得到了输出。在这种类型的索引中,当我们访问值时,我们得到整个数组。除了获取整个数组,我们还可以访问特定的值。让我们来看一个例子:

>>> td_array[1,0] 8 >>> 

在前面的例子中,我们通过传递两个值来访问td_array的行和列。如输出所示,我们得到了值8

我们也可以以不同的方式设置二维数组。首先,将我们的二维数组长度增加。让我们将长度设置为10。因此,为此,我们创建一个所有元素都是零的示例数组,然后我们将在其中放入值。让我们看一个例子:

>>> td_array = np.zeros((10,10)) >>> td_array array([[0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
 [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]]) >>> for i in range(10):
 ...     td_array[i] = i ... >>> td_array array([[0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
 [1., 1., 1., 1., 1., 1., 1., 1., 1., 1.], [2., 2., 2., 2., 2., 2., 2., 2., 2., 2.], [3., 3., 3., 3., 3., 3., 3., 3., 3., 3.], [4., 4., 4., 4., 4., 4., 4., 4., 4., 4.], [5., 5., 5., 5., 5., 5., 5., 5., 5., 5.], [6., 6., 6., 6., 6., 6., 6., 6., 6., 6.], [7., 7., 7., 7., 7., 7., 7., 7., 7., 7.], [8., 8., 8., 8., 8., 8., 8., 8., 8., 8.], [9., 9., 9., 9., 9., 9., 9., 9., 9., 9.]]) >>>

在前面的例子中,我们创建了一个长度为10乘以10的二维数组。

现在让我们在其中进行一些花式索引,如下例所示:

>>> td_array[[1,3,5,7]] array([[1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
 [3., 3., 3., 3., 3., 3., 3., 3., 3., 3.], [5., 5., 5., 5., 5., 5., 5., 5., 5., 5.], [7., 7., 7., 7., 7., 7., 7., 7., 7., 7.]]) >>> 

在前面的例子中,我们获取了特定的索引值。因此,在结果中,我们得到了输出。

通用数组函数

通用函数对numpy数组中的所有元素执行操作。现在,我们将看一个例子,对数组执行多个通用函数。首先,我们将对数组进行平方根处理。创建一个名为sqrt_array.py的脚本,并在其中写入以下内容:

import numpy as np array = np.arange(16) print("The Array is : ",array) Square_root = np.sqrt(array) print("Square root of given array is : ", Square_root)

运行脚本,你会得到以下输出:

student@ubuntu:~/work$ python3 sqrt_array.py

输出如下:

The Array is : [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15] Square root of given array is : [0\. 1\. 1.41421356 1.73205081 2\. 2.23606798
 2.44948974 2.64575131 2.82842712 3\. 3.16227766 3.31662479 3.46410162 3.60555128 3.74165739 3.87298335]

在前面的例子中,我们使用numpyrange函数创建了一个简单的数组。然后我们对生成的数组应用了sqrt()函数,以获得数组的平方根。在获取数组的平方根后,我们将对数组应用另一个通用函数,即指数exp()函数。让我们看一个例子。创建一个名为expo_array.py的脚本,并在其中写入以下内容:

import numpy as np array = np.arange(16) print("The Array is : ",array) exp = np.exp(array) print("exponential of given array is : ", exp)

运行脚本,你会得到以下输出:

student@ubuntu:~/work$ python3 expo_array.py

输出如下:

The Array is :  [ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15] exponential of given array is :  [1.00000000e+00 2.71828183e+00 7.38905610e+00 2.00855369e+01
 5.45981500e+01 1.48413159e+02 4.03428793e+02 1.09663316e+03 2.98095799e+03 8.10308393e+03 2.20264658e+04 5.98741417e+04 1.62754791e+05 4.42413392e+05 1.20260428e+06 3.26901737e+06]

在前面的例子中,我们使用numpyrange函数创建了一个简单的数组。然后我们对生成的数组应用了exp()函数,以获得数组的指数。

Pandas 模块

在本节中,我们将学习有关 pandas 模块的知识。pandas 模块提供了快速灵活的数据结构,专为处理结构化和时间序列数据而设计。pandas 模块用于数据分析。pandas 模块是建立在 NumPY 和 Matplotlib 等包之上的,并为我们提供了大部分分析和可视化工作的场所。要使用此模块的功能,您必须首先导入它。

首先,通过运行以下命令安装我们示例中需要的以下软件包:

$ pip3 install pandas $ pip3 install matplotlib

在这里,我们将看一些使用 pandas 模块的例子。我们将学习两种数据结构:系列和数据框。我们还将看到如何使用 pandas 从csv文件中读取数据。

系列

pandas 系列是一维数组。它可以容纳任何数据类型。标签被称为索引。现在,我们将看一个不声明索引的系列和声明索引的系列的例子。首先,我们将看一个不声明索引的系列的例子。为此,请创建一个名为series_without_index.py的脚本,并在其中写入以下内容:

import pandas as pd import numpy as np s_data = pd.Series([10, 20, 30, 40], name = 'numbers') print(s_data)

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 series_without_index.py

输出如下:

0 10 1 20 2 30 3 40 Name: numbers, dtype: int64

在上面的例子中,我们学习了不声明索引的系列。首先,我们导入了两个模块:pandas 和numpy。接下来,我们创建了将存储系列数据的s_data对象。在该系列中,我们创建了一个列表,而不是声明索引,我们提供了 name 属性,该属性将为列表提供一个名称,然后我们打印了数据。在输出中,左列是数据的索引。即使我们从未提供索引,pandas 也会隐式地给出。索引将始终从0开始。在列的下方是我们系列的名称和值的数据类型。

现在,我们将看一个声明索引的系列的例子。在这里,我们还将执行索引和切片操作。为此,请创建一个名为series_with_index.py的脚本,并在其中写入以下内容:

import pandas as pd import numpy as np s_data = pd.Series([10, 20, 30, 40], index = ['a', 'b', 'c', 'd'], name = 'numbers') print(s_data) print() print("The data at index 2 is: ", s_data[2]) print("The data from range 1 to 3 are:\n", s_data[1:3])

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 series_with_index.py a    10 b    20 c    30 d    40 Name: numbers, dtype: int64 

The data at index 2 is:  30 The data from range 1 to 3 are:
 b    20 c    30 Name: numbers, dtype: int64

在上面的例子中,我们为数据在index属性中提供了索引值。在输出中,左列是我们提供的索引值。

数据框

在本节中,我们将学习有关 pandas 数据框的知识。数据框是具有列并且可能是不同数据类型的二维标记数据结构。数据框类似于 SQL 表或电子表格。在使用 pandas 时,它们是最常见的对象。

现在,我们将看一个例子,从csv文件中读取数据到 DataFrame 中。为此,您必须在系统中有一个csv文件。如果您的系统中没有csv文件,请按以下方式创建一个名为employee.csv的文件:

Id, Name, Department, Country 101, John, Finance, US 102, Mary, HR, Australia 103, Geeta, IT, India 104, Rahul, Marketing, India 105, Tom, Sales, Russia

现在,我们将把这个csv文件读入 DataFrame 中。为此,请创建一个名为read_csv_dataframe.py的脚本,并在其中写入以下内容:

import pandas as pd file_name = 'employee.csv' df = pd.read_csv(file_name) print(df) print() print(df.head(3)) print() print(df.tail(1))

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 read_csv_dataframe.py Output:
 Id    Name  Department     Country 0  101    John     Finance          US 1  102    Mary          HR   Australia 2  103   Geeta          IT       India 3  104   Rahul   Marketing       India 4  105     Tom       Sales      Russia 

 Id    Name  Department     Country 0  101    John     Finance          US 1  102    Mary          HR   Australia 2  103   Geeta          IT       India
Id  Name  Department  Country 4  105   Tom       Sales   Russia

在上面的例子中,我们首先创建了一个名为employee.csvcsv文件。我们使用 pandas 模块创建数据框。目标是将csv文件读入 DataFrame 中。接下来,我们创建了一个df对象,并将csv文件的内容读入其中。接下来我们打印一个 DataFrame。在这里,我们使用head()tail()方法来获取特定数量的数据行。我们指定了head(3),这意味着我们打印了前三行数据。我们还指定了tail(1),这意味着我们打印了最后一行数据。

数据可视化

数据可视化是描述理解数据重要性并以可视化方式放置数据的努力的术语。在本节中,我们将看一下以下数据可视化技术:

  • Matplotlib

  • Plotly

Matplotlib

Matplotlib 是 Python 中的数据可视化库,它允许我们使用几行代码生成图表、直方图、功率谱、条形图、误差图、散点图等。Matplotlib 通常使事情变得更容易,最困难的事情也变得可能。

要在您的 Python 程序中使用matplotlib,首先我们必须安装matplotlib。在您的终端中运行以下命令来安装matplotlib

$ pip3 install matplotlib

现在,您还必须安装另一个包tkinter,用于图形表示。使用以下命令安装它:

$ sudo apt install python3-tk

在上面的例子中,我们使用plt.figure()函数在不同的画布上绘制东西。之后,我们使用plt.plot()函数。这个函数有不同的参数,对于绘制图表很有用。在上面的例子中,我们使用了一些参数;即x1x2y1y2。这些是用于绘制的相应轴点。

现在,我们将看一些matplotlib的例子。让我们从一个简单的例子开始。创建一个名为simple_plot.py的脚本,并在其中写入以下内容:

import matplotlib.pyplot as plt import numpy as np x = np.linspace(0, 5, 10) y = x**2 plt.plot(x,y) plt.title("sample plot") plt.xlabel("x axis") plt.ylabel("y axis") plt.show()

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 simple_plot.py

输出如下:

在上面的例子中,我们导入了两个模块,matplotlibnumpy,来可视化数据以及分别创建数组xy。之后,我们将两个数组绘制为plt.plot(x,y)。然后我们使用xlabel()ylabel()title()函数向图表添加标题和标签,并使用plt.show()函数显示这个绘图。因为我们在 Python 脚本中使用 Matplotlib,不要忘记在最后一行添加plt.show()来显示您的绘图。

现在我们将创建两个数组来显示绘图中的两行曲线,并且我们将对这两条曲线应用样式。在下面的例子中,我们将使用ggplot样式来绘制图表。ggplot是一个用于声明性创建图形的系统,基于图形语法。要绘制ghraph,我们只需提供数据,然后告诉ggplot如何映射变量以及使用什么图形原语,它会处理细节。在大多数情况下,我们从ggplot()样式开始。

现在,创建一个名为simple_plot2.py的脚本,并在其中写入以下内容:

import matplotlib.pyplot as plt from matplotlib import style style.use('ggplot') x1 = [0,5,10]
y1 = [12,16,6] x2 = [6,9,11] y2 = [6,16,8] plt.subplot(2,1,1) plt.plot(x1, y1, linewidth=3) plt.title("sample plot") plt.xlabel("x axis") plt.ylabel("y axis") plt.subplot(2,1,2) plt.plot(x2, y2, color = 'r', linewidth=3) plt.xlabel("x2 axis") plt.ylabel("y2 axis") plt.show()

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 simple_plot2.py

输出如下:

现在matplotlib已经安装在您的系统中,我们将看一些例子。在绘图时,有两个重要的组件:图和轴。图是充当绘制所有内容的窗口的容器。它可以有各种类型的独立图。轴是您可以绘制数据和与之相关的任何标签的区域。轴由一个x轴和一个y轴组成。

在上面的例子中,首先我们导入了所需的模块,然后我们使用ggplot样式来绘制图表。我们创建了两组数组;即x1y1x2y2。然后我们使用 subplot 函数plt.subplot(),因为它允许我们在同一画布中绘制不同的东西。如果您想要在不同的画布上显示这两个图,您也可以使用plt.figure()函数而不是plt.subplot()

输出如下:

import matplotlib.pyplot as plt from matplotlib import style style.use('ggplot') x1 = [0,5,10] y1 = [12,16,6] x2 = [6,9,11] y2 = [6,16,8] plt.figure(1) plt.plot(x1, y1, color = 'g', linewidth=3) plt.title("sample plot") plt.xlabel("x axis") plt.ylabel("y axis") plt.savefig('my_sample_plot1.jpg') plt.figure(2) plt.plot(x2, y2, color = 'r', linewidth=3) plt.xlabel("x2 axis") plt.ylabel("y2 axis") plt.savefig('my_sample_plot2.jpg') plt.show()

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 simple_plot3.py

输出如下:

现在,我们将看一下如何使用plt.figure()函数绘制数组并使用 Matplotlib 保存生成的图。您可以使用savefig()方法将它们保存为不同的格式,如pngjpgpdf等。我们将把前面的图保存在一个名为my_sample_plot.jpg的文件中。现在,我们将看一个例子。为此,创建一个名为simple_plot3.py的脚本,并在其中写入以下内容:

然后,我们使用color参数为图形线条提供特定的颜色,并且在第三个参数中,我们使用linewidth,它决定了图形线条的宽度。之后,我们还使用了savefig()方法来以特定的图像格式保存我们的图。您可以在运行 Python 脚本的当前目录中检查它们(如果您没有指定路径)。

您可以通过直接访问该目录来打开这些图像,或者您也可以使用以下方法使用matplotlib来打开这些生成的图像。现在,我们将看一个打开保存的图的示例。为此,请创建一个名为open_image.py的脚本,并在其中写入以下内容:

import matplotlib.pyplot as plt import matplotlib.image as mpimg plt.imshow(mpimg.imread('my_sample_plot1.jpg')) plt.show()

运行脚本,您将获得以下输出:

student@ubuntu:~/work$ python3 open_image.py

输出如下:

在前面的例子中,我们使用了 Matplotlib 的imshow()函数来打开图的保存图像。

现在,我们将看一些不同类型的图。Matplotlib 允许我们创建不同类型的图来处理数组中的数据,如直方图、散点图、条形图等。使用不同类型的图取决于数据可视化的目的。让我们看一些这些图。

直方图

这种类型的图表帮助我们以一种无法仅仅使用均值或中位数来应付的方式来检查数值数据的分布。我们将使用hist()方法来创建一个简单的直方图。让我们看一个创建简单直方图的例子。为此,请创建一个名为histogram_example.py的脚本,并在其中写入以下内容:

import matplotlib.pyplot as plt import numpy as np x = np.random.randn(500) plt.hist(x) plt.show()

运行脚本,您将获得以下输出:

student@ubuntu:~/work$ python3 histogram_example.py

输出如下:

在前面的例子中,我们使用numpy创建了一组随机数。然后,我们使用plt.hist()方法绘制了这些数值数据。

散点图

这种类型的图表将数据显示为一组点。它提供了一种方便的方式来可视化数值值的关系。它还帮助我们理解多个变量之间的关系。我们将使用scatter()方法来绘制散点图中的数据。在散点图中,点的位置取决于其xy轴的值;也就是说,数据集中的每个值都是水平或垂直维度中的一个位置。让我们看一个散点图的例子。创建一个名为scatterplot_example.py的脚本,并在其中写入以下内容:

import matplotlib.pyplot as plt import numpy as np x = np.linspace(-2,2,100) y = np.random.randn(100) colors = np.random.rand(100) plt.scatter(x,y,c=colors) plt.show()

运行脚本,您将获得以下输出:

student@ubuntu:~/work$ python3 scatterplot_example.py

输出如下:

在前面的例子中,我们得到了xy的值。然后,我们使用plt.scatter()方法来绘制这些值,以获得xy值的散点图。

条形图

条形图是用矩形条表示数据的图表。您可以将它们垂直或水平绘制。创建一个名为bar_chart.py的脚本,并在其中写入以下内容:

import matplotlib.pyplot as plt from matplotlib import style style.use('ggplot') x1 = [4,8,12] y1 = [12,16,6] x2 = [5,9,11] y2 = [6,16,8] plt.bar(x1,y1,color = 'g',linewidth=3) plt.bar(x2,y2,color = 'r',linewidth=3) plt.title("Bar plot") plt.xlabel("x axis") plt.ylabel("y axis") plt.show()

运行脚本,您将获得以下输出:

student@ubuntu:~/work$ python3 bar_chart.py

输出如下:

在前面的例子中,我们有两组值:x1y1x2y2。在获得数值数据后,我们使用plt.bar()方法来绘制当前数据的条形图。

有多种技术可用于绘制数据。其中,有几种使用matplotlib进行数据可视化的技术或方法,我们已经看到了。我们还可以使用另一种数据可视化工具plotly来执行这些操作。

Plotly

Plotly 是 Python 中的一个交互式、开源的绘图库。它是一个图表库,提供了 30 多种图表类型,如科学图表、3D 图形、统计图表、金融图表等。

要在 Python 中使用plotly,首先我们必须在系统中安装它。要安装plotly,请在您的终端中运行以下命令:

$ pip3 install plotly

我们可以在线和离线使用plotly。对于在线使用,你需要有一个plotly账户,之后你需要在 Python 中设置你的凭据:

 plotly.tools.set_credentials_file(username='Username', api_key='APIkey')

要离线使用plotly,我们需要使用plotly函数:plotly.offline.plot()

在这一部分,我们将使用 plotly 离线。现在,我们将看一个简单的例子。为此,创建一个名为sample_plotly.py的脚本,并在其中写入以下内容:

import plotly from plotly.graph_objs import Scatter, Layout plotly.offline.plot({
 "data": [Scatter(x=[1, 4, 3, 4], y=[4, 3, 2, 1])], "layout": Layout(title="plotly_sample_plot") })

将前面的脚本命名为sample_plotly.py运行。你将得到以下输出:

student@ubuntu:~/work$ python3 sample_plotly.py

输出如下:

在前面的例子中,我们导入了plotly模块,然后将plotly设置为离线使用。我们在其中放入了一些有用于绘制图表的参数。在例子中,我们使用了一些参数:datalayout。在data参数中,我们使用散点函数定义了xy数组,这些数组具有要在xy轴上绘制的值。然后我们使用layout参数,在其中我们定义了布局函数以为图表提供标题。前面程序的输出保存为 HTML 文件,并在默认浏览器中打开。这个 HTML 文件与你的脚本在同一个目录中。

现在让我们看一些不同类型的图表来可视化数据。所以,首先,我们将从散点图开始。

散点图

创建一个名为scatter_plot_plotly.py的脚本,并在其中写入以下内容:

import plotly import plotly.graph_objs as go import numpy as np  x_axis = np.random.randn(100) y_axis = np.random.randn(100)  trace = go.Scatter(x=x_axis, y=y_axis, mode = 'markers') data_set = [trace] plotly.offline.plot(data_set, filename='scatter_plot.html')

运行脚本,你将得到以下输出:

student@ubuntu:~/work$ python3 scatter_plot_plotly.py

输出如下:

在前面的例子中,我们导入了plotly,然后通过使用numpy创建了随机数据,并在脚本中导入了numpy模块。生成数据集后,我们创建了一个名为trace的对象,并将我们的数值数据插入其中以进行散点。最后,我们将trace对象中的数据放入plotly.offline.plot()函数中,以获得数据的散点图。与我们的第一个示例图一样,这个例子的输出也以 HTML 格式保存,并显示在默认的网络浏览器中。

线散点图

我们还可以创建一些更有信息量的图表,比如线散点图。让我们看一个例子。创建一个名为line_scatter_plot.py的脚本,并在其中写入以下内容:

import plotly import plotly.graph_objs as go import numpy as np x_axis = np.linspace(0, 1, 50) y0_axis = np.random.randn(50)+5 y1_axis = np.random.randn(50) y2_axis = np.random.randn(50)-5 trace0 = go.Scatter(x = x_axis,y = y0_axis,mode = 'markers',name = 'markers') trace1 = go.Scatter(x = x_axis,y = y1_axis,mode = 'lines+markers',name = 'lines+markers') trace2 = go.Scatter(x = x_axis,y = y2_axis,mode = 'lines',name = 'lines') data_sets = [trace0, trace1, trace2] plotly.offline.plot(data_sets, filename='line_scatter_plot.html')

运行脚本,你将得到以下输出:

student@ubuntu:~/work$ python3 line_scatter_plot.py

输出如下:

在前面的例子中,我们导入了plotly,以及numpy模块。然后我们为 x 轴生成了一些随机值,也为三个不同的 y 轴生成了随机值。之后,我们将这些数据放入创建的trace对象中,最后将该数据集放入 plotly 的离线函数中。然后我们得到了散点和线的格式的输出。这个例子的输出文件以line_scatter_plot.html的名称保存在你当前的目录中。

箱线图

箱线图通常是有信息量的,也很有帮助,特别是当你有太多要展示但数据很少的时候。让我们看一个例子。创建一个名为plotly_box_plot.py的脚本,并在其中写入以下内容:

import random import plotly from numpy import * N = 50. c = ['hsl('+str(h)+',50%'+',50%)' for h in linspace(0, 360, N)] data_set = [{
 'y': 3.5*sin(pi * i/N) + i/N+(1.5+0.5*cos(pi*i/N))*random.rand(20), 'type':'box', 'marker':{'color': c[i]} } for i in range(int(N))] layout = {'xaxis': {'showgrid':False,'zeroline':False, 'tickangle':45,'showticklabels':False},
 'yaxis': {'zeroline':False,'gridcolor':'white'}, 'paper_bgcolor': 'rgb(233,233,233)', 'plot_bgcolor': 'rgb(233,233,233)', } plotly.offline.plot(data_set)

运行脚本,你将得到以下输出:

student@ubuntu:~/work$ python3 plotly_box_plot.py

输出如下:

在前面的例子中,我们导入了plotly,以及numpy模块。然后我们声明 N 为箱线图中的总箱数,并通过固定颜色的饱和度和亮度以及围绕色调进行变化,生成了一个彩虹颜色的数组。每个箱子由一个包含数据、类型和颜色的字典表示。我们使用列表推导来描述 N 个不同颜色的箱子,每个箱子都有不同的随机生成的数据。之后,我们格式化输出的布局并通过离线的plotly函数绘制数据。

等高线图

轮廓图通常用作科学图,并在显示热图数据时经常使用。让我们看一个轮廓图的例子。创建一个名为contour_plotly.py的脚本,并在其中写入以下内容:

from plotly import tools import plotly import plotly.graph_objs as go trace0 = go.Contour(
 z=[[1, 2, 3, 4, 5, 6, 7, 8], [2, 4, 7, 12, 13, 14, 15, 16], [3, 1, 6, 11, 12, 13, 16, 17], [4, 2, 7, 7, 11, 14, 17, 18], [5, 3, 8, 8, 13, 15, 18, 19], [7, 4, 10, 9, 16, 18, 20, 19], [9, 10, 5, 27, 23, 21, 21, 21]], line=dict(smoothing=0), ) trace1 = go.Contour(
 z=[[1, 2, 3, 4, 5, 6, 7, 8], [2, 4, 7, 12, 13, 14, 15, 16], [3, 1, 6, 11, 12, 13, 16, 17], [4, 2, 7, 7, 11, 14, 17, 18], [5, 3, 8, 8, 13, 15, 18, 19], [7, 4, 10, 9, 16, 18, 20, 19], [9, 10, 5, 27, 23, 21, 21, 21]], line=dict(smoothing=0.95), ) data = tools.make_subplots(rows=1, cols=2,
 subplot_titles=('Smoothing_not_applied', 'smoothing_applied')) data.append_trace(trace0, 1, 1) data.append_trace(trace1, 1, 2) plotly.offline.plot(data)

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 contour_plotly.py This is the format of your plot grid: [ (1,1) x1,y1 ]  [ (1,2) x2,y2 ]

输出如下:

在前面的例子中,我们取了一个数据集,并对其应用了contour()函数。然后我们将轮廓数据附加到data_set中,并最终对数据应用了plotly函数以获得输出。这些是 plotly 中用于以可视方式绘制数据的一些技术。

总结

在本章中,我们学习了 NumPY 和 Pandas 模块,以及数据可视化技术。在 NumPY 模块部分,我们学习了数组的索引和切片以及通用数组函数。在 pandas 模块部分,我们学习了 Series 和 DataFrames。我们还学习了如何将csv文件读入 DataFrame。在数据可视化中,我们学习了 Python 中用于数据可视化的库:matplotlibplotly

在下一章中,您将学习有关 MySQL 和 SQLite 数据库管理的知识。

问题

  1. 什么是 NumPy 数组?

  2. 以下代码片段的输出是什么?

import numpy as np
# input array
in_arr1 = np.array([[ 1, 2, 3], [ -1, -2, -3]] )
print ("1st Input array : \n", in_arr1) 
in_arr2 = np.array([[ 4, 5, 6], [ -4, -5, -6]] )
print ("2nd Input array : \n", in_arr2) 
# Stacking the two arrays horizontally
out_arr = np.hstack((in_arr1, in_arr2))
print ("Output stacked array :\n ", out_arr)
  1. 如何比np.sum更快地对小数组求和?

  2. 如何从 Pandas DataFrame 中删除索引、行或列?

  3. 如何将 Pandas DataFrame 写入文件?

  4. pandas 中的 NaN 是什么?

  5. 如何从 pandas DataFrame 中删除重复项?

  6. 如何更改使用 Matplotlib 绘制的图形的大小?

  7. Python 中绘制图形的可用替代方法是什么?

进一步阅读

第十八章:MySQL 和 SQLite 数据库管理

在本章中,您将学习有关 MySQL 和 SQLite 数据库管理的知识。您将学习如何安装 MySQL 和 SQLite。您还将学习如何创建用户,授予权限,创建数据库,创建表,将数据插入表中,并查看表中的所有记录,特定记录,并更新和删除数据。

在本章中,您将学习以下内容:

  • MySQL 数据库管理

  • SQLite 数据库管理

MySQL 数据库管理

本节将介绍使用 Python 进行 MySQL 数据库管理。您已经知道 Python 有各种模块用于mysql数据库管理。因此,我们将在这里学习有关 MySQLdb 模块的知识。mysqldb模块是 MySQL 数据库服务器的接口,用于提供 Python 数据库 API。

让我们学习如何安装 MySQL 和 Python 的mysqldb包。为此,请在终端中运行以下命令:

$ sudo apt install mysql-server

此命令安装 MySQL 服务器和各种其他软件包。在安装软件包时,我们被提示为 MySQL root 帐户输入密码:

  • 以下代码用于检查是否安装了mysqldb包:
$ apt-cache search MySQLdb
  • 以下是用于安装 MySQL 的 Python 接口:
$ sudo apt-get install python3-mysqldb
  • 现在,我们将检查mysql是否安装正确。为此,在终端中运行以下命令:
student@ubuntu:~$ sudo mysql -u root -p 

一旦命令运行,您将获得以下输出:

Enter password: Welcome to the MySQL monitor.  Commands end with ; or \g. Your MySQL connection id is 10 Server version: 5.7.24-0ubuntu0.18.04.1 (Ubuntu)
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>

通过运行sudo mysql -u root -p,您将获得mysql控制台。有一些命令用于列出数据库和表,并使用数据库来存储我们的工作。我们将逐一看到它们:

  • 这是用于列出所有数据库的:
show databases;
  • 这是用于使用数据库的:
use database_name;

每当我们退出 MySQL 控制台并在一段时间后再次登录时,我们必须使用use database_name;语句。使用此命令的目的是我们的工作将保存在我们的数据库中。我们可以通过以下示例详细了解这一点:

  • 以下代码用于列出所有表:
show tables;

这些是我们用于列出数据库,使用数据库和列出表的命令。

现在,我们将使用mysql控制台中的 create database 语句创建数据库。现在,使用mysql -u root -p打开mysql控制台,然后输入您在安装时输入的密码,然后按Enter。接下来,创建您的数据库。在本节中,我们将创建一个名为test的数据库,并在本节中将使用该数据库:

student@ubuntu:~/work/mysql_testing$ sudo mysql -u root -p  Output: Enter password: Welcome to the MySQL monitor.  Commands end with ; or \g. Your MySQL connection id is 16 Server version: 5.7.24-0ubuntu0.18.04.1 (Ubuntu)
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> mysql> show databases; +--------------------+ | Database           | +--------------------+ | information_schema | | mysql              | | performance_schema | | sys                | +--------------------+ 4 rows in set (0.10 sec)
mysql> create database test; Query OK, 1 row affected (0.00 sec)
mysql> show databases; +--------------------+ | Database           | +--------------------+ | information_schema | | mysql              | | performance_schema | | sys                | | test               | +--------------------+ 5 rows in set (0.00 sec)
mysql> use test; Database changed mysql>

首先,我们使用 show databases 列出了所有数据库。接下来,我们使用 create database语句创建了我们的数据库 test。然后,我们再次执行 show databases 以查找我们的数据库是否已创建。我们的数据库现在已创建。接下来,我们使用该数据库来存储我们正在进行的工作。

现在,我们将创建一个用户并授予该用户权限。运行以下命令:

mysql> create user 'test_user'@'localhost' identified by 'test123'; Query OK, 0 rows affected (0.06 sec) mysql> grant all on test.* to 'test_user'@'localhost'; Query OK, 0 rows affected (0.02 sec)
mysql>

我们创建了一个名为test_user的用户;该用户的密码为test123。接下来,我们授予我们的test_user用户所有权限。现在,通过运行quit;exit;命令退出mysql控制台。

现在,我们将看一些示例,获取数据库版本,创建表,将一些数据插入表中,更新数据和删除数据。

获取数据库版本

首先,我们将看一个获取数据库版本的示例。为此,我们将创建一个get_database_version.py脚本,并在其中编写以下内容:

import MySQLdb as mdb import sys  con_obj = mdb.connect('localhost', 'test_user', 'test123', 'test') cur_obj = con_obj.cursor() cur_obj.execute("SELECT VERSION()") version = cur_obj.fetchone() print ("Database version: %s " % version) con_obj.close()

在运行此脚本之前,非常重要遵循先前的步骤;不应跳过它们。

运行脚本,您将获得以下输出:

student@ubuntu:~/work/mysql_testing$ python3 get_database_version.py Output: Database version: 5.7.24-0ubuntu0.18.04.1

在上面的示例中,我们得到了数据库版本。首先,我们导入了 MySQLdb 模块。然后我们编写了连接字符串。在连接字符串中,我们提到了我们的用户名、密码和数据库名称。接下来,我们创建了一个游标对象,用于执行 SQL 查询。在execute()中,我们传递了一个 SQL 查询。fetchone()检索查询结果的下一行。接下来,我们打印了结果。close()方法关闭了数据库连接。

创建表和插入数据

现在,我们将创建一个表,并向其中插入一些数据。为此,创建一个create_insert_data.py脚本,并在其中写入以下内容:

import MySQLdb as mdb con_obj = mdb.connect('localhost', 'test_user', 'test123', 'test') with con_obj:
 cur_obj = con_obj.cursor() cur_obj.execute("DROP TABLE IF EXISTS books") cur_obj.execute("CREATE TABLE books(Id INT PRIMARY KEY AUTO_INCREMENT, Name VARCHAR(100))") cur_obj.execute("INSERT INTO books(Name) VALUES('Harry Potter')") cur_obj.execute("INSERT INTO books(Name) VALUES('Lord of the rings')") cur_obj.execute("INSERT INTO books(Name) VALUES('Murder on the Orient Express')") cur_obj.execute("INSERT INTO books(Name) VALUES('The adventures of Sherlock Holmes')") cur_obj.execute("INSERT INTO books(Name) VALUES('Death on the Nile')") print("Table Created !!") print("Data inserted Successfully !!")

运行脚本,您将获得以下输出:

student@ubuntu:~/work/mysql_testing$ python3 create_insert_data.py Output: Table Created !! Data inserted Successfully !!

要检查您的表是否成功创建,请打开您的mysql控制台并运行以下命令:

student@ubuntu:~/work/mysql_testing$ sudo mysql -u root -p Enter password: Welcome to the MySQL monitor.  Commands end with ; or \g. Your MySQL connection id is 6 Server version: 5.7.24-0ubuntu0.18.04.1 (Ubuntu)
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> mysql> mysql> use test; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> show tables; +----------------+ | Tables_in_test | +----------------+ | books          | +----------------+ 1 row in set (0.00 sec)

您可以看到您的 books 表已创建。

检索数据

要从表中检索数据,我们使用select语句。现在,我们将从我们的 books 表中检索数据。为此,创建一个retrieve_data.py脚本,并在其中写入以下内容:

import MySQLdb as mdb con_obj = mdb.connect('localhost', 'test_user', 'test123', 'test') with con_obj:
 cur_obj = con_obj.cursor() cur_obj.execute("SELECT * FROM books") records = cur_obj.fetchall() for r in records: print(r)

运行脚本,您将获得以下输出:

student@ubuntu:~/work/mysql_testing$ python3 retrieve_data.py Output: (1, 'Harry Potter') (2, 'Lord of the rings') (3, 'Murder on the Orient Express') (4, 'The adventures of Sherlock Holmes') (5, 'Death on the Nile')

在上面的示例中,我们从表中检索了数据。我们使用了 MySQLdb 模块。我们编写了一个连接字符串并创建了一个游标对象来执行 SQL 查询。在execute()中,我们编写了一个 SQLselect语句。最后,我们打印了记录。

更新数据

现在,如果我们想对记录进行一些更改,我们可以使用 SQLupdate语句。我们将看一个update语句的示例。为此,创建一个update_data.py脚本,并在其中写入以下内容:

import MySQLdb as mdb con_obj = mdb.connect('localhost', 'test_user', 'test123', 'test') cur_obj = con_obj.cursor() cur_obj.execute("UPDATE books SET Name = 'Fantastic Beasts' WHERE Id = 1")try:
 con_obj.commit() except:
 con_obj.rollback()

按以下方式运行脚本:

student@ubuntu:~/work/mysql_testing$ python3 update_data.py

现在,要检查您的记录是否已更新,请按以下方式运行retrieve_data.py

student@ubuntu:~/work/mysql_testing$ python3 retrieve_data.py Output: (1, 'Fantastic Beasts') (2, 'Lord of the rings') (3, 'Murder on the Orient Express') (4, 'The adventures of Sherlock Holmes') (5, 'Death on the Nile')

您可以看到 ID 为1的数据已更新。在上面的示例中,在execute()中,我们编写了一个update语句,将更新 ID 为1的数据。

删除数据

要从表中删除特定记录,请使用delete语句。我们将看一个删除数据的示例。创建一个delete_data.py脚本,并在其中写入以下内容:

import MySQLdb as mdb con_obj = mdb.connect('localhost', 'test_user', 'test123', 'test') cur_obj = con_obj.cursor() cur_obj.execute("DELETE FROM books WHERE Id = 5"); try:
 con_obj.commit() except:
 con_obj.rollback() 

按以下方式运行脚本:

student@ubuntu:~/work/mysql_testing$ python3 delete_data.py

现在,要检查您的记录是否已删除,请按以下方式运行retrieve_data.py脚本:

student@ubuntu:~/work/mysql_testing$ python3 retrieve_data.py Output: (1, 'Fantastic Beasts') (2, 'Lord of the rings') (3, 'Murder on the Orient Express') (4, 'The adventures of Sherlock Holmes')

您可以看到,您的 ID 为5的记录已被删除。在上面的示例中,我们使用了delete语句来删除特定记录。在这里,我们删除了 ID 为5的记录。您还可以根据自己选择的任何字段名删除记录。

SQLite 数据库管理

在本节中,我们将学习如何安装和使用 SQLite。Python 有sqlite3模块来执行 SQLite 数据库任务。SQLite 是一个无服务器、零配置、事务性 SQL 数据库引擎。SQLite 非常快速和轻量级。整个数据库存储在单个磁盘文件中。

现在,我们将首先安装 SQLite。在终端中运行以下命令:

$ sudo apt install sqlite3

在本节中,我们将学习以下操作:创建数据库、创建表、向表中插入数据、检索数据,以及从表中更新和删除数据。我们将逐个查看每个操作。

现在,首先,我们将看如何在 SQLite 中创建数据库。要创建数据库,您只需在终端中输入以下命令:

$ sqlite3 test.db

运行此命令后,您将在终端中打开sqlite控制台,如下所示:

student@ubuntu:~$ sqlite3 test.db SQLite version 3.22.0 2018-01-22 18:45:57 Enter ".help" for usage hints. sqlite>

您的数据库已通过简单运行sqlite3 test.db创建。

连接到数据库

现在,我们将看到如何连接到数据库。为此,我们将创建一个脚本。Python 已经在标准库中包含了一个sqlite3模块。我们只需要在使用 SQLite 时导入它。创建一个connect_database.py脚本,并在其中写入以下内容:

import sqlite3 con_obj = sqlite3.connect('test.db') print ("Database connected successfully !!")

运行脚本,您将获得以下输出:

student@ubuntu:~/work $ python3 connect_database.py Output: Database connected successfully !!

在前面的例子中,我们导入了sqlite3模块来执行功能。现在,检查您的目录,您将在目录中找到创建的test.db文件。

创建表

现在,我们将在我们的数据库中创建一个表。为此,我们将创建一个create_table.py脚本,并在其中写入以下内容:

import sqlite3 con_obj = sqlite3.connect("test.db") with con_obj:
 cur_obj = con_obj.cursor() cur_obj.execute("""CREATE TABLE books(title text, author text)""")  print ("Table created")

运行脚本,您将得到以下输出:

student@ubuntu:~/work $ python3 create_table.py Output: Table created

在前面的例子中,我们使用CREATE TABLE语句创建了一个名为 books 的表。首先,我们使用test.db建立了与数据库的连接。接下来,我们创建了一个游标对象,用于在数据库上执行 SQL 查询。

插入数据

现在,我们将向我们的表中插入数据。为此,我们将创建一个insert_data.py脚本,并在其中写入以下内容:

import sqlite3 con_obj = sqlite3.connect("test.db") with con_obj:
 cur_obj = con_obj.cursor() cur_obj.execute("INSERT INTO books VALUES ('Pride and Prejudice', 'Jane Austen')") cur_obj.execute("INSERT INTO books VALUES ('Harry Potter', 'J.K Rowling')") cur_obj.execute("INSERT INTO books VALUES ('The Lord of the Rings', 'J. R. R. Tolkien')") cur_obj.execute("INSERT INTO books VALUES ('Murder on the Orient Express', 'Agatha Christie')") cur_obj.execute("INSERT INTO books VALUES ('A Study in Scarlet', 'Arthur Conan Doyle')") con_obj.commit() print("Data inserted Successfully !!")

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 insert_data.py Output: Data inserted Successfully !!

在前面的例子中,我们向我们的表中插入了一些数据。为此,我们在 SQL 语句中使用了insert。通过使用commit(),我们告诉数据库保存所有当前的事务。

检索数据

现在,我们将从表中检索数据。为此,创建一个retrieve_data.py脚本,并在其中写入以下内容:

import sqlite3 con_obj = sqlite3.connect('test.db') cur_obj = con_obj.execute("SELECT title, author from books")
for row in cur_obj:
 print ("Title = ", row[0]) print ("Author = ", row[1], "\n") con_obj.close()

运行脚本,您将得到以下输出:

student@ubuntu:~/work$ python3 retrieve_data.py Output: Title =  Pride and Prejudice Author =  Jane Austen
Title =  Harry Potter Author =  J.K Rowling
Title =  The Lord of the Rings Author =  J. R. R. Tolkien
Title =  Murder on the Orient Express Author =  Agatha Christie
Title =  A Study in Scarlet Author =  Arthur Conan Doyle

在前面的例子中,我们导入了sqlite3模块。接下来,我们连接到了我们的test.db数据库。为了检索数据,我们使用了select语句。最后,我们打印了检索到的数据。

您还可以在sqlite3控制台中检索数据。为此,首先启动 SQLite 控制台,然后按照以下方式检索数据:

student@ubuntu:~/work/sqlite3_testing$ sqlite3 test.db Output: SQLite version 3.22.0 2018-01-22 18:45:57 Enter ".help" for usage hints. sqlite> sqlite> select * from books; Pride and Prejudice|Jane Austen Harry Potter|J.K Rowling The Lord of the Rings|J. R. R. Tolkien Murder on the Orient Express|Agatha Christie A Study in Scarlet|Arthur Conan Doyle sqlite>

更新数据

我们可以使用update语句从我们的表中更新数据。现在,我们将看一个更新数据的例子。为此,创建一个update_data.py脚本,并在其中写入以下内容:

import sqlite3 con_obj = sqlite3.connect("test.db") with con_obj:
            cur_obj = con_obj.cursor()
 sql = """ UPDATE books SET author = 'John Smith' WHERE author = 'J.K Rowling' """ cur_obj.execute(sql) print("Data updated Successfully !!")

运行脚本,您将得到以下输出:

student@ubuntu:~/work $ python3 update_data.py Output: Data updated Successfully !!

现在,要检查数据是否实际上已更新,请运行retrieve_data.py,或者您可以转到 SQLite 控制台并运行select * from books;。您将得到更新后的输出如下:

By running retrieve_data.py: Output: student@ubuntu:~/work$ python3 retrieve_data.py Title =  Pride and Prejudice Author =  Jane Austen
Title =  Harry Potter Author =  John Smith
Title =  The Lord of the Rings Author =  J. R. R. Tolkien
Title =  Murder on the Orient Express Author =  Agatha Christie
Title =  A Study in Scarlet Author =  Arthur Conan Doyle
Checking on SQLite console: Output: student@ubuntu:~/work$ sqlite3 test.db SQLite version 3.22.0 2018-01-22 18:45:57 Enter ".help" for usage hints. sqlite> sqlite> select * from books; Pride and Prejudice|Jane Austen Harry Potter|John Smith The Lord of the Rings|J. R. R. Tolkien Murder on the Orient Express|Agatha Christie A Study in Scarlet|Arthur Conan Doyle sqlite>

删除数据

现在,我们将看一个从表中删除数据的例子。我们将使用delete语句来做到这一点。创建一个delete_data.py脚本,并在其中写入以下内容:

import sqlite3 con_obj = sqlite3.connect("test.db") with con_obj:
 cur_obj = con_obj.cursor()            sql = """
 DELETE FROM books WHERE author = 'John Smith' """ cur_obj.execute(sql) print("Data deleted successfully !!")

运行脚本,您将得到以下输出:

student@ubuntu:~/work $ python3 delete_data.py Output: Data deleted successfully !!

在前面的例子中,我们从表中删除了一条记录。我们使用了delete SQL 语句。现在,要检查数据是否成功删除,请运行retrieve_data.py或启动 SQLite 控制台,如下所示:

By running retrieve_data.py Output: student@ubuntu:~/work$ python3 retrieve_data.py Title =  Pride and Prejudice Author =  Jane Austen
Title =  The Lord of the Rings Author =  J. R. R. Tolkien
Title =  Murder on the Orient Express Author =  Agatha Christie
Title =  A Study in Scarlet Author =  Arthur Conan Doyle

您可以看到作者是john smith的记录已被删除:

Checking on SQLite console: Output: student@ubuntu:~/work$ sqlite3 test.db SQLite version 3.22.0 2018-01-22 18:45:57 Enter ".help" for usage hints. sqlite> sqlite> select * from books; Pride and Prejudice|Jane Austen The Lord of the Rings|J. R. R. Tolkien Murder on the Orient Express|Agatha Christie A Study in Scarlet|Arthur Conan Doyle sqlite>

总结

在本章中,我们学习了 MySQL 以及 SQLite 数据库管理。我们创建了数据库和表。然后我们在表中插入了一些记录。使用select语句,我们检索了记录。我们还学习了更新和删除数据。

问题

  1. 数据库用于什么?

  2. 数据库中的 CRUD 是什么?

  3. 我们可以连接远程数据库吗?如果可以,请举例说明。

  4. 我们可以在 Python 代码中编写触发器和存储过程吗?

  5. 什么是 DML 和 DDL 语句?

进一步阅读

第十九章:评估

第一章,Python 脚本概述

  1. 迭代器是可以被迭代的对象。它是一个会返回数据的对象,每次返回一个元素。生成器是一个可以迭代的函数,它返回一个对象。

  2. 列表是可变的。

  3. Python 中的数据结构是可以一起保存一些数据的结构。换句话说,它们用于存储相关数据的集合。

  4. 我们可以通过使用索引值来访问列表中的值。

  5. 模块只是包含 Python 语句和定义的文件。

第二章,调试和分析 Python 脚本

  1. 要调试程序,使用pdb模块。

  2. a) 在运行ipython3之前,使用sudo apt-get install ipython3进行安装。

b) %lsmagic

  1. 全局解释器锁是计算机语言解释器中使用的一种机制,用于同步线程的执行,以便一次只有一个本机线程可以执行

  2. 以下是答案:

a) PYTHONPATH:它的作用类似于 PATH。此变量告诉 Python 解释器在程序中导入的模块文件的位置。它应该包括 Python 源库目录和包含 Python 源代码的目录。PYTHONPATH有时会被 Python 安装程序预设。

b) PYTHONSTARTUP:它包含包含 Python 源代码的初始化文件的路径。每次启动解释器时都会执行它。在 Unix 中,它被命名为.pythonrc.py,它包含加载实用程序或修改PYTHONPATH的命令。

c) PYTHONCASEOK:在 Windows 中用于指示 Python 在导入语句中找到第一个不区分大小写的匹配项。将此变量设置为任何值以激活它。

d) PYTHONHOME:这是一个替代的模块搜索路径。通常嵌入在PYTHONSTARTUPPYTHONPATH目录中,以便轻松切换模块库。

  1. 答案:[0]

在函数中创建了一个新的列表对象,并且引用丢失了。可以通过比较kk = [1]之前和之后的 ID 来检查这一点。

  1. 答案:b. 变量名不应以数字开头。

第三章,单元测试 - 单元测试框架简介

  1. 单元测试是软件测试的一种级别,其中测试软件的各个单元/组件。目的是验证软件的每个单元是否按设计执行。

自动化测试是一种自动化技术,其中测试人员自己编写脚本并使用适当的软件来测试软件。基本上是手动流程的自动化过程。

手动测试是发现软件程序中的缺陷或错误的过程。在这种方法中,测试人员扮演端用户的重要角色,并验证应用程序的所有功能是否正常工作。

  1. Unittest,mock,nose,pytest

  2. 测试用例是为验证软件应用程序的特定功能或功能而执行的一组操作。本教程描述了测试用例的设计以及其各个组件的重要性。

  3. PEP 8 是 Python 的风格指南。这是一组规则,用于格式化您的 Python 代码,以最大限度地提高其可读性。按照规范编写代码有助于使具有许多编写者的大型代码库更加统一和可预测。

第四章,自动化常规管理活动

  1. readline()方法从文件中读取整行。字符串中保留了尾随的换行符。如果存在大小参数并且为非负,则它是包括尾随换行符在内的最大字节计数,并且可能返回不完整的行。

  2. 读取:cat

创建新文件:touch

删除文件:rm

列出当前目录中的文件:ls

  1. 以下是答案:
os.system(“shell_command”)
subprocess.getstatusoutput(“shell_command”)
  1. 以下是答案:
import configparser as config
config.set(section, option, value)
  1. 以下是答案:
 psutil, fabric, salt, asnible, buildbot, shinken
  1. 以下是答案:
input() 
sys.stdin.readline()
  1. 当您想要改变列表时使用list.sort(),当您想要一个新的排序对象时使用sorted()。对于尚未是列表的可迭代对象,使用sorted()进行排序更快。对于列表,list.sort()sorted()更快,因为它不必创建副本。

第五章,处理文件、目录和数据

  1. 通过使用pathlib库。

  2. 以下是答案:

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
  1. 如果没有参数调用,则返回当前范围内的名称。否则,返回给定对象的属性(部分)组成的名称的按字母顺序排列的列表,以及可从该对象到达的属性。

  2. DataFrame 是一个二维大小、可变且可能异构的带标签轴的表格数据结构。

Series 是 DataFrame 的单列数据结构,不仅在概念上是如此,而且在内存中实际上是作为一系列存储的。

  1. 列表推导提供了一种简洁的方法来创建新列表。

  2. 是的:

Set comprehension {s**2 for s in range(10)}
Dict comprehension {n: n**2 for n in range(5)}
  1. 以下是答案:
df.head(number of lines) default blank 
df.tail(number of lines) default blank
  1. 以下是答案:
[i for i in range(10) if i%2]
  1. 答案:b。这是一个元素列表。

第六章,文件归档、加密和解密

  1. 是的,使用 Python 的pyminizip库。

  2. 上下文管理器是一种在需要时精确分配和释放某种资源的方法。最简单的例子是文件访问:

with open ("foo", 'w+') as foo:
foo.write("Hello!")
is similar to
foo = open ("foo", 'w+'):
 foo.write("Hello!")
foo.close()
  1. 在 Python 中,pickling 指的是将对象序列化为二进制流的过程,而 unpickling 是其相反过程。

  2. 无参数且无返回值的函数

无参数且有返回值的函数

带参数且无返回值的函数

带参数和返回值的函数

第七章,文本处理和正则表达式

  1. 正则表达式是编程中用于模式匹配的方法。正则表达式提供了一种灵活而简洁的方法来匹配文本字符串。

  2. 以下是答案:

import redef is_allowed_specific_char(string):
 charRe = re.compile(r'[^a-zA-Z0-9.]')
 string = charRe.search(string)
 return not bool(string)
 print(is_allowed_specific_char("ABCDEFabcdef123450"))
 print(is_allowed_specific_char("*&%@#!}{"))
  1. 答案:a。

re是标准库的一部分,可以使用import re导入。

  1. 答案:a。

它将在开头查找模式,如果找不到则返回None

  1. 答案:d。

此函数返回整个匹配。

第八章,文档和报告

  1. 主要区别在于当您使用inputprint函数时,所有的输出格式化工作都是在幕后完成的。stdin 用于所有交互式输入,包括对input()的调用;stdout 用于print()和表达式语句的输出以及input()的提示。

  2. 简单邮件传输协议SMTP)是用于电子邮件传输的互联网标准。最初由 RFC 821 在 1982 年定义,2008 年通过 RFC 5321 进行了扩展 SMTP 的更新,这是今天广泛使用的协议。

  3. 以下是答案:

Hi Eric. You are a comedian. You were in Monty Python.
  1. 以下是答案:
str1 + str2 = HelloWorld!
str1 * 3 = HelloHelloHello

第九章,处理各种文件

  1. f.readline()从文件中读取一行;一个换行符(\n)留在字符串的末尾,并且只有在文件的最后一行没有换行符时才会被省略。如果要将文件的所有行读入列表中,还可以使用list(f)f.readlines()

  2. 基本上,使用with open()只是确保您不会忘记close()文件,使其更安全/防止内存问题。

  3. r表示该字符串将被视为原始字符串。

  4. 生成器简化了迭代器的创建。生成器是一个产生一系列结果而不是单个值的函数。

  5. 在 Python 中,pass 语句用于在语法上需要语句但您不希望执行任何命令或代码时使用。pass 语句是一个空操作;执行时什么也不会发生。

  6. 在 Python 中,匿名函数是在没有名称的情况下定义的函数。而普通函数是使用def关键字定义的,Python 中的匿名函数是使用lambda关键字定义的。因此,匿名函数也称为 lambda 函数。

第十章,基本网络 - 套接字编程

  1. 套接字编程涉及编写计算机程序,使进程能够在计算机网络上相互通信。

  2. 在分布式计算中,远程过程调用是指计算机程序导致在不同地址空间中执行过程,这是编码为正常过程调用,程序员不需要显式编码远程交互的细节。

  3. 以下是答案:

import filename (import file)
from filename import function1 (import specific function)
from filename import function1, function2(import multiple functions)
from filename import * (import all the functions)
  1. 列表和元组之间的主要区别在于列表是可变的,而元组是不可变的。可变数据类型意味着可以修改此类型的 Python 对象。不可变意味着不能修改此类型的 Python 对象。

  2. 你不能有一个带有重复键的字典,因为在后台它使用了一个哈希机制。

  3. urlliburllib2都是执行 URL 请求相关操作的 Python 模块,但提供不同的功能。

urllib2可以接受一个请求对象来设置 URL 请求的标头,urllib只接受一个 URL。Python 请求会自动编码参数,因此您只需将它们作为简单参数传递。

第十一章,使用 Python 脚本处理电子邮件

  1. 在计算中,邮局协议是一种应用层互联网标准协议,用于电子邮件客户端从邮件服务器检索电子邮件。 POP 版本 3 是常用的版本。Internet Message Access ProtocolIMAP)是一种互联网标准协议,用于电子邮件客户端通过 TCP/IP 连接从邮件服务器检索电子邮件消息。 IMAP 由 RFC 3501 定义。

  2. break 语句终止包含它的循环。程序的控制流流向循环体之后的语句。如果 break 语句在嵌套循环(一个循环内部的循环)中,break 将终止最内层的循环。以下是一个例子:

for val in "string":
 if val == "i":
 break
 print(val)
print("The end")
  1. continue 语句用于仅跳过当前迭代中循环内部的其余代码。循环不会终止,而是继续下一个迭代:
for val in "string":
 if val == "i":
 continue
 print(val)
print("The end")
  1. pprint模块提供了一种能够以可用作解释器输入的形式漂亮打印任意 Python 数据结构的功能。如果格式化的结构包括不是基本 Python 类型的对象,则表示可能无法加载。如果包括文件、套接字、类或实例等对象,以及许多其他无法表示为 Python 常量的内置对象,可能会出现这种情况。

  2. 在 Python 中,负索引用于从列表、元组或支持索引的任何其他容器类的最后一个元素开始索引。-1指的是最后一个索引-2指的是倒数第二个索引,依此类推。

  3. Python 编译.py文件并将其保存为.pyc文件,以便在后续调用中引用它们。.pyc包含 Python 源文件的已编译字节码。.pyc包含 Python 源文件的已编译字节码,这是 Python 解释器将源代码编译为的内容。然后,Python 的虚拟机执行此代码。删除.pyc不会造成任何损害,但如果要进行大量处理,它们将节省编译时间。

  4. 以下是答案:

num = 7
for index in range(num,0,-1):
if index % 2 != 0:
for row in range(0,num-index):
print(end=" ")
for row in range(0,index):
if row % 2== 0:
print("1",end=" ")
else:
print("0",end=" ")
print()

第十二章,通过 Telnet 和 SSH 远程监视主机

  1. 客户端-服务器模型是一种分布式应用程序结构,它在资源或服务的提供者(称为服务器)和服务请求者(称为客户端)之间分配任务或工作负载。

  2. 通过使用以下内容:

os.commands(command_name)
subprocess.getstatusoutput(command_name)
  1. 虚拟局域网是在数据链路层上分区和隔离的任何广播域,局域网是本地区域网络的缩写,在这种情况下,虚拟指的是通过附加逻辑重新创建和改变的物理对象。

  2. 答案:[]

它打印一个空列表,因为列表的大小小于 10。

  1. 以下是答案:
import calender
calendar.month(1,1)
  1. 以下是答案:
def file_lengthy(fname):
 with open(fname) as f:
 for i, l in enumerate(f):
 pass
 return i + 1
print("Number of lines in the file: ",file_lengthy("test.txt"))

第十三章,构建图形用户界面

  1. 图形用户界面,允许用户与电子设备进行交互。

  2. 构造函数是一种特殊类型的方法(函数),用于初始化类的实例成员。__init__ 方法的实现。析构函数是在对象销毁期间自动调用的特殊方法。__del__ 方法的实现。

  3. Self 是对对象本身的对象引用;因此,它们是相同的。

  4. Tkinter 是 Python 绑定到 Tk GUI 工具包的工具。它是 Tk GUI 工具包的标准 Python 接口,也是 Python 的事实标准 GUI。Tkinter 包含在标准的 Linux、Microsoft Windows 和 macOS X 的 Python 安装中。Tkinter 的名称来自 Tk 界面。PyQt 是跨平台 GUI 工具包 Qt 的 Python 绑定,实现为 Python 插件。PyQt 是由英国公司 Riverbank Computing 开发的免费软件。wxPython 是 Python 编程语言的跨平台 GUI API wxWidgets 的包装器。它是 Tkinter 的替代品之一,与 Python 捆绑在一起。它实现为 Python 扩展模块。其他流行的替代品是 PyGTK,它的后继者 PyGObject 和 PyQt。

  5. 以下是答案:

def copy(source, destination):
 with open(source, "w") as fw, open(destination,"r") as fr:
 fw.writelines(fr)
copy(source_file_name1, file_name2)
  1. 以下是答案:
fname = input("Enter file name: ")
l=input("Enter letter to be searched:")
k = 0
with open(fname, 'r') as f:
 for line in f:
 words = line.split()
 for i in words:
 for letter in i:
 if(letter==l):
 k=k+1
print("Occurrences of the letter:")
print(k)

第十四章,使用 Apache 和其他日志文件

  1. 运行时异常发生在程序执行期间,它们会在中途突然退出。编译时异常是在程序执行开始之前发现的异常。

  2. 正则表达式、regex 或 regexp 是定义搜索模式的字符序列。通常,这种模式由字符串搜索算法用于字符串的查找或查找和替换操作,或用于输入验证。

  3. 以下是 Linux 命令的描述:

  • head:用于查看普通文件的前 N 行。

  • tail:用于查看普通文件的最后 N 行。

  • cat:用于查看普通文件的内容。

  • awk:AWK 是一种专为文本处理而设计的编程语言,通常用作数据提取和报告工具。它是大多数类 Unix 操作系统的标准功能。

  1. 以下是答案:
def append(source, destination):
 with open(source, "a") as fw, open(destination,"r") as fr:
 fw.writelines(fr)
append(source_file_name1, file_name2)
  1. 以下是答案:
filename=input("Enter file name: ")
for line in reversed(list(open(filename))):
 print(line.rstrip())
  1. 表达式的输出如下:

  2. C@ke

  3. Cooookie

  4. <h1>

第十五章,SOAP 和 REST API 通信

  1. REST 基本上是 Web 服务的一种架构风格,它作为不同计算机或系统之间的通信渠道在互联网上工作。SOAP 是一种标准的通信协议系统,允许使用不同操作系统(如 Linux 和 Windows)的进程通过 HTTP 及其 XML 进行通信。基于 SOAP 的 API 旨在创建、恢复、更新和删除记录,如账户、密码、线索和自定义对象。

  2. json.load可以反序列化文件本身;也就是说,它接受文件对象。

  3. 是的。JSON 是平台无关的。

  4. 答案:false。

  5. 答案:{'x': 3}

第十六章,网络抓取-从网站提取有用数据

  1. Web 抓取、网络收集或网络数据提取是用于从网站提取数据的数据抓取。Web 抓取软件可以直接使用超文本传输协议访问万维网,也可以通过 Web 浏览器访问。

  2. Web 爬虫(也称为网络蜘蛛或网络机器人)是以一种有条理、自动化的方式浏览万维网的程序或自动化脚本。这个过程称为网络爬行或蜘蛛。

  3. 是的。

  4. 是的,使用 Tweepy。

  5. 是的,通过使用 Selenium-Python 网络驱动程序。还有其他库可用,如 PhantomJS 和 dryscrape。

第十七章,统计收集和报告

  1. NumPy 的主要对象是同质多维数组。它是一张元素表(通常是数字),都是相同类型的,由正整数元组索引。在 NumPy 中,维度被称为轴。

  2. 以下是输出:

1st Input array : 
 [[ 1 2 3]
 [-1 -2 -3]]
2nd Input array : 
 [[ 4 5 6]
 [-4 -5 -6]]
Output stacked array :
 [[ 1 2 3 4 5 6]
 [-1 -2 -3 -4 -5 -6]]
  1. 以下是答案:
Z = np.arange(10)
np.add.reduce(Z)
  1. 以下是答案:
# Delete the rows with labels 0,1,5
data = data.drop([0,1,2], axis=0)
# Delete the first five rows using iloc selector
data = data.iloc[5:,]
#to delete the column
del df.column_name
  1. 以下是答案:
df.to_csv(“file_name.csv”,index=False, sep=”,”)
  1. 不是 数字(NaN),比如空值。在 pandas 中,缺失值用 NaN 表示。

  2. 以下是答案:

df.drop_duplicates()
  1. 以下是答案:
from matplotlib.pyplot import figure
figure(num=None, figsize=(8, 6), dpi=80, facecolor='w', edgecolor='k')
  1. Matplotlib、Plotly 和 Seaborn。

第十八章,MySQL 和 SQLite 数据库管理

  1. 将数据存储在行和列中,并且可以轻松快速地执行不同的操作。

  2. 在数据库中,CRUD 代表(创建,读取,更新,删除)。

  3. 是的,这里有一个例子:

MySQLdb.connect('remote_ip', 'username', 'password', 'databasename')
  1. 是的。

  2. DDL代表数据定义语言。它用于定义数据结构。例如,使用 SQL,它将是创建表,修改表等指令。DML代表数据操作语言。它用于操作数据本身。例如,使用 SQL,它将是插入,更新和删除等指令。

posted @ 2025-09-23 21:57  绝不原创的飞龙  阅读(20)  评论(0)    收藏  举报