资讯详情

【从零开始NetDevOps】第二章网工速通Python

《从零开始NetDevOps》本人8年多了NetDevOps一本实战总结的书(又称书,通过微信官方账号连载,集成成册,希望有一天能以实体书的形式与大家见面)。

NetDevOps是指以网络工程师为主体,自动开发网络运维场景的工作思路和模式,是2014年左右从国外刮来的网络工程Python"近年来,中国的趋势逐渐兴起。我在中国一家大型金融机构的数据中心从事网络自动化开发已有8年了。我希望通过分享我的知识,我能向你展示一种不同于他人的实际战斗指导,强大的普遍性,善于挖掘细节,知道为什么风格,简单NetDevOps知识体系,给大家一个不同的视角,一个来自于实战中的视角。

由于时间匆忙,文章中难免会出现错误。请理解。同时,作者将在每章完成后进行修改和发布。欢迎继续关注

本系列文章将连载NetDevOps加油站微信官方账号欢迎大家点赞关注 在这里插入图片描述

第二章 Python基础

在第一章,我和大家分享了我的对NetDevOps的认知,NetDevOps简要介绍了发展的几个重要阶段Python这种语言开发,本章开始我们要开始硬核之旅,带领大家从零开始掌握Python,只有掌握了Python我们可以根据自己的需要编写脚本甚至工具平台来开发编程语言。

Python对于网络工程师来说,掌握它是一种非常简单易用的编程语言Python这件事并不,大家要做的就是一步一步掌握每一节的知识点,亲自敲出来!

本章将从网络运维的知识体系出发Python解释清楚,解释核心部分。当新手面对一门语言时,我个人认为我们需要尽快掌握最基本、最核心的知识,并快速编写有效的脚本,以便有动力继续前进。许多初学者最容易犯的错误可能是买一本很好的书。从头到尾学习后,他们不能写有用的代码(减少工作量的脚本)。如果他们不明白,他们也可以写一些简单的脚本,比如数字大小、猜测数字等等。这也与NetDevOps我们没有将开发应用到日常运维中。如何避免这种困境?最好的实践方法是掌握最核心、最基本的语法,以解决实际工作中遇到的问题为方向,不要被庞大的编程语言系统淹没在学习的迷雾中。以基本语法为核心,以解决实际问题为目的,不断扩大这种语言的学习范围和深度,实现滚雪球的效果,在简单的脚本中看到光线,在解决问题后找到信心!

同时,在学习知识的过程中,我们应该学会从一个例子中得出推论,触摸庞通。例如,许多书以现实生活中的基本语法为例。作为网络工程师,我们应该学会将这些场景映射到网络运维中,类比网络运维。

工欲善其事必先利其器,首先让我们一起动手搭建一个Python开发环境吧!

2.1 版本选择与环境搭建

我应该选择哪一个Python版本?

关于Python在这个时代,版本的选择是毫无疑问的,必须选择Python3。Python在当今时代,无论是官方的还是第三的,都是明天的黄花Python支持已经结束。而且根据个人实践,我更推荐Python3.8、Python3.9。根据我在实际生产中的使用,以及一些Python许多工具包,许多包至少需要3个.6的某个比较靠后的版本,基本都能支持3.9,所以3.8和3.9是不错的选择。本书涉及的包对3.9的支持也比较好,3.9的官方支持时间将比3.8时间比较长,所以目前个人认为最佳解是3.9。当然,随着时间的变化,你也可以根据这个想法来决定你的入门Python版本。

同时,根据作者的一些实践经验,我也推荐初学者安装Anaconda最新版本(截至发布,最新版本为2022.5,内含Python3.9版本),它是开源的Python包括发行版conda、Python等180多个科学包及其依赖项,虽然是用于科学计算,但是集成的这180个包,如果离的办公网络中,可以减少很多麻烦,内部集成Jupyter Notebook这种基于web的交互式的IDE(开发集成环境,简单理解就是开发工具)。也是新手或者简单写一些测试脚本的好选择。

当然,这本书还是纯粹的Python作为演示,暂时不安装环境Anaconda。

Python的安装

对于新手,我会强调:**确保你的电脑里只有一台Python环境!**如果安装问题不符合预期,必须卸载,重新启动计算机,确保没有文件残留,然后点击安装文件进行安装!

