【自动化运维新手村】Python基础-3

摘要

首先说明,以下几类读者请自行对号入座:

  • 对CMDB很了解但对于Python还没有上手的读者,强烈建议阅读前面几篇;
  • 对Python了解较少只能写出简单脚本的读者,强烈建议阅读此篇;
  • 已经可以熟练写出Python脚本,但对CMDB不是很了解的读者,建议阅读此篇;
  • 即了解Python,又了解CMDB的读者,可以出门左转,看下一篇。

上一节我带领读者们在阅读源码前进行了一系列思考,培养了一下大家的编程思想,并且紧接着阅读了CMDB v1.0.py的部分源码,那今天我们开篇就不再过多赘述,接上一节直接上干货。

上干货
添加资产信息

在初始化好地域信息之后,我们首先要做的就是添加资产信息了

  1. 按照我们上节课所讲,先要思考一下实现这个功能有哪些地方需要注意:
  • 添加什么样的信息?
  • 将信息添加到哪里,如何定位到要添加的路径?
  • 如何把更新的数据持久化?
  1. 这里我先依次给大家解答一下:
  • 因为我们数据源是以JSON的格式存储在文本文件中,所以必须保证我们添加的信息也是json格式
  • JSON格式的数据源对应的是Python中的字典,所以字典是可以根据键进行索引的,那么我们可以通过多个键的排列去依次进行查找定位字典的位置,比如可以是key1/key2/key3的形式
  • 数据的持久化依然选择通过JSON的方式将数据持久化到文本文件中
  1. 我们已经基本有了实现添加资产信息的思路,现在要做的就是将思路更进一步细化到可实现的伪代码:
  • 我们需要定义一个add()函数来实现这个功能,并且这个函数需要接收两个参数,分别是要添加的信息和信息要更新到的指定路径,那么我们的函数签名应该是add(attrs, path)

这里的attrs是属性attributes的缩写,在写代码的过程中希望大家培养为变量起一个合适规范的名字的好习惯,初学者尽量避免使用拼音来给变量或函数命名,应该使用能表明变量含义的命名方式。

  • 我们传入的attrs必须是一个json格式的字符串,传入的path必须是一个通过/分隔的字符串
  • 通过path去按层级定位数据源中的指定位置,通过字典的赋值将attrs添加到数据源中
  • 通过json.loadjson.dump做数据持久化
  1. 接下来就是需要写出一份能实现上述功能的伪代码,如下:
def add(path, attrs):
    # 判断attrs的合法性
    if attrs is valid
    # 将attrs解析成Python类型
    attrs = parse_attrs()
    # 从文本文件中读取数据源
    data = read_file()
    # 分割path路径
    seg = path.split()
    # 根据路径定位数据源的指定位置
    target_path = position_data()
    # 将attrs添加到指定路径
    data[target_path] = attrs
    # 将数据保存到文本文件
    write_file(data)
    # 打印数据源
    print(data)
  1. 那么最终添加资产信息的源代码如下:
def add(path, attrs=None):
    if attrs is None:  # 判断attrs的合法性
        print("add operation must have attrs arg")
        return
    try:  # 将attrs解析成Python类型
        attrs = json.loads(attrs)
    except Exception:
        print("input attribute is an invalid json string")
        return
    with open("data.json", "r+") as f:  # 从文本文件中读取数据源
        data = json.load(f)
    path_seg = path.split("/")  # 分割path路径
    target_path = data
    for idx, seg in enumerate(path_seg[1:]):  # 根据路径定位数据源的指定位置
        if idx == len(path_seg)-2:
            if seg in target_path:
                print("%s already exists in %s, please use update operation" %
                      (seg, path))
                return
            target_path[seg] = attrs  # 将attrs添加到指定路径
            break
        target_path = target_path[seg]
    with open("data.json", "w+") as f:  # 将数据保存到文本文件
        data = json.dump(f, indent=2)
    print(json.dumps(data, indent=2))  # 打印数据源

很多读者可能第五步有点儿懵,有种刚学会1+1=2就跳到高等代数微积分的感觉,但其实把上述代码的每一部分单独拿出来还都是比较好理解的。

  • 判断attrs的合法性并将attrs解析成Python类型
if attrs is None:
    print("add operation must have attrs arg")
    return
try:  # 将attrs解析成Python类型
    attrs = json.loads(attrs)
except Exception:
	print("input attribute is an invalid json string")
    return

这一步在解析参数的同时也是在判断attrs的合法性,因为我们要求输入的attrs参数不能为None且必须是一个json类型的字符串,那么我们理论上就可以通过json.loads将其进行解析,如果解析失败那么就说明该参数不是合法的json,就需要退出该函数;如果attrs为合法的json,那么我们就可以将其解析为Python中的数据类型应用于下面的代码中。关于try...except的详细讲解我们会在番外篇中提到。

Tips Python中None的判断
在Python中判断一个变量是否是None的写法不是 if var == None而是if var is None,这里我们推荐大家使用第二种方法,具体关于等于判断的区别我们会在番外篇中提到。

  • 从文件中读取数据源

这一步就是运用我们上节课所讲的内容,此处不再赘述

  • 分割path路径
path_seg = path.split("/")[1:]  # 分割path路径

