Python运维开发基础09-函数基础【转】
上节作业回顾
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# author:Mr.chen
# 实现简单的shell命令sed的替换功能 import sys,os para_argv = sys.argv
Tag = True #判断参数的传递
if para_argv[1] == "-i" and len(para_argv) == 4 :
if type(para_argv[2]) == str :
if os.path.isfile(para_argv[3]) and os.popen("whoami").read().strip() == "root" :
#对过滤条件的字符串进行分割,请注意此处写法,可以降低判断嵌套深度
List = []
if "#" in para_argv[2] and para_argv[2].count("#") == 3 :
List = para_argv[2].split("#")
elif "@" in para_argv[2] and para_argv[2].count("@") == 3:
List = para_argv[2].split("@")
elif "/" in para_argv[2] and para_argv[2].count("/") == 3:
List = para_argv[2].split("/")
else :
print ("请用@或/或#分隔过滤条件,分隔符只能是3个")
#对分割以后的列表进行判断
if len(List) != 0 and List[0].strip() == "s" :
if List[3].strip() != "" and List[3] != "g" :
print ("{}是个无法识别的字符".format(List[3]))
else :
with open(para_argv[3],"r") as f , open(para_argv[3]+".bak","w") as f_new :
for line in f :
if List[1] in line and List[3].strip() == "" :
line = line.replace(List[1],List[2],1)
else :
line = line.replace(List[1],List[2],-1)
f_new.write(line)
os.system("/bin/mv "+para_argv[3]+".bak "+para_argv[3])
print ("命令执行成功!")
elif len(List) != 0 and List[0].strip().count("s") == 1 and List[0].strip().endswith("s") :
if List[0].strip().count(",") == 1 :
if List[0].strip().split(",")[0].isdigit() and List[0].strip().split(",")[1][:-1].isdigit() :
num_one = int(List[0].strip().split(",")[0])
num_two = int(List[0].strip().split(",")[1][:-1])
with open(para_argv[3],"r") as f , open(para_argv[3]+".bak","w") as f_new :
for index,line in enumerate(f) :
if num_one <= index+1 <= num_two :
if List[1] in line and List[3].strip() == "" :
line = line.replace(List[1],List[2],1)
elif List[1] in line and List[3].strip() == "g" :
line = line.replace(List[1],List[2],-1)
f_new.write(line)
os.system("/bin/mv "+para_argv[3]+".bak "+para_argv[3])
print ("命令执行成功!")
else :
print ("无法识别的字符{}".format(List[0].strip()))
else :
if List[0].strip()[:-1].isdigit() :
num = int(List[0].strip()[:-1])
with open(para_argv[3],"r") as f , open(para_argv[3]+".bak","w") as f_new :
for index,line in enumerate(f) :
if index+1 == num :
if List[1] in line and List[3].strip() == "" :
line = line.replace(List[1],List[2],1)
elif List[1] in line and List[3].strip() == "g" :
line = line.replace(List[1],List[2],-1)
f_new.write(line)
os.system("/bin/mv "+para_argv[3]+".bak "+para_argv[3])
print ("命令执行成功!")
else :
print ("{}不是一组数字,无法识别".format(List[0].strip()[:-1]))
elif os.path.isfile(para_argv[3]) and os.access(para_argv[3],os.R_OK) and os.access(para_argv[3],os.W_OK):
print ("为了节约时间,只对用户是root的情况做出判断。")
else :
print ("error!{}不是一个有效的文件或者文件的读写权限有问题。".format(para_argv[3]))
else :
print ("error! 格式为:{} -i '{过滤条件}' filename".format(para_argv[0]))
elif type(para_argv[1]) == str and len(para_argv) == 3 :
print ("为了节约时间,只实现了有参数-i的对文件的替换操作")
else :
print ("您输入的参数有误!")
print ("格式:{} [-i] '过滤条件' filename".format(para_argv[0]))
架构导引
一个故事引发的深思:
假如有一天老板让你写一个监控程序,监控服务器的系统状况,当cpu/memory/disk等指标的使用量超过阈值即发邮件报警,你掏空了所有的知识量,写入了以下代码。
while True :
if cpu利用率 > 90% :
连接邮件服务器
发送邮件
关闭连接 if 硬盘使用空间 > 90% :
连接邮件服务器
发送邮件
关闭连接 if 内存占用 > 80% :
连接邮件服务器
发送邮件
关闭连接
上面的代码实现了功能,但即使是邻家女孩也看出了端倪,少女亲切的摸了下你家儿子的脸蛋,说,你这个重复代码太多了,每次报警都要重写一段发邮件的代码,太low了,这样干存在2个问题:
- [x] : 代码重复过多,一个劲的copy and paste 不符合高端程序员的气质
- [x] : 如果日后需要修改发邮件的这段代码,比如加入群发功能,那你就需要在所有用到这段代码的地方都修改一遍
你觉得少女说的对,你也不想写重复代码,但又不知道怎么做,少女好像看出了你的心思,此时她抱起你儿子,笑着说,其实很简单,只需要把重复的代码提取出来,放在一个公共的地方,起个名字,以后谁想用这段代码,就通过这个调用就行了,如下:
def 发送邮件(内存)
连接邮箱服务器
发送邮件
关闭连接 while True :
if cpu利用率 > 90% :
发送邮件(“CPU报警”) if 硬盘使用空间 > 90% :
发送邮件(“硬盘报警”) if 内存占用 > 80% :
发送邮件(“内存报警”)
你看着少女写的代码,气势恢宏,磅礴大气,代码里透露着一股内敛的傲气,心想,这个人真是不一般,突然对她的背景更感兴趣了,问她,这些花式玩法你都是怎么知道的?她亲了一口你儿子,捋了捋不存在的胡子,淡淡的讲,“老娘,年少时,师从京西航天桥Mr.chen ”.
一,函数
1.1 介绍
在过去的十年间,大家广为熟知的编程方法无非两种:面向对象和面向过程,其实,无论哪种,都是一种编程的规范或者是如何编程的方法论。而如今,一种更为古老的编程方式:函数式编程,以其不保存状态,不修改变量等特性重新进入人们的视野。
- [x] : 面向对象
- [x] : 面向过程
- [x] : 函数式编程
这三种其实都是在叫你们如何来编程,也就是说他们仅仅只是编程的方法论。如果我们将这三种比作武林门派:
面向对象====>华山派==(秘籍)==>类==(关键字)==>class
面向过程====>少林派==(秘籍)==>过程===(关键字)==>def
函数式编程====>逍遥派==(秘籍)==>函数==(关键字)==>def
下面我们就来依次了解这些传统的编程理念,让我们从基本的函数概念开始。
1.2 定义
初中数学函数定义:一般的,在一个变化过程中,如果有两个变量x和y,并且对于x的每一个确定的值,y都有唯一确定的值与其对应,那么我们就把x称为自变量,把y称为因变量,y是x的函数。自变量x的取值范围叫做这个函数的定义域。
编程语言中函数定义:
函数是逻辑结构化和过程化的一种编程方法。
#Python中函数定义方法: def test(x) :
“The function definitions”
x += 1
return x def :定义函数的关键字
test:函数名
():内可定义形参
“” :文档描述(非必要,但是强烈建议为你的函数添加描述信息)
x+=1:泛指代码块或程序处理逻辑
return:定义返回值
1.3 为何使用函数
没有函数的编程只是在写逻辑(功能),想脱离函数,重用你的逻辑,唯一的方法就是拷贝。
例:
#假设我们编写好了一个逻辑(功能),用来以追加的方式写日志:
with open("a.txt","ab") as f :
f.write("end action") #现在有三个函数,每个函数在处理完自己的逻辑后,都需要使用上面这个逻辑,那么唯一的方法就是,拷贝三次这段逻辑 def test1() :
print ("test1 starting action...")
with open("a.txt","ab") as f:
f.write("end action") def test2() :
print ("test2 starting action...")
with open("a.txt","ab") as f :
f.write("end action") def test3():
print ("test3 starting action....")
with open("a.txt","ab") as f:
f.write("end action")
那么我们假设有大于N个函数都需要使用这段逻辑,你可以拷贝N次吗?
优化:
def logger() :
with open("a.txt","a+") as f :
f.write("end action\n") def test1() :
print ("in the test1")
logger() def test2() :
print ("in the test2")
logger() def test3() :
print ("in the test3")
logger()
1.4 函数和过程
过程定义:
过程就是简单特殊没有返回值的函数
这么看来我们在讨论为何使用函数的时候引入的函数,都没有返回值,没有返回值就是过程,没错,但是在Python中有比较神奇的事情
#代码演示: def test01() :
msg = "hello The little green frog"
print (msg) def test02() :
msg = "hello WuDaLang"
print (msg)
return msg t1 = test01()
t2 = test02() print ("from test01 return is {} ".format(t1))
print ("from test02 return is {} ".format(t2)) #输出结果 hello The little green frog
hello WuDaLang
from test01 return is None
from test02 return is hello WuDaLang
总结:
当一个函数/过程没有使用return显示的定义返回值时,Python解释器会隐式的返回None,所以在Python中即便是过程也可以算作函数。
1.5 函数返回值
在Python里调用函数是可以有返回值的。
#代码演示: def test01() :
pass def test02() :
return 0 def test03() :
return 0,10,"hello",["Mr.chen","yunjisuan"],{"WuDaLang":"lb"} t1 = test01()
t2 = test02()
t3 = test03() print ("from test01 return is {} {}".format(type(t1),t1))
print ("from test01 return is {} {}".format(type(t2),t2))
print ("from test01 return is {} {}".format(type(t3),t3)) #输出结果 from test01 return is <class 'NoneType'> None
from test01 return is <class 'int'> 0
from test01 return is <class 'tuple'> (0, 10, 'hello', ['Mr.chen', 'yunjisuan'], {'WuDaLang': 'lb'})
- 我们发现当我们调用这个函数,如果函数里有return这个东西,后边跟着的东西就作为函数的结果返回到调用的地方,同时这个返回值可以赋值给变量。
- 那么函数执行了return后,函数里其他的代码还能执行吗?同学们继续往下看
#代码演示: def test1() :
print ("in the test1")
return 0
print ("我还能出现吗?") #这句能正常输出吗? x = test1() #输出结果 [root@localhost scripts]# python3 test.py
in the test1
- 我们发现在函数体里的代码,一旦遇到return就返回到调用函数的地方了。而函数体里return之后的代码将不再执行。
- 那么return里能返回什么东西呢?关键字可以吗?函数的名字可以吗?我们继续往下看。
#代码演示: def test1() :
print ("in the test1")
return 0 def test2() :
print ("in the test2")
return test1 #能返回函数名吗?当然可以 #def test3() :
# print ("in the test3")
# return def #关键字能返回吗?当然不可以 x = test2()
print (x) #输出结果 [root@localhost scripts]# python3 test.py
in the test2
<function test1 at 0x7f15525bb378> #我们发现返回的是一个内存地址
- 内存地址:是一个指向内存的对象,Python根据这个地址从内存中提取数据,或者运行代码。
- 那么,同学们,函数名和函数名()有什么区别呢?我们继续实验。
#代码演示: def test1() :
print ("in the test1")
return 58 def test2() :
print ("in the test2")
return test1() #返回的是什么呢?还是地址吗? x = test2()
print (x) #输出结果 [root@localhost scripts]# python3 test.py
in the test2
in the test1
58 #返回的58
综上,我们发现,当我们return一个函数的名字时,返回的是一个指向内存的地址(并没有去内存中运行程序),当我们return一个函数名字+()时,返回的是那个函数体执行的结果。因此,()我们可以理解成执行前边的函数名对象。
1.6 函数为什么要有返回值?
因为在代码编写的过程中,我们经常需要知道一个函数体里的代码的执行情况。我们可以通过判断函数体的返回值来决定接下来的代码的走向。
#代码演示: def test1() :
return 0 def test2() :
return 1 if test1() :
print ("我是test1")
elif test2() :
print ("我是test2") #输出演示 [root@localhost scripts]# python3 test.py
我是test2
二,函数参数及调用
2.1 函数的调用
调用方法:
(1)形参和实参
- 形参:形式参数,不是实际存在,是虚拟变量。在定义函数和函数体的时候使用形参,目的是在函数调用时接收实参(实参个数,类型应与实参一一对应)
- 实参:实际参数,调用函数时传给函数的参数,可以是常量,变量,表达式,函数,传给形参。
区别:
形参是虚拟的,不占用内存空间,形参变量只有在被调用时才分配内存单元,实参是一个变量,占用内存空间,数据传送单向,实参传给形参,不能形参传给实参。
#代码演示: def test(x) : #x就是形参
print (x) test(2) #2就是实参,向函数test传递实参 #输出结果 2
(2)位置参数和关键字
同学们思考,形参可以比实参个数多吗?
标准传参调用方式
#代码演示: def test(x,y) :
print (x) test(2) #输出结果 [root@localhost scripts]# python3 test.py
Traceback (most recent call last):
File "test.py", line 7, in <module>
test(2)
TypeError: test() missing 1 required positional argument: 'y' #显示找不到y的值
所以,我们得出结果,形参个数不能比实参多。那么反过来呢?实参个数能不能比形参多?
#代码演示: def test(x) :
print (x) test(2,4) #输出结果 [root@localhost scripts]# python3 test.py
Traceback (most recent call last):
File "test.py", line 7, in <module>
test(2,4)
TypeError: test() takes 1 positional argument but 2 were given #显然也是错的
因此,形参个数和实参个数必须一一对应。形参有多少个,在传递参数的时候实参就必须有多少个。
关键字调用方式:
如果不指定实参具体传给哪个形参,那么默认是要按照顺序一一对应的。如果指定就会按照指定的方式赋值。
#代码演示: def test(x,y) :
print (x)
print (y) def test2(x,y) :
print (x)
print (y) test(2,4) #没指定,一一对应传参赋值方式
test2(y=2,x=4) #指定的传参赋值方式 #输出结果 [root@localhost scripts]# python3 test.py
2 #这是test函数的x
4 #这是test函数的y
4 #这是test2函数的x
2 #这是test2函数的y
思考:同学们分析下如下代码中的各种x,y都是什么意思?下面这段代码能正常执行吗?
#代码演示 def test(x,y) :
print (x)
print (y) x = 1
y = 1 test(x=x,y=y)
继续思考,同学们下面这段代码能正常执行吗?
#代码演示: def test(x,y) :
print (x)
print (y) test(x=2,3) #传递了一个未指定的实参和一个指定了的形参
还得思考,同学们下面这段代码能正常执行吗?
#代码演示: def test(x,y) :
print (x)
print (y) test(y=2,3) #传递了一个未指定的实参和一个指定了的形参
不能不思考:,同学们下面这段代码呢?能正常执行吗?
#代码演示: def test(x,y) :
print (x)
print (y) test(3,x=2)
最后的思考:,同学们下面这段代码能正常执行吗?
#代码演示: def test(x,y) :
print (x)
print (y) test(3,y=2)
同学们,是否已经懵逼了呢?请同学们仔细理解上面的几个例子然后验证如下的话:
- [x] :位置参数必须写在关键字参数的前边
- [x] :被位置参数赋值的形参,是不允许被关键字参数继续赋值的。
理解了上面几句话,请同学们继续分析如下例子。
#例1 def test(x,y,z):
print (x)
print (y)
print (z)
test(3,6,x=3) #例2 def test(x,y,z):
print (x)
print (y)
print (z)
test(3,6,z=3) #例3 def test(x,y,z):
print (x)
print (y)
print (z)
test(3,y=3,6) #例4 def test(x,y,z):
print (x)
print (y)
print (z)
test(3,y=3,z=5) #例5 def test(x,y,z):
print (x)
print (y)
print (z)
test(3,y=3,z=5) #例6 def test(x,y,z):
print (x)
print (y)
print (z)
test(3,z=3,y=5) #例7 def test(x,y,z):
print (x)
print (y)
print (z)
test(x=5,7,z=9)
能正确说出上述七个例子的答案,就说明你真的懂了。
三,架构引导与作业
架构引导:
- 通过对函数的学习,我们不难发现,所谓面向过程,其实就是利用我们对函数的定义来优化经常需要重复编写的代码,以达到简化代码的目的。
- 而通过调用的方式,我们可以将函数体内的代码在程序的每个关键点重复的去执行。
- 然而,拥有了参数传递的函数体,更可以实现我们许多复杂的逻辑计算功能。
- 因此,从函数这节开始,我们对整个代码编写的着眼点,就要放在如何利用函数思想,去设计优化我们的代码架构,使之更精简,更可读。
- 但是,同学们我们在学习函数体时,从未在函数体内赋值过新的变量。我们只是在介绍何为函数何为参数以及如果去使用和调用。
- 那么,函数体内可以创建新的变量吗?假如函数体内的变量和函数体外的变量名称冲突,那又会发生什么呢?这就需要我们学习下一节的知识:函数的作用域
作业:
利用函数思想优化并实现"用户管理接口"
完成时间:间隔一次课
- 有功能选择主菜单
- 可以注册用户账号
- 可以登陆用户账号
- 可以删除用户账号
- 可以修改用户密码
- 只能在功能选择菜单中退出程序
- 每个分支功能均可返回到主菜单
- 用户数据保存在文件中
Python运维开发基础09-函数基础 - 陈思齐 - 博客园
https://www.cnblogs.com/chensiqiqi/p/9163057.html
Python运维开发基础09-函数基础【转】的更多相关文章
- Python运维开发基础10-函数基础【转】
一,函数的非固定参数 1.1 默认参数 在定义形参的时候,提前给形参赋一个固定的值. #代码演示: def test(x,y=2): #形参里有一个默认参数 print (x) print (y) t ...
- Python运维开发基础01-语法基础【转】
开篇导语 整个Python运维开发教学采用的是最新的3.5.2版,当遇到2.x和3.x版本的不同点时,会采取演示的方式,让同学们了解. 教学预计分为四大部分,Python开发基础,Python开发进阶 ...
- Python运维开发基础01-语法基础
标签(空格分隔): Mr.chen之Python3.0执教笔记(QQ:215379068) --仅供北大青鸟内部学习交流使用 开发不是看出来的,开发一定是练出来的: 想学好开发,没有捷径可走,只有不断 ...
- Python运维开发基础08-文件基础【转】
一,文件的其他打开模式 "+"表示可以同时读写某个文件: r+,可读写文件(可读:可写:可追加) w+,写读(不常用) a+,同a(不常用 "U"表示在读取时, ...
- Python运维开发基础07-文件基础【转】
一,文件的基础操作 对文件操作的流程 [x] :打开文件,得到文件句柄并赋值给一个变量 [x] :通过句柄对文件进行操作 [x] :关闭文件 创建初始操作模板文件 [root@localhost sc ...
- Python运维开发基础06-语法基础【转】
上节作业回顾 (讲解+温习120分钟) #!/usr/bin/env python3 # -*- coding:utf-8 -*- # author:Mr.chen # 添加商家入口和用户入口并实现物 ...
- Python运维开发基础05-语法基础【转】
上节作业回顾(讲解+温习90分钟) #!/usr/bin/env python # -*- coding:utf-8 -*- # author:Mr.chen import os,time Tag = ...
- Python运维开发基础04-语法基础【转】
上节作业回顾(讲解+温习90分钟) #!/usr/bin/env python3 # -*- coding:utf-8 -*- # author:Mr.chen # 仅用列表+循环实现“简单的购物车程 ...
- Python运维开发基础03-语法基础 【转】
上节作业回顾(讲解+温习60分钟) #!/usr/bin/env python3 # -*- coding:utf-8 -*- # author:Mr.chen #只用变量和字符串+循环实现“用户登陆 ...
随机推荐
- C#设计模式(11)——装饰者模式
1.装饰者模式介绍 装饰者顾名思义就是对一个类添加一些额外的装饰(功能).我们想给一个对象添加一些额外的功能又不改变对象内方法的签名怎么做呢?最常用的方法就是继承了,子类继承父类,然后重写父类的方法. ...
- [JUC-1]并发包实现及线程状态
一.Java 并发包实现 二.Java 线程状态转换图
- uby on rails 用户密码加密
运行环境: rails 4.2.1 ruby 2.0.0p481 mysql(支持多种数据库) 在实际的项目中,需要注意对用户 ...
- Integer与int值的比较
==一般用于比较内存地址,equals()用于比较Object的值,注意int用equals()是会报错的.Integer i=1Integer k=1i.equals(k)=truei==k=tru ...
- 完全使用UDP登录Linux
===============Mosh 登录器========================================= == 针对TCP被某些防火墙阻断的Linux机器, 该程序可以让你不使 ...
- 指定so动态链接库连接器
在学习x86_64汇编时, 发现一旦使用glibc库函数, 如printf时, 一般是需要使用为ld传递命令行参数-lc来动态连接libc.so的, 但是, 生成的可执行文件却无法运行: 气煞我也! ...
- PC机Win10声音问题两例处理办法
1.PC电脑接HDMI显示器后无声的解决方案点击声音->播放,下面有一个是显示器,一个扬声器,选择扬声器即可.2.低音太重解决办法扬声器属性,增强,禁用所有声音效果.
- 使用 Topshelf 结合 Quartz.NET 创建 Windows 服务
Ø 前言 之前一篇文章已经介绍了,如何使用 Topshelf 创建 Windows 服务.当时提到还缺少一个任务调度框架,就是 Quartz.NET.而本文就展开对 Quartz.NET 的研究,以 ...
- java基础之自定义异常类及throw和throws的区别
一.异常的架构: Throwable类:所以异常类都是Throwable的子类,它派生两个子类 Error和Exception. Error类:表示仅靠程序本身无法恢复的的严重错误,比如内存溢出,虚拟 ...
- mssql 创建函数简单实例
CREATE FUNCTION [dbo].[f_DailyIncome] ( @userId int, @date date ) ,) AS BEGIN ,); ) from Channel_Use ...