一台电脑可以装多个Python但是Python只有一个可操作文件在环境变量中生效,我们安装了一个Python环境被加载到环境变量中,由于某种原因,我们可能会选择重新安装,如果操作有点粗心,可能会导致计算机中的两个共存Python,而对于初学者而言,常常不知道自己到底用了哪个Python环境,这是我在实际工作中观察到的,许多网络工程师会被环境安装说服,或者在后期,由于环境问题,他们无法开发。例如,您安装了连接网络设备netmiko包(后续会详细说明)认为自己在开发中使用A环境。IDE也默认了A环境,但是不管怎么导入这个包,程序都说找不到。例如,您安装了连接网络设备netmiko包(后续会详细说明)认为自己在开发中使用A环境。IDE也默认了A环境,但是不管怎么导入这个包,程序都说找不到。原因是安装初期各种问题重新安装。Python,导致多个Python共存,netmiko实际安装在B环境中。无论你怎么进口,你的开发环境都指向A环境。

我们必须去官方网站,结合自己的操作系统下载相应的Python安装文件。官网地址https://www.python.org/

[外链图片存储失败,源站可能有防盗链机制,建议保存图片直接上传(img-xwd7lZfe-1658882259395)(assets/image-20220527002110867.png)]

我们点击官网Downloads的All releases进入版本选择页面的导航栏。

[外链图片存储失败,源站可能有防盗链机制,建议保存图片直接上传(img-qD0Uyy9R-1658882259397)(assets/image-20220527002222391.png)]

在上半部分,我们会看到Python几个活跃版本,其发行日期和官方支持结束日期。.9版本综合官方支持时间和当前主流NetDevOps Python支持工具包是最优解。

我们来到网站中间,选择最新的Python3.9版本,点击download选择安装包。

[外链图片存储失败,源站可能有防盗链机制,建议保存图片直接上传(img-YI7eEdPq-1658882259398)(assets/image-20220527002424062.png)]

在新打开的网站底部,我们可以单击相应的安装文件下载。本书的操作系统为64位win10操作系统,选择相应版本下载安装。

[外链图片存储失败,源站可能有防盗链机制,建议保存图片直接上传(img-4TGTkqjC-1658882259398)(assets/image-20220527002612549.png)]

双加对应的安装文件,这个时候一定要勾选上将Python将选项添加到环境变量中,以便我们打开它cmd窗口输入Python会有效果的。我们可以选择将其安装在默认位置或指定盘符目录中。

[外链图片存储失败,源站可能有防盗链机制,建议保存图片直接上传(img-Cf7Ykz7A-1658882259399)(assets/image-20220527002946978.png)]

安装很快就完成了。此时,我们打开它CMD,输入“python”,进入到Python交互式编程窗口。到目前为止,Python安装完成。

通过在CMD(或者其他terminal中)敲入“python进入的模式是Python在这里,我们将实时计算每个命令。但这些代码在关闭窗口后也消失了。事实上,它更多地用于演示或测试一些相对较短的代码,响应会更快。

[外链图片存储失败,源站可能有防盗链机制,建议保存图片直接上传(img-cbtgzXci-1658882259400)(assets/image-20220527185811927.png)]

现在请和我一起敲下第一行代码

print('Hello,world') 

[外链图片存储失败,源站可能有防盗链机制,建议保存图片直接上传(img-ViT00GVB-1658882259401)(assets/image-20220527185854880.png)]

到目前为止,我们已经完成了Python安装敲下了我们的第一行Python代码。

总结
  1. 新手建议选择Python3.9。
  2. 新手建议电脑里只有一套Python环境。

2.2 IDE推荐设置

安装好了Python我们需要选择环境Python的IDE(集成开发环境)。IDE一般支持语法亮点、智能代码补充、自定义快捷键、自动格式化代码等。合理使用优秀IDE,它可以大大提高我们的开发效率。p

对于新手,Python的IDE选择,笔者推荐PyCharm的社区版本,PyCharm是由JetBrains打造的一款Python IDE,有社区版和专业版,专业版加入了一些web开发和科学计算开发的便利功能,对于普通用户,社区版足矣。

安装与配置

通过PyCharm的官方网站 https://www.jetbrains.com/pycharm/ 我们点击Download,会打开一个新的页面,选择社区版即可。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wz0ZoJ2u-1658882259402)(assets/image-20220527195937907.png)]