这里就是运用到Python中对字符串的操作,str.split()用于分割字符串,通过传入分隔符,可以将字符串按分隔符切分成数组返回,所以这里的path_seg就是一个路径的数组,我们只需要根据这个数组,一层一层的定位到数据源的指定位置即可。这里同时运用到了数组切片的原理,因为我们的路径假设为/region/idc/switch的格式,所以按照/切割后,路径数组为["", "region", "idc", "switch"],第一个元素为空字符串,所以通过path_seg[1:]的方式只取第二个到最后一个的路径元素。

  • 根据路径定位数据源的指定位置并将attrs添加到指定路径
target_path = data
for idx, seg in enumerate(path_seg):  # 根据路径定位数据源的指定位置
    if idx == len(path_seg)-1:
        if seg in target_path:
            print("%s already exists in %s, please use update operation" % (seg, path))
            return
        target_path[seg] = attrs  # 将attrs添加到指定路径
 		break
    target_path = target_path[seg]

这一块可能是一个难点,需要大家对循环的有一定的理解,首先我们先定义一个目标路径的变量target_path,它一开始等于整个data的最外层,在后面的循环中它会不断的更新;在循环语句中用到了一个Python的语法糖enumerate(),通过传入一个可迭代对象(此处为我们的路径数组),可以对于下标和内容同时进行循环遍历,所以for idx, seg in enumerate(path_seg[1:])这里的idxseg分别表示路径数组中某一段路径的下标和内容。

这里向大家说明一下循环语句的本质原理,循环其实就是有一个可以重复的操作不停的在执行,当达到某一个边界条件时就退出循环,所以一般的循环语句都会存在边界条件,如果没有边界条件我们就称其为死循环。

我们上述代码块的边界条件就是遍历完整个路径数组,在每次遍历的时候对data一层一层的取值并返回,直到我们遍历到路径数组的最后一个元素(也就是其下标idx == len(path_seg)-1,之所以 -1是因为下标是从0开始的,所以数组的长度会比最后一个下标大1),这时候我们判断这个路径元素是否存在于当前位置,如果存在则说明不可以进行添加,直接通过return退出函数,如果不存在则我们通过字典赋值的方式将attrs添加到该位置,并通过break结束循环。

Tips: break与continue

对于刚接触编程的读者可能不太清楚break与continue的区别,break可以理解为直接退出这个循环,不管这个循环有没有到达边界条件;而continue则是跳过此次循环,如果还没有达到边界条件则继续进行下一次循环。如下代码

for i in [1, 2, 3]:
    if i == 2:
        continue
    print(i)
 # 输出 1 3   
 for i in [1, 2, 3]:
    if i == 2:
        break
    print(i)  
 # 输出 1

上面的描述可能会有些晦涩难懂,下面我们通过Debug的方式看看每次循环时候的变量值就会清晰很多。

假设我们已经执行了语句python cmdb-v1.0.py init beijing,这时我们的数据源如下:

{
  "beijing": {
    "idc": "beijing",
    "switch": {},
    "router": {}
  }
}

那么这时候我们执行

python cmdb-v1.0.py add /beijing/switch/10.0.0.1 '{\"ip\": \"10.0.0.1\", \"role\": \"asw\"}'进行调试

/beijing/switch/10.0.0.1就是我们要指定的路径

'{\"ip\": \"10.0.0.1\", \"role\": \"asw\"}'就是我们要添加的信息,这里的信息是一个json格式的字符串

  1. 在还没有开始循环前的各变量值如下

在这里插入图片描述

此时的target_path = {"beijing": {"idc": "beijing", "switch": {}, "router": {}}}

  1. 第一次循环结束后各变量值如下

在这里插入图片描述

此时的seg = "beijing" target_path = {"idc": "beijing", "switch": {}, "router": {}}

  1. 第二次循环结束后各变量值如下

在这里插入图片描述

此时的seg = "switch" target_path = {"idc": "beijing", "switch": {}, "router": {}}

  1. 当最后一次循环时

在这里插入图片描述

此时seg = "10.0.0.1" targe_path = {}idcpath_seg长度相等,且seg原先不存在,所以可以将attrs更新到target_path上去。

根据上面一步一步的调试,我们可以清晰的看到每次循环中segtarget_path的变化,其实target_path是一个指针,它最开始指向字典的最外层,随着一次次的循环,它根据seg层层递进,直到指向目标路径,这时候将attrs添加上去就完成了最终操作。

最后的数据如下:

{
  "beijing": {
    "idc": "beijing",
    "switch": {
      "10.0.0.1": {
        "ip": "10.0.0.1",
        "role": "asw"
      }
    },
    "router": {}
  }
}

这一节我们就先讲到这里,这次我们主要讲解了添加资产信息的详细源码,看起来虽然代码不长,但实际上需要注意的思想和需要新手朋友们注意的知识点还是有很多,希望大家可以自己亲自去调试运行一下,仔细体会一下每一次循环过程中变量的变化。一起期待我们下一节的继续讲解。

篇后语

其实这一节除了代码细节的讲解之外,我们在阅读源码前的五个步骤是更为关键的部分。根据我上面五个步骤的讲解,大家可以再次发现,在编程的过程中,前一到四步可以说是最终代码成型的地基,并且上面的四个步骤在进行的过程中并不需要我们真正掌握哪一门具体的编程语言,而是需要我们充分利用编程的思想,将要解决的问题逐步拆解;第五步才是真正需要利用代码实现,而且我们选择的Python是较为容易上手的语言,这也是对刚接触编程的朋友来说比较友好的,最后希望大家能够在跟随我一步一步学习的过程中培养起良好的编程思想。


欢迎大家添加我的个人公众号【Python玩转自动化运维】加入读者交流群,获取更多干货内容
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值