【自动化运维新手村】Python基础-3_EthanYue1024的博客-程序员资料

技术标签: python  运维  Python玩转自动化运维  自动化  

摘要

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

  • 对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玩转自动化运维】加入读者交流群,获取更多干货内容
在这里插入图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_40489165/article/details/121781756

智能推荐

Java开源模板引擎_wx5701619的博客-程序员资料_java 模板引擎原理

Velocity Velocity是一个基于java的模板引擎(template engine)。它允许任何人仅仅简单的使用模板语言(template language)来引用由java代码定义的对象。 当Velocity应用于web开发时,界面设计人员可以和java程序开发人员同步开发一个遵循MVC架构的web站点,也就是说,页面设计人员可以只关注页面的显示效果,而由java程序

Unix/Linux下几个最致命的命令_虎皮猫大人王的博客-程序员资料

本文主要参考了以下原文:http://www.linuxpromagazine.com/Online/News/Seven-Deadliest-Linux-Commandshttp://ubuntuforums.org/announcement.php?f=326大多数时候程序员性情温和,神情淡定。但是会有例外,当他们因为加班加点过度劳累,在意识脆弱、头脑短路、麻痹大意时执行了

R语言应用实战-聚类分析以及k-means的优缺点_普通网友的博客-程序员资料_r型聚类分析的优缺点

一.聚类概念聚类分析cluster Analysis)是研究物以类聚的现代统计方法。在过去是依靠经验和专业知识做定性分析处理,很少利用数学方法多元统计分析逐渐被引进数值分类,形成聚类分析的分支。以下是我为大家准备的几个精品专栏,喜欢的小伙伴可自行订阅,你的支持就是我不断更新的动力哟!MATLAB-30天带你从入门到精通MATLAB深入理解高级教程(附源码)tableau可视化数据分析高级教程思想:认为所研究的样本或指标(变量)之间存在着不同程度的相似性(亲疏关系)。于是根据一批样本的

Centos 8 | 网络_enobear的博客-程序员资料

网络配置说明新安装的 Centos 8 默认网卡是没有启动的。默认只能通过NetworkManager.service进行网络配置。没有传统的network.service,但依然支持。NMNM服务是管理和监控网络设置的守护进程,它是一个动态的,事件驱动的网络管理服务。命令# 重启NMsystemctl restart NetworkManager# 查看网络连接nmcli c# 查看网卡信息nmcli d# 查看ipnmcli# 重新加载网络nmcli c relo

create-react-app 创建页面打开没有显示_Ordinary_hermit的博客-程序员资料

react创建网页显示空白,可能会遇到的问题

不是太细的java自学笔记4(p366-p388)(java异常,自定义异常,throw,throws)_NoN小旻的博客-程序员资料

59.异常抓抛模型:抛出:出现异常,会生成一个对应异常类的对象。并将此对象抛出。一旦抛出异常之后,其后代码不再执行。抓:异常处理方式,第一种try-catch-finally,第二种fhrowstry-catch-finally的使用try{ //可能出现的异常 }catch(异常类型1 变量名1){ //异常处理方式1 }catch(异常类型2 变量名2){ //异常处理方式2 } ... finally{//一定会执行的代码}//案例...

随便推点

统一诊断服务(UDS)_晓翔仔的博客-程序员资料_uds 库

统一诊断服务(Unified Diagnostic Services),简称UDS。是ISO 15765和ISO 14229定义的一种汽车通用诊断协议

考研复试408问题(还在更新)_聚精会神搞学习的博客-程序员资料

面试问题之编程语言:c++的特点是什么?封装,继承,多态,支持面向对象和面向过程的开发c++的异常处理机制?抛出异常和捕捉异常进行处理。c++和c,java的区别?c是纯过程,c++是对象加过程,java是存面向对象纯虚函数?被virtual修饰的成员函数,再基类不能实现,而他的实现放到派生类中实现什么是内存泄漏?申请了一块内存空间,使用完毕后没有释放掉计算机网络:TCP/IP分层五层模型:物理层,数据链路层,网络层,运输层,应用层七层模型:物理层,数据链路层,网

mysql中like % %模糊查询_斜阳雨陌的博客-程序员资料_like %

1,%:表示任意0个或多个字符。可匹配任意类型和长度的字符,有些情况下若是中文,请使用两个百分号(%%)表示。 比如 SELECT * FROM [user] WHERE u_name LIKE '%三%' 将会把u_name为“张三”,“张猫三”、“三脚猫”,“唐三藏”等等有“三”的记录全找出来。 另外,如果需要找出u_name中既有“三”又有“猫”的记录,请使用and条件 SELECT * F...

LIKE的用法_Serendipity的人的博客-程序员资料_like函数的用法

我们来谈谈关于like运算符的理解:下面是like的语法,以后使用到like运算符的都必须根据这个语法使用LIKE运算符是用来匹配通配符指定模式的文本值。如果搜索表达式与模式表达式匹配,LIKE 运算符将返回真(true),也就是 1。下划线“_”百分号“%”百分号(%)代表零个、一个或多个数字或字符。下划线(_)代表一个单一的数字或字符。这些符号可以被组合使用。下面举例下划线“_”的用法:下划线代表单个字符。以下查找StudentNumber中第二个字符为.

java web方向专业术语_Eikis的博客-程序员资料

1、TomcatTomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。(是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目)。对于一个初学者来说,可以这样认为,当在一台机器上配置好Apache 服务器,可

推荐文章

热门文章

相关标签