双击安装软件,按需调整安装位置,以及一些其他的选项(这些选项不影响基本使用),等待安装结束后打开PyCharm。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VnjvQp6R-1658882259402)(assets/image-20220527200055130.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-flugw1CM-1658882259403)(assets/image-20220527200521596.png)]

登录之后会让我们选择创建工程还是打开一个现有的代码项目。在此我们选择创建新项目。

我们修改一些项目的配置,比如我们选择修改项目名称和位置。默认的如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WAywBlVx-1658882259404)(assets/image-20220527200652722.png)]

在这个配置选项中,对于初学者我们建议不适用虚拟环境(虚拟环境我们在本书的后续会讲),记得我们说过,对于新手尽量只有一套Python环境。

我们选择自己配置Python解析器,如下图点击“…”

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FxBC6We5-1658882259405)(assets/image-20220527201009179.png)]

这个时候会弹出一个窗口,我们选择系统解析器,在右侧的解析器地址中选择我们安装的Python即可(对于新手而言一定要先安装Python,再安装Pycharm)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hGqfe3xa-1658882259405)(assets/image-20220527201235346.png)]

我们也可以选择修改我们的项目名称。之后点击create按钮即可创建项目。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X4ukS04i-1658882259406)(assets/image-20220527201418725.png)]

项目创建之初PyCharm会对我们的Python环境进行索引,以便提供更方便的开发功能。同时默认帮我们创建了一个代码,我们可以删除调,或者在上一步取消创建main.py的选项。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DSvTqQyV-1658882259413)(assets/image-20220527201630959.png)]

创建第一个脚本并运行

在右侧的项目区域我们右键选择New->Python File,给文件命名即可创建好Python文件。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DtLYnGvJ-1658882259414)(assets/image-20220527202121650.png)]

在新建的Python文件中我们简单编写打印一个字符串的代码,然后右键,选择 Run 我们的脚本名称。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tNXl9qST-1658882259415)(assets/image-20220527202423024.png)]

结果如下,在下方会有一个窗口,把我们的代码结果输出,程序如果正常执行,最后的exit code是0。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8Heq9mEf-1658882259416)(assets/image-20220527202348973.png)]

至此我们的整个开发环境已经搭建好了。PyCharm有很多的便利用法,我们在后续文章中逐步展开。

2.3 速学Python的基础知识

在正式学习Python之前,我们先准备一些基础的知识,以便我们后续章节的讲解。

这部分内容,同时又需要在后续编程中不断加深理解。

2.3.1 标识符及变量

​ 标识符是Python用于识别不同的变量、函数、对象、类、模块而起的一个名称,比如在代码开发中给某变量起名字,这个名字就是标识符,当然我们习惯成变量名(函数的标识符就称函数名,诸如此类)。

​ 标识符的命名规则是包含字母、数字、下划线“_”,且必须以一个非数字字符开始。且标识符是大小写敏感的,一定要注意区分大小写。

​ 放到我们网络运维,我们定义一个变量,用来表示接入交换机,我们就可以给他们定义成as01,我们让as01的IP地址为192.168.1.1,这个过程就是赋值。

​ 在Python中是这样表达的。

as01 = '192.168.1.1'

​ 我们用单个等号“=”来进行赋值。仔细看会发现等号左右各有一个空格,这主要是为了可读性更好,防止字符都紧紧挨在一起,显得非常拥挤。

​ Python不同于其他的语言,

​ 回到命名规则,起名不能随便起,我们刚才讲过了,必须是字母、数字、下划线的组合,且不能以数字开头。

​ 比如这几个起名就是合法的:as01 _as01 as_01。

​ 但是这个起名就是非法的:01as as-01。因为第一个以数字开头了,第二个有“-”号,不在数字、字母、下划线这三种合法组成元素之一。

​ 还有一种极端情况,单独的下划线"",也是合法的,如下:

device_name, _ = get_device_info(id=1)

_这种情况主要是因为,在代码编写过程中,函数返回两个值,但有时候我们只关心第一个,那第二个变量名就定义为下划线,下划线作为一种约定俗称不重要的变量名使用。这种极端情况大家了解即可,因为有些人的代码是这么写的,假如有天我们遇到了,我们需要读懂其中的意思。

蛇形命名法

python的变量推荐使用蛇形命名法,其规则是单词全部用小写字母,单词之间用下划线隔开,因为酷似一条弯弯曲曲的小蛇,故称之为蛇形命名法。

