本站以分享各种运维经验和运维所需要的技能为主
《python零基础入门》:python零基础入门学习
《python运维脚本》: python运维脚本实践
《shell》:shell学习
《terraform》持续更新中:terraform_Aws学习零基础入门到最佳实战
《k8》暂未更新
《docker学习》暂未更新
《ceph学习》ceph日常问题解决分享
《日志收集》ELK+各种中间件
《运维日常》运维日常
《linux》运维面试100问
高阶函数应用
用法:
函数操作符:
参数:
-
以key=val形式存在的参数,称为关键字参数
-
以args形式存在的参数,称作位置参数
def func1(name,age):
print('%s is %s years old' % (name,age))
func1() #报错, 参数不够
func1('tom',20,100) #错误,参数个数太多
func1('tom',20) #OK
func1(20,'tom') #语法正确,语义不对
func1(age=20,name='ton') #OK
func1(age=20,'tom') #语法错误.关键字参数必须在位置参数后
func1(20,name='tom') #错误,因为name得到了多个值
func1('tom',age=20) #ok
参数组:
-
定义函数时,参数名前加上*表示把参数放到元组中
-
定义函数时,参数名前加上(两个)**表示把参数放到字典中
将参数放到元组上: 加 *
def func2(*args):
print(args)
func2()
func2('hao')
func2('hao',100,200,'tom','jerry')
>>> func2()
()
>>> func2('hao')
('hao',)
将参数放到字典上 : 加**
>>> def func(**args):
... print(args)
...
>>>
>>> func()
{}
>>> func(name='tom',age=20)
{'name': 'tom', 'age': 20}
例子:
调用函数时,给参数加上一个*把列表拆成一个个的个体:
>>> def myadd(x,y):
... return x + y
...
>>>
>>> nums = [123 , 4564]
>>> myadd(nums[0],nums[1])
4687
>>> myadd(*nums)
4687
调用函数时,给参数加上一个*把拆成一个个的个体:
>>> def myadd(x,y):
... return x + y
>>> adict = {'x':100,'y':25}
>>> adict
{'x': 100, 'y': 25}
>>> myadd(**adict)
125
myadd(x=100,y=25)
计算游戏:
from random import choice,randint
def exam():
'出题测试'
#随机取出100以内的两个随机数字
nums = [randint(1,100) for i in range(2)]
nums.sort(reverse=True) #降序排列
#随机取出加减法
op = choice('+-')
#算出正确答案
if op == '+':
result = nums[0] + nums[1]
else:
result = nums[0] - nums[1]
#用户作答
count = 0
win = 0
prompt = '%s %s %s = ' % (nums[0], op, nums[1])
while count < 4:
try:
answer = int(input(prompt))
except ValueError:
print('不可以偷懒哦')
continue
if answer == result:
win += 1
print('Very Good !!!')
break
else:
print('Wrong Answer !!!!')
count += 1
else:
print('\033[031;1m正确答案:%s%s\033[0m' % (prompt,result))
def main():
while 1:
exam()
try:
#将用户输入信息的额外空白字符删除后,取出第一个字符
yn = input('Continue(y/n)? ').strip()[0]
except IndexError:
continue
except (KeyboardInterrupt, EOFError):
print('n')
if yn in 'nN':
print('\nbye-bye')
break
if __name__ == '__main__':
main()
匿名函数:
-
lambda关键字后面的名称是函数参数
-
冒号后面表达式的结果是匿名函数的返回值
>>> add2 = lambda x,y : x+y
>>> add2(5,6)
11
from random import choice,randint
# def add(x,y):
# return x + y
#
# def sub(x,y):
# return x - y
def exam():
'出题测试'
#cmds = {'+': add, '-': sub}
cmds = {'+': lambda x, y:x + y, '-':lambda x, y: x - y}
#随机取出100以内的两个随机数字
nums = [randint(1,100) for i in range(2)]
nums.sort(reverse=True) #降序排列
#随机取出加减法
op = choice('+-')
#算出正确答案
# if op == '+':
# result = nums[0] + nums[1]
# else:
# result = nums[0] - nums[1]
#result = cmds[op](nums[0],nums[1])
result = cmds[op](*nums)
#用户作答
count = 0
win = 0
prompt = '%s %s %s = ' % (nums[0], op, nums[1])
while count < 4:
try:
answer = int(input(prompt))
except ValueError:
print('不可以偷懒哦')
continue
if answer == result:
win += 1
print('Very Good !!!')
break
else:
print('Wrong Answer !!!!')
count += 1
else:
print('\033[031;1m正确答案:%s%s\033[0m' % (prompt,result))
def main():
while 1:
exam()
try:
#将用户输入信息的额外空白字符删除后,取出第一个字符
yn = input('Continue(y/n)? ').strip()[0]
except IndexError:
continue
except (KeyboardInterrupt, EOFError):
print('n')
if yn in 'nN':
print('\nbye-bye')
break
if __name__ == '__main__':
main()
filter函数
-
它的第一个参数是函数,该函数接受一个参数,返回True或者False
-
它的第二个参数是序列对象
-
序列对象的每个值作为参数传给第一个函数,返回真保留,否则丢弃
过滤奇数:
from random import randint
def func1(x):
return True if x % 2 == 0 else False
if __name__ == '__main__':
nums = [randint(1,100) for i in range(10)]
print(nums)
result = filter(func1,nums)
result2 = filter(lambda x:True if x % 2 == 0 else False,nums)
print(list(result))
print(list(result2))
map函数:
-
- 它的第一个参数是函数,该函数用于加工数据
-
- 它的第二个参数是序列对象
-
- 序列对象中的每一个数据都会传给函数进行加工,保留加工结果
from random import randint
def func(x):
return x * 2 +1
if __name__ == '__main__':
nums = [randint(1,100) for i in range(10)]
print(nums)
result = map(func,nums)
result2 = map(lambda x: x * 2 + 1 , nums)
print(list(result))
print(list(result2))
变量作用域:
全局变量:#在函数外面定义的变量,是全局变量,全局变量从定义开始,到程序结束,一直可见可用
局部变量:#函数内定义的变量是局部变量,局部变量只能在函数内使用
#在函数外面定义的变量,是全局变量,全局变量从定义开始,到程序结束,一直可见可用
>>> a = 100
>>> def func1():
... print(a)
...
>>> func1()
100
#函数内定义的变量是局部变量,局部变量只能在函数内使用
>>> def func2():
... b = 'hello'
... print(b)
...
>>> func2()
hello
>>> b #全局变量中,b变量还没有定义
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'b' is not defined
#全局和局部存在同名变量,局部变量将会遮盖住全局变量
>>> def func3():
... a = 200
... print(a)
...
>>> func3()
200
>>> a
100
#如果希望在局部将全局变量改变,需要使用global关键字
>>> def func4():
... global a
... a = 200
... print(a)
...
>>> func4()
200
>>> print(a)
200
>>> a
200
偏函数:
-
- 改造现有函数,生成新函数
-
- 将现有函数的某些参数固定下来,生成新函数
>>> def add(a,b,c,d,e):
... return a + b + c + d + e
...
>>> add(10,20,30,40,1)
101
>>> add(10,20,30,40,9)
109
>>> add(10,20,30,40,19)
119
#改造现有的add函数,把前4项的值固定来,生成新函数,新函数只需要一个参数,即原函数的第5个参数
>>> from functools import partial
>>> myadd = partial(add,10,20,30,40)
>>> myadd(1)
101
>>> myadd(9)
109
>>> myadd(19)
119
#int函数默认认为传入的字符串是10进制数形式
>>> int('10')
10
>>> int('10',base=2)
2
>>> int('11',base=2)
3
>>> int('11000001',base=2)
193
#改造int函数,生成新函数intX,用于指字符串是X进制
>>> int2 = partial(int , base=2)
>>> int2('11110001')
241
>>> int8 = partial(int , base=8)
>>> int8('11')
9
递归函数
def func(x):
if x == 1:
return 1
else:
return x * func(x - 1)
if __name__ == '__main__':
print(func(5))
例子:快速排序:
>>> nums = [11, 50, 51, 54, 57, 88, 68, 2, 81, 89]
# 假设第一个数是中间值,比中间值大的放到一个列表,小的放到另一个列表
>>> middle = nums[0] # middle是数字
>>> smaller = [2]
>>> larger = [50, 51, 54, 57, 88, 68, 81, 89]
# 把3个部分拼接
>>> smaller + [middle] + larger
[2, 11, 50, 51, 54, 57, 88, 68, 81, 89]
# 继续用相同的方法把smaller列表和larger列表进行排序
# 当列表只有一项或是空列表,就不用再排序了
from random import randint
def qsort(seq):
# 如果序列长度小于2,直接返回,不用排
if len(seq) < 2:
return seq
# 假设第一项是中间值
middle = seq[0]
smaller = [] # 存放比中间值小的数字
larger = [] # 存放比中间值大的数字
# 遍历seq中剩余内容,比middle小的放到smaller中,大的放到larger中
for data in seq[1:]:
if data <= middle:
smaller.append(data)
else:
larger.append(data)
# 将三个部分拼接起来,smaller和larger用相同的方法继续排列
return qsort(smaller) + [middle] + qsort(larger)
if __name__ == '__main__':
nums = [randint(1, 100) for i in range(10)]
print(nums)
print(qsort(nums))
生成器:
-
生成器表达式,与列表解析语法一样,只是用()替代[]
-
函数形成的生成器
1.表达式:
>>> ['192.168.1.%s' % i for i in range(255)]
>>> ('192.168.1.%s' % i for i in range(255)) ----节省空间
<generator object <genexpr> at 0x7f79ed4c4b48>
>>> for ip in ('192.168.1.%s' % i for i in range(255)):
>>> print(ip)
2.函数:
>>> def mygen():
... yield 10
... yield 200
... a = 100 + 200
... yield a
... yield 'hello'
...
>>> mg = mygen()
>>> mg
<generator object mygen at 0x7f79ed4c4ba0>
>>> for i in mg :
... print(i)
...
10
200
300
hello
模块:
搜索路径:
在导入模块时,python到sys.path定义的目录下搜索
(nsd1907) [root@room8pc16 day03]# mkdir /tmp/mymods
(nsd1907) [root@room8pc16 day03]# vim /tmp/mymods/star.py
hi = "Hello World!"
def pstar(n=30):
print('*' * n)
if __name__ == '__main__':
pstar()
(nsd1907) [root@room8pc16 day03]# python
>>> import star # 报错
>>> import sys
>>> sys.path
>>> sys.path.append('/tmp/mymods')
>>> import star # 成功
- 还可以定义PYTHONPATH环境变量,来指定模块搜索路径
(nsd1907) [root@room8pc16 day03]# export PYTHONPATH=/tmp/mymods
(nsd1907) [root@room8pc16 day03]# python
>>> import sys
>>> sys.path
['', '/tmp/mymods', '/usr/local/lib/python36.zip', '/usr/local/lib/python3.6', '/usr/local/lib/python3.6/lib-dynload', '/root/nsd1907/lib/python3.6/site-packages']
- 目录也可以作为一个特殊的模块,称作包
> 注意:在python2中,目录下必须有一个名为\_\_init\_\_.py的文件,才能成为包,该文
件即使是空的,也必须存在。
(nsd1907) [root@room8pc16 day03]# mkdir mypkgs
(nsd1907) [root@room8pc16 day03]# vim mypkgs/mytest.py
hi = 'Hello China'
(nsd1907) [root@room8pc16 day03]# ls
mypkgs
(nsd1907) [root@room8pc16 day03]# python
>>> import mytest # Error
>>> import mypkgs.mytest # 正确
>>> mypkgs.mytest.hi
'Hello China'
tarfile模块
-
用于实现压缩,解压缩
打包:
>>> tar = tarfile.open('/tmp/myfile.tar.gz', 'w:gz')
>>> tar.add('/etc/hosts')
>>> tar.add('/etc/security')
>>> tar.close()
解压:
>>> tar = tarfile.open('/tmp/myfile.tar.gz')
>>> tar.extractall(path='/tmp/mymods')
>>> tar.close()
>>>
hashlib模块:
(nsd1907) [root@room9pc01 etc]# echo -n 123456 > /tmp/1.txt
(nsd1907) [root@room9pc01 etc]# md5sum /tmp/1.txt
e10adc3949ba59abbe56e057f20f883e /tmp/1.txt
>>> import hashlib
>>> m = hashlib.md5(b'123456') #参数必须是bytes类型
>>> m.hexdigest()
'e10adc3949ba59abbe56e057f20f883e'
>>> m1 = hashlib.md5()
>>> m1.update(b'12')
>>> m1.update(b'34')
>>> m1.update(b'56')
>>> m1.hexdigest()
'e10adc3949ba59abbe56e057f20f883e'
import hashlib
import sys
def check_md5(fname):
m = hashlib.md5()
with open(fname, 'rb') as fobj:
while 1:
data = fobj.read(4096)
if not data:
break
m.update(data)
return m.hexdigest()
if __name__ == '__main__':
print(check_md5(sys.argv[1]))
例子:备份
# (nsd1907) [root@room9pc01 day03]# mkdir -p /tmp/demo/security
# (nsd1907) [root@room9pc01 day03]# mkdir -p /tmp/demo/backup
# (nsd1907) [root@room9pc01 day03]# cp -r /etc/security /tmp/demo/
from time import strftime
import os
import tarfile
import hashlib
import sys
import pickle
def check_md5(fname):
m = hashlib.md5()
with open(fname, 'rb') as fobj:
while 1:
data = fobj.read(4096)
if not data:
break
m.update(data)
return m.hexdigest()
def full_backup(src,dst,md5file):
'源目录打包,计算每个文件的md5值'
#拼接出打包的文件名
fname = '%s_full_%s.tar.gz' % \
(os.path.basename(src),strftime('%Y%m%d'))
fname = os.path.join(dst,fname)
#压缩
tar = tarfile.open(fname,'w:gz')
tar.add(src)
tar.close()
#计算每个文件的md5值
md5dict = {}
for path, folders, files in os.walk(src):
for file in files :
key = os.path.join(path,file)
md5dict[key] = check_md5(key)
#把md5字典存到文件中
with open(md5file,'wb') as fobj:
pickle.dump(md5dict,fobj)
def incr_backup(src,dst,md5file):
'找到新增文件和改动的文件,将它们打包: 更新md5值'
#拼接出打包的文件名
fname = '%s_back_%s.tar.gz' % \
(os.path.basename(src),strftime('%Y%m%d'))
fname = os.path.join(dst,fname)
#计算每个文件的md5值
md5dict = {}
for path, folders, files in os.walk(src):
for file in files :
key = os.path.join(path,file)
md5dict[key] = check_md5(key)
#取出前一天的md5值
with open(md5file,'rb') as fobj:
old_md5 = pickle.load(fobj)
#将新增文件和变化文件打包
tar = tarfile.open(fname,'w:gz')
for key in md5dict:
if old_md5.get(key) != md5dict[key]:
tar.add(key)
tar.close()
#更新md5文件
with open(md5file,'wb') as fobj:
pickle.dump(md5dict,fobj)
if __name__ == '__main__':
src = '/tmp/demo/security'
dst = '/tmp/demo/backup'
# 周一完全备份,其他时间增量备份
md5file = '/tmp/demo/md5.data'
if strftime('%a') == 'Mon':
full_backup(src,dst,md5file)
else:
incr_backup(src,dst,md5file)
######每次增量备份完之后,可以用以下命令查看md5是否有更新
(nsd1907) [root@room9pc01 day03]# strings /tmp/demo/md5.data | grep host
/tmp/demo/security/hostsq