如下我们定义一台设备的相关信息

device_name = 'AS01'
device_ip = '192.168.1.1'
device_start_u = 10

2.3.2 保留字

​ 每门语言运行都会有一些特殊的语法,比如用if去做判断,我们不能用if来作为变量名(包括其他标识符也不行),这类我们称之为保留字(其他语言也称关键字)。Python有33个保留字,如下表。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lHKmgea9-1658882259416)(assets/image-20220527233446959.png)]

2.3.3 缩进

​ 有别于java、C等其他语言,Python是以缩进来分隔代码的逻辑块。这种缩进特别像一篇文章,每段段落是两个空格开始。用两个空格我们可以区分出段落。在Python中用于突出一块完整的代码逻辑。其他的语言是有的是通过大括号来实现的。

​ 1. 首行要顶头写,无缩进。

​ 2. 进入到某代码块,使用相同的空格缩进,标准Python风格是使用4个空格,但是个人认为层级过深可以适当用两个空格做缩进。

我们看一个例子如下:

a = 1
b = 2
if a > b:
    print('a>b')
    print('a is ',a)
else:
    print('a<=b')
    print('a is ',a)

​ 虽然我们还没触碰Python的编程核心,但是这段代码也非常易懂,且可以执行,这就是Python的魅力,接近自然语言、伪码。

通过这段代码的缩进我们可以清晰知道,先定义了变量a,b。然后进行了一个判断。如果符合条件或者不符合条件,分别进行了对应的输出。每种情况下的输出逻辑都可以通过缩进看出,打印的两行代码缩进相同,且上下连贯没有被中断,所以这两行代码是一起的。

​ 在更复杂的逻辑中,Python也是靠缩进来区分代码块。所以合适的逻辑和适当的留白(在不影响代码的情况下,多敲一个空格或者空白行),可以让我们的代码可读性更好。

​ 注意,永远不要在普通文本编辑里,在代码中使用Tab键做缩进!这种视觉上是四个空格,实际是一个制表符,是一个缩进,及其容易造成缩进混乱,程序报错。但是在PyCharm等专业Python IDE里可以使用Tab键,它们会将其Tab键的输入替换成是4个空格。

2.3.4 注释

注释主要用于对代码做一些备注,良好的注释有助于提高我们代码的可维护性和可读性。

Python的注释有两种风格:

  • “#”单行注释,可以单独写一行,也可以在Python代码后面写,但是注释内容都不能跨行

  • 三个单引号或者三个双引号的多行注释

示例:

# 定义变量a,单起一行注释。“#”与注释内容建议一个空格,记得我们的留白
a = 1
b = 2  # 定义变量b,行末的注释,建议"#"与代码末端保持两个空格,提高可读性

''' 判断ab的大小主体逻辑。 可以写很多行内容。 可以把三个单引号一同替换为三个双引号 '''
a = 1
b = 2
if a > b:
    print('a>b')
    print('a is ',a)
else:
    print('a<=b')
    print('a is ',a)

2.3.5 输出

​ 输出的方式千千万,我们这里讲的是用print函数打印出来结果,是为了给“人”看的,是stdout的一种方式。实际上写文件,写数据库也可以看做是输出。

# 定义变量并同时赋值
a = 'a'
b = 'b'
c = 'c'
# 在print默认空格隔开,以回车(换行)结束 直接
print(a,b,c) 
print(a, b, c, sep=',') # 用sep指定的字符串来隔开
print(a, b, c, end=';') # 用end指定的符号来结束,默认是回车(换行)结束

结果如下:

a b c
a,b,c
a b c;

2.4 基础数据类型

每个编程语言都有自己独特的基础数据类型,我们耳熟能详的比如整数、字符串、数组等等,其他所有的复杂对象都是从这些基础的数据结构衍生出来的。。

Python的基础数据类型包含以下几种:

  1. 数字
  2. 字符串
  3. 列表
  4. 字典
  5. 元组
  6. 集合
  7. 布尔

下面我们依次展开讲解各个数据类型

另外还有一个特殊值,空值None,类似于其他语言中的NULL,它代表是一个空对象(它不是基础数据类型,但是是一个非常简单且需要掌握的数据类型),不做过多展开。

2.4.1 数字

Python中的数字分为整数(int)、浮点数(float)、复数(complex),复数在日常中基本不会涉及,我们跳过。

整数

Python中的整数与我们的书写习惯一致。正整数、负整数、零均按我们的日常使用习惯使用即可。

整数的上下限在64位系统中可以认为无上限。而且在日常网络运维也不会出现一个内存无法保存的整数。我们无需关注这些极端情况。

a = 10
b = 0
c = -20

浮点数

浮点数即我们日常所说的小数,浮点数在Python中与我们的书写也一致。

x = 51.2
y = -11.2

同时它还支持科学计数法,大家了解即可,日常开发中很少使用。

a = 1.23e-18  # 等同于1.23*10^-18

数字的计算

python的数值支持加(+),减(-),乘(*),除(/),整除(//),取余(%),代码如下:

a = 6
b = 8
print(a + b)  # 输出结果14
print(a - b)  # 输出结果-2
print(a * b)  # 输出结果48
print(a / b)  # 输出结果0.75
print(a // b)  # 输出结果0
print(a % b)  # 输出结果6

2.4.2 字符串

​ 字符串是非常重要的一个数据类型,它是以引号括起来的一段文本。引号可以是单引号、双引号、三引号(三个单引号或者三个双引号),但是一定要成对出现,引号中间的文本内容是字符串承载的数据。字符串是严格区分大小写的。只写一对引号,内容为空,我们称之为空字符串。在Python中没有char(单个字符)这种数据类型,字符串中的字符可以是任意个,包括零个、一个或者多个

示例:

a = 'NetDevOps'
b = "NetDevOps"
c = '''this is a book about NetDevOps 这是一本关于NetDevOps的书 '''

示例中我们用单引号,双引号和三引号分别创建了三个字符串。假如我们的字符串中含有引号,这个时候该如何处理呢?

方法1:定义字符串的引号和字符串文本中的引号使用不同的引号。对于新手建议使用这种。

d = "It's a book about NetDevOps."
e = 'It is a book about "NetDevOps".'
f = '''It's a book abount "NetDevOps".'''  # 文本中既有单引号又有双引号,我们可以考虑用三引号。

方法2:使用转义符号反斜杠——“\”,转移符号后接我们要使用的引号。

d = 'It\'s a book about NetDevOps.'
e = "It is a book about \"NetDevOps\"."

关于转义

我们想用字符串表示一个回车怎么处理呢?

Python的做法是使用\n代表回车,其中\ 就是转义符号,它后面接字母n代表回车换行,字母n的表达意义发生了转换,这就是转义。反斜杠被称为转义符号,\n被称为转义字符。

下表是一些常用的转义字符(笔者根据日常运维所需进行了取舍,后续常用的列了出来)

转义字符 说明
\n 换行,将光标位置移到下一行开头。
\r 将光标位置移到本行开头
\t 横向制表符
\' 单引号
\" 双引号
\\ 斜杠符号,\本身是转义符号,我们想用它表示字符串本身时需要转义

在NetDevOps中, 我们写代码,我们定义一个设备名称的变量,就可以赋值成字符串类型的,设备的制造商可以是字符串,设备的所在房间可以是字符串,设备端口的配置可以字符串。待执行的一条命令也可以是字符串。

dev_name = 'as01'
dev_manufacture = 'HUAWEI'
dev_room = '0401'
# 我们可以适当对单词进行缩写,比如用intf代表interface。
# 但是尽量不要用int,int是一个用于将对象转换成整数的函数。
intf_config = '''interface Vlan20 ip address 192.168.137.201 255.255.255.0 '''
cmd = "show version"

字符串的常用方法

Python的字符串提供了很多便利的方法(可以简单等同于函数,初学者不必纠结名称),可以方便我们处理字符串,比如进行查找、切割、转大小写等,根据笔者的使用经验和大家简单介绍一下常用的方法。

注:函数是一个单独定义的代码块,方法是对象中的一个执行特定功能的代码块。对于初学者可以简单把函数与方法划等号,也可以简单认为方法是在对象中的函数的称谓,无需过多纠结这两个名词。本书编写会尽量严谨,但是读者在阅读过程中可以把方法和函数划等号。

以下方法直接在我们的字符串变量后写点和方法的名字即可,方法中要传入对应的参数,形式如下。

字符串变量.方法名( 参数 )

format

format方法是一个字符串格式化的方法,字符串的格式化是指,按照一定模板,向模板内传值,生成一个符合模板格式要求的字符串。Python的字符串格式化方法非常多,此处我们重点介绍format方法。

先编写一个字符串的模板,对于其中希望填充值的地方用花括号{}括起来,然后对模板字符串调用format方法,依次传入要填充的字符串,数目一定要与花括号的数目对应。

server = 'host01'
ip_addr = '192.168.1.100'
intf_desc_tpl = 'connect to {}, ip:{}'
intf_desc.format(server,ip_addr)
print(intf_desc)  # 结果是"connect to host01, ip:192.168.1.100"

这种方法还有另外一个书写方式,在定义字符串模板的时候,希望填充的值用花括号括起来,同时花括号内填这个填充值的参数名称,然后对模板字符串调用format方法,为花括号内的参数进行赋值。此方法可读性非常好,但是写起来会比上面的方法多写一些内容,初学者可以在看到函数部分后再回来看看此部分示例。

server = 'host01'
ip_addr = '192.168.1.100'
intf_desc_tpl = 'connect to {SERVER}, ip:{SERVER_IP}'
intf_desc.format(SERVER=server, SERVER_IP=ip_addr)
print(intf_desc)  # 结果是"connect to host01, ip:192.168.1.100"
find

find方法用户发现字符串中是否包含子串,如果发现子串返回子串首字母出现的位置索引值(Python中的索引从零开始),如果未发现返回-1

我们可以通过比较find的结果与0比较,小于零代表未发现,大于等于零代表发现了子串。

intf_show = 'Eth1/1 is up'
up_index = intf_show.find('up')
print(up_index)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-chIy8dyw-1658882259417)(assets/image-20220528171136866.png)]

最终输出结果是10。

如果我们改为find('down')则输出结果是-1。

我们在NetDevOps开发中可以用于判断回显是否包含关键字。

startswth

startswith方法用于判断是否以给定的字符串开始的,返回是真(True)或假(False)。

intf_show = 'Ethernet1/1 is up'
is_interface_line = intf_show.startswith('Ethernet')
print(is_interface_line)  # 输出结果是Ture
endswith

endswith方法用于判断是否以给定的字符串结束的,返回是真(True)或假(False)。

intf_show = 'Ethernet1/1 is up'
interface_up = intf_show.endswith('up')
print(interface_up)

find 、startswith、endswith主要用于在文本中发现是否有关键字,通过关键字我们可以判断一些状态,或者确定此行中是否有我们要提取的信息等等。

split

split方法用于切割字符串,返回的结果是列表(list,后续会展开讲)。

默认是用空白符来进行切割,空白符泛指没有显示却又占位置的符号,比如空格、制表符、换行。

intf_show = 'Ethernet1/1 is up'
result = intf_show.split()
print(result)  # 结果是['Ethernet1/1', 'is', 'up']

通过这种方式,我们就可以获取包含一些字段信息的列表,再通过列表的访问机制就可以提取出端口名称和端口状态了,这个我们在列表中讲解使用方法。

我们也可以用指定的字符去切割,比如我们使用is去切割。

intf_show = 'Ethernet1/1 is up'
result = intf_show.split('is')
print(result)  # 结果是['Ethernet1/1 ', ' up']

这样直接获取了端口和状态。

strip

strip方法用去去除字符串左右的指定字符串,不修改原来的字符串(因为字符串是不可修改的类型),返回一个新的字符串。

默认是去除左右的所有空白符。

我们也可以在方法内直接传入要去除的字符串,同时strip还有两个变种方法lstrip和rstrip,可以只去除左侧或者右侧的指定字符串,单这些NetDevOps脚本编写很少涉及,故不演示。

intf_show = ' Ethernet1/1 is up '
result = intf_show.strip()
print(result)  # 结果是"Ethernet1/1 is up"
splitlines

splitlines方法用于将一大段文本按行切割,返回一个列表。行的结束符号Python会帮我们自动判断,对于初学者无需关注。

intf_config = '''interface Vlan20 ip address 192.168.137.201 255.255.255.0 '''
configs = intf_config.splitlines()
# 结果是['interface Vlan20', ' ip address 192.168.137.201 255.255.255.0']
print(configs) 

replace

replace方法用于将某字符串替换为我们指定的字符串。它有两个参数,第一个想要替换的字符串,第二个是要去替换之前那个字符串的字符串。一个是old,一个是new。

intf_name = 'Eth1/1'
full_intf_name = intf_name.replace('Eth', 'Ethernet')
print(full_intf_name)  # 结果是"Ethernet1/1"

由于字符串是不可变的数据类型,所以原有的变量intf_name指向的字符串不会被修改,我们需要将函数返回的值赋值给一个变量,可以是新定义一个变量,也可以用原有的变量。

intf_name = 'Eth1/1'
intf_name = intf_name.replace('Eth', 'Ethernet')
print(intf_name)  # 结果是"Ethernet1/1"

字符串的拼接

字符串通过加号可以实现字符串的拼接,生成一个新的字符串。

server = 'host01'
ip_addr = '192.168.1.100'
intf_desc = 'connect to ' + server + ', ip:' + ip_addr
print(intf_desc)  # 结果是"connect to host01, ip:192.168.1.100"

对于初学者而言,多用于按照一定格式拼接多个字符串。如果是这种情况,更推荐字符串格式化这种方式。

以上几个字符串的相关使用,结合判断、循环,我们就可以写出一些复杂的逻辑,对网络配置进行解析,提取出我们想要的信息。这个思路,我们在掌握了判断循环后再去编写代码实现。

2.4.3 列表

列表(list)有点类似于其他编程语言中的数组,它是一组有序的数据,每个成员都有一个索引值,索引值从零开始依次递增。

这组有序的数据类型可以是Python的基础数据类型,也可以是复杂的对象。Python的列表最大的不同在于成员的数据类型可以不一。

它的创建方式比比较简单,用中括号(方括号)创建,列表中的成员用逗号隔开。

intfs = ['Eth1/1', 'Eth1/2', 'Eth1/3', 'Eth1/4']
dev_info = ['192.168.1.1', 'as01', 'huawei', 'ce6800', 48, ['beijing', 'dc01']]

如上,第一个我们用于定义一组端口,都是字符串的成员。这是在日常NetDevOps开发中比较常见的一种形式,成员都是相同的类型,代表一类事物。

第二个列表我们稍微改了一下,成员既有字符串,又有数字,还有列表。这种是典型用多个维度的成员组成的列表,用于描述一个事物。deb_info这个变量中我们通过成员描述了它的IP地址、设备名称、厂商、系列、端口数记忆所属数据中心。

这是笔者总结的两种组织列表的场景:同一纬度的成员描述一系列事物,不同维度的成员描述一个事物。

访问成员

列表是有序的,通过它对应的排序(从零开始),称之为索引更为准确,通过方括号,我们可以访问到这个成员。

intfs = ['Eth1/1', 'Eth1/2', 'Eth1/3', 'Eth1/4']
intf = intfs[0]  # 此处千万不要用int去命名端口变量,会与int函数冲突
print(intf)  # 此处输出'Eth1/1'

intf = intfs[2]
print(intf)  # 此处输出'Eth1/3'

Python的列表访问成员还有一个非常有意思的,异于其他语言的特性,负索引。

我们可以输入负数,代表从倒数第N个成员。负索引最后一个成员开始排序,最后一个的索引是-1。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4HNRXoKW-1658882259418)(assets/image-20220529115904356.png)]

intfs = ['Eth1/1', 'Eth1/2', 'Eth1/3', 'Eth1/4']
intf = intfs[-1]  # 此处千万不要用int去命名端口变量,会与int函数冲突
print(intf)  # 此处输出'Eth1/4'

无论是正索引还是负索引,我们访问都不能越界,如上图,我们不能访问索引为4或者-5的成员,因为它不存在,Python都会报错。

计算列表长度

我们想获取列表长度的时候可以直接调用一个Python的内置函数len,然后传入列表。

intfs = ['Eth1/1', 'Eth1/2', 'Eth1/3', 'Eth1/4']
intf_sum = len(intfs)
print(intf_sum)  # 此处输出4
print(intfs[intf_sum - 1])  # 此处输出'Eth1/4'

我们访问列表的最后一个成员的时候,可以使用长度减一的索引来访问,但是不建议,Python的风格(我们称之为pythonic),一般使用负索引。

追加成员

列表是一个可变的数据类型,在创建之后,我们还可以继续在列表内追加成员,使用列表的append方法即可,一次只能追加一个成员,可以一直追加。

intfs = ['Eth1/1', 'Eth1/2', 'Eth1/3', 'Eth1/4']
intfs.append('Eth1/4')
# 结果是['Eth1/1', 'Eth1/2', 'Eth1/3', 'Eth1/4', 'Eth1/4']
print(intfs)

合并列表

两个列表合并有两种方式:

  1. 使用加法,两个列表合并成一个新的列表,原有的两个列表没有任何变化
intfs_part1 = ['Eth1/1', 'Eth1/2', 'Eth1/3', 'Eth1/4']
intfs_part2 = ['Eth1/5', 'Eth1/6', 'Eth1/7', 'Eth1/8']
intfs = intfs_part1 + intfs_part2

print(intfs_part1)  # 结果是['Eth1/1', 'Eth1/2', 'Eth1/3', 'Eth1/4', 'Eth1/4']
print(intfs_part2)  # 结果是['Eth1/5', 'Eth1/6', 'Eth1/7', 'Eth1/8']
print(intfs)  # 结果是['Eth1/1', 'Eth1/2', 'Eth1/3', 'Eth1/4', 'Eth1/5', 'Eth1/6', 'Eth1/7', 'Eth1/8']
  1. 使用extend方法,将另外一个列表B批量追加到调用方法的列表A之后,只有调用方法的列表A发生变化,有了新的成员。
intfs_part1 = ['Eth1/1', 'Eth1/2', 'Eth1/3', 'Eth1/4']
intfs_part2 = ['Eth1/5', 'Eth1/6', 'Eth1/7', 'Eth1/8']
intfs_part1.extend(intfs_part2)

print(intfs_part1)  # 结果是['Eth1/1', 'Eth1/2', 'Eth1/3', 'Eth1/4', 'Eth1/5', 'Eth1/6', 'Eth1/7', 'Eth1/8']
print(intfs_part2)  # 结果是['Eth1/5', 'Eth1/6', 'Eth1/7', 'Eth1/8']

切片

切片如同这个词的字面意思,是指从一个已有的列表中切取一“片”,这一“片”也就是一个子列表,切片的方式很灵活,它的规则如下。

[start_index:stop_index:step]

start_index 是指起始索引值,可以不写,默认是列表头。

stop_index 是指结束索引值,可以不写,默认取到列表尾。

step 是指步长,是取成员索引的间隔。(可以为负数,达到反向切片效果,了解即可)

通过以上的方式,则会返回一个新的列表。

切片过程中如果指定了stop_index,则只能取到stop_index 前一个符合步长的索引值。类似于数学中的开区间,无法取值到stop_index。

intfs = ['Eth1/1', 'Eth1/2', 'Eth1/3', 'Eth1/4']
sub_intfs = intfs[:3]
# 只能取值到3前面的索引也就是到索引2,结果是['Eth1/1', 'Eth1/2', 'Eth1/3']
print(sub_intfs)

sub_intfs = intfs[1:3]
# start_index是可以取到的,但是stop_index是取不到的,结果是['Eth1/2', 'Eth1/3']
print(sub_intfs)


sub_intfs = intfs[::2]
# 旗帜索引可以不填写,默认从头取到尾,间隔为2,结果是['Eth1/1', 'Eth1/3']
print(sub_intfs)

2.4.4 字典

字典(dcit)是一组通过关键字进行索引的、有序的、不重复的、可变的数据集合,可以简单理解为一组键值对且键不可重复(key是关键字,value是对应的值,二者是一个字典的成员)。

注:自Python3.6开始,字典变为了有序的数据集合。

字典的创建方式很简单,通过花括号{}来创建一个字典,成员(键值对)间用逗号隔开,键与值之间用冒号隔开。形如:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hKja8MxE-1658882259419)(assets/image-20220529161320396.png)]

key可以是可以哈希的对象即可,对于初学者而言,认为只有字符串和数字可以作为key,实际在使用中,我们用字符串做key的更常见。

value可以是任何python的数据类型,包含了基础的数据类型,也包含复杂的数据对象。

dev_info = { 
        'ip': '192.168.1.1', 'name': 'as01', 'manufacture': 'huawei', 'series': 'ce6800', 'ports_sum': 48}

为了提高可读性冒号的前后各一个空格,逗号后面一个空格,适当留白。当字典的成员(键值对)比较多的时候,我们可以适换行。

dev_info = { 
        'ip': '192.168.1.1',
            
        标签: 2u1s9电力变送器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台