python自动化运维之路~DAY4
作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。
一.模块导入方式详解.
关于Python有几种导入模块的方式,请参考我的另外一篇博客(第20道问答题):http://www.cnblogs.com/yinzhengjie/p/6396820.html
1.内置函数或者第三方库的导入方法。
1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ 5 #EMAIL:[email protected] 6 ''' 7 import导入内置函数用法展示: 8 ''' 9 import sys,os #导入内置函数 10 print(os.path.abspath(__file__)) #打印当前脚本的绝对路径 11 print(os.path.dirname(os.path.abspath(__file__))) #打印当前脚本所在目录的绝对路径 12 print("*"*50,"我是分割线","*"*50) 13 14 ''' 15 import导入第三方模块(paramiko连接服务器)的用法展示 16 ''' 17 import paramiko #通过用户名密码的方式登陆服务器并执行指令操作如下: 18 ssh = paramiko.SSHClient() 19 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 20 ssh.connect('172.30.1.87', 22, 'yinzhengjie', '1') 21 stdin, stdout, stderr = ssh.exec_command('df -h') 22 print(stdout.read()) 23 ssh.close() 24 25 26 #以上代码测试结果如下: 27 D:\python\daima\DAY5\ATM\bin\mange.py 28 D:\python\daima\DAY5\ATM\bin 29 ************************************************** 我是分割线 ************************************************** 30 b'\xe6\x96\x87\xe4\xbb\xb6\xe7\xb3\xbb\xe7\xbb\x9f \xe5\xae\xb9\xe9\x87\x8f \xe5\xb7\xb2\xe7\x94\xa8 \xe5\x8f\xaf\xe7\x94\xa8 \xe5\xb7\xb2\xe7\x94\xa8% \xe6\x8c\x82\xe8\xbd\xbd\xe7\x82\xb9\nudev 973M 0 973M 0% /dev\ntmpfs 199M 22M 178M 11% /run\n/dev/sda1 18G 5.1G 12G 31% /\ntmpfs 992M 220K 992M 1% /dev/shm\ntmpfs 5.0M 4.0K 5.0M 1% /run/lock\ntmpfs 992M 0 992M 0% /sys/fs/cgroup\ntmpfs 199M 72K 199M 1% /run/user/1000\n/dev/sr0 1.4G 1.4G 0 100% /media/yinzhengjie/Ubuntu 16.04 LTS amd64\n'
2.Python Package包的导入方法:
如果区分你看到的目录是一个Python Package包呢?其实很简单,你只要看这个名录下是否有__init__.py这个文件就好了,如果有那么就是Python Package包,如果没有,就说嘛你看到的就是个普通的目录,如下图,你就可以看出来ATM就是一个Python Package包,而shopping_mall就是一个目录,而判断的依据就是是否包含_init__.py文件。
那么,在python package包中导入模块呢?又是如何实现的呢?我们一起来看一下:
1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ 5 #EMAIL:[email protected] 6 ''' 7 前景提要: 8 在包ATM.bin目录下有一个atm模块,这个模块的内容如下: 9 def test_name(): 10 name_str = input("Please enter your name:>>>") 11 print("My name is [\033[31;1m%s \033[0m]"% name_str) 12 print("这里是ATM的执行程序") 13 ''' 14 import sys,os 15 BASE = os.path.normcase(os.path.join(os.path.dirname(os.path.abspath(__file__)), # 16 os.path.pardir, 17 os.path.pardir) 18 ) 19 20 sys.path.append(BASE) #这个步骤是将路径加进来,并执行里面的代码 21 from ATM.bin import atm 22 atm.test_name() 23 ''' 24 关于“BASE“字符串说明如下: 25 1>.os.path.normcase(path)作用:本地化的路径的字符串。在Unix和Mac OS X,这个返回的路径不变;不区分大小写的文件系统,它的路径转换为小写。在Windows上,它也转换成斜线,反斜线。 26 2>.path说明如下: 27 os.path.join(os.path.dirname(os.path.abspath(__file__)), #join是把路径拼接起来,dirname是取该文件的目录 28 os.path.pardir, #pardir是取上级目录 29 os.path.pardir) #pardir是取上级目录 30 ''' 31 32 33 #以上代码测试结果如下: 34 这里是ATM的包名 35 这里是ATM的执行程序 36 Please enter your name:>>>尹正杰 37 My name is [尹正杰 ]
二.装饰器:("器"所指的就是函数)
定义:本质是函数,(装饰其他函数)就是为其他函数添加附加功能。
原则:装饰器对它被装饰的函数是完全透明的,大致分为两个特色:
1.不能修改被装饰的函数的源代码;
2.不能修改被装饰的函数的调用方式。
实现装饰器知识储备:1.函数即"变量";
2.高阶函数;
3.嵌套函数。
1.函数即"变量"
1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ 5 #EMAIL:[email protected] 6 ''' 7 函数即"变量": 8 和变量的存储方式是一样的,我们定义个函数得给他起一个名称,便于我们来调用。 9 函数分两种:1.用关键字定义的函数“def” 10 2.匿名函数 11 ''' 12 #无参数函数 13 def test_1():#其中我们可以将test_1这个函数名称[存储内存地址,在后面加一个()就可以调用该函数,将其下面的所有的代码叫做函数体 14 print("my name is yinzhengjie,I love python!") #从这一行开始缩进相同的代码就是函数体 15 return "goodboy!" 16 17 #有参数函数 18 def test_2(name): 19 print("my name is \033[32;1m%s:\033[0m"%name) 20 pass 21 test_1() #这个过程就是调用上面已经定义好的函数! 22 test_2("yinzhengjie") 23 print("*"*50,"我是分割线","*"*50) 24 ''' 25 什么是匿名函数: 26 不需要起名称而且不需要被多次调用!基本上允许一次之后就被回收了,不过我们可以给他赋值给一个变量。(python解释器会定时查看当前内存的变量是否被调用,如果没有被调用的话就会被解释器收回内存地址,如果已经被调用的话就不会收回其的内存地址直到程序运行结束之后释放掉所有的内存,注意,如果你的某个变量被多个地方调用的话你手动del掉的变量还是不会被系统收回,你删除的只是这个变量的某一次的调度次数而已~) 27 ''' 28 print(lambda y:y+100) #由于没有赋值给你一个变量,python解释器无法调用它(如果使用print函数打印它的话,只能打印它在内存中的地址编号而已)!我们需要按照下面的方法进行调用的哟~ 29 calc = lambda x:x*100 30 print(calc(3)) 31 32 33 #以上代码执行结果如下: 34 my name is yinzhengjie,I love python! 35 my name is yinzhengjie: 36 ************************************************** 我是分割线 ************************************************** 37lambda> at 0x00E16DB0> 38 300
2.高阶函数
1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ 5 #EMAIL:[email protected] 6 import time 7 #a.把一个函数名当作实参传给另外一个函数(在不修改被装饰函数源代码的情况下为其添加附加功能); 8 def test1(function): 9 start_time = time.time() 10 function() 11 stop_time = time.time() 12 print("the function run time is %s" % (stop_time - start_time)) 13 def bar(): 14 print("in the bar") 15 time.sleep(3) 16 test1(bar) 17 print("*"*50,"我是分割线","*"*50) 18 # b.返回值中包含函数名(不修改函数的调用方式)。 19 def bar(): 20 time.sleep(2) 21 print("in the bar") 22 def test2(function): 23 print(function) 24 return function 25 print(test2(bar)) 26 t=test2(bar) 27 t() 28 29 30 #以上代码执行结果如下: 31 in the bar 32 the function run time is 3.0001704692840576 33 ************************************************** 我是分割线 ************************************************** 3435 36 37 in the bar
3.嵌套函数
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :yinzhengjie #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ #EMAIL:[email protected] ''' 嵌套函数: 简单的理解就是函数里面套函数,就是一个def中可以定义多个def,而且支持在函数中调用子函数,下面我们来举例子看一下就明白了 。 ''' #例如1: def foo(): print("in the foo") def bar(): print("in the bar") bar() #只属于局部变量的函数,只能在局部变量的缩进来调用,不能在全局调用哟~ def test1(): foo() test1() print("*"*50,"我是分割线","*"*50) foo() print("*"*50,"我是分割线","*"*50) # 例如2: x=0 def grandpa(): x=1 def dad(): x=2 def son(): x=3 print(x) #最终生效的作用域不是全局变量,而是当前函数的定义的变量x=3,这就是在嵌套函数中的作用域的功能! son() dad() grandpa() #以上代码执行结果如下: in the foo in the bar ************************************************** 我是分割线 ************************************************** in the foo in the bar ************************************************** 我是分割线 ************************************************** 3
4.定义一个无参数装饰器,(装饰器又叫语法糖,在其他语言中也有类似的功能哟~)
1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ 5 #EMAIL:[email protected] 6 import time 7 #定义一个装饰器,实现统计每个函数的运行时间 8 def timmer(func): #定义一个装饰器名称(也可以理解定义一个变量),并定义一个需要装饰的参数,当调用的时候必须将被装饰的参数替换,Python默认做了这个操作 9 def warpper(*args,**kwargs): #这个就是装饰器,里面会存着传给func的参数 10 start_time = time.time() 11 res = func(*args,**kwargs) #运行被装饰的函数 12 stop_time = time.time() 13 print('the func tun time is %s' % (stop_time - start_time)) 14 return res 15 return warpper 16 17 # 定义一个函数,并且使用@符号调用装饰器即可! 18 @timmer #相当于test1 = timer(test1) 这个时候会去调用timmer这个装饰器。 19 def test1():#这个功能只是打印字符串的功能 20 time.sleep(3) 21 print("in the test1") 22 23 @timmer #相当于test2 = timer(test2) 24 def test2(name,age):#这个功能只是打印字符串的功能,并且还有返回值 25 time.sleep(3) 26 print("My name is \033[32;1m%s:\033[0m" % name) 27 print("My age is \033[32;1m%s:\033[0m" % age) 28 return 100 29 30 # 调用对应的函数 31 result_1= test1() 32 result_2 = test2("yinzhengjie",25) 33 print(result_1) 34 print(result_2) 35 36 37 #以上代码执行效果如下: 38 in the test1 39 the func tun time is 3.000213146209717 40 My name is yinzhengjie: 41 My age is 25: 42 the func tun time is 3.0001907348632812 43 None 44 100
5.定义一个有参装饰器
1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ 5 #EMAIL:[email protected] 6 #定义一个有参装饰器,在调用的时候需要传递一个参数进去 7 import time 8 user,passwd = "yinzhengjie","123" 9 def auth(auth_type): #定义一个模拟登陆网页认证的装饰器 10 def outer_wrapper(func): 11 def wrapper(*args, **kwargs): 12 username = input("Please enter your username:>>>").strip() 13 password = input("Please enter your password:>>>").strip() 14 if user == username and passwd == password: 15 print("欢迎你,:\033[0m%s\033[0m" % username) 16 res = func(*args, **kwargs) 17 return res 18 else: 19 exit("\033[31;1m用户名或者密码错误!\033[0m") 20 return wrapper 21 return outer_wrapper 22 def index(): 23 print("welcome to index page!") 24 @auth(auth_type="local") 25 def home(): 26 print("welcome to home page!") 27 return "这是家目录" 28 @auth(auth_type = "ldap") 29 def bbs(): 30 print("welcome to bbs page!") 31 index() 32 print(home()) 33 bbs() 34 35 36 #以上代码执行结果如下: 37 welcome to index page! 38 Please enter your username:>>>yinzhengjie 39 Please enter your password:>>>123 40 欢迎你,:yinzhengjie 41 welcome to home page! 42 这是家目录 43 Please enter your username:>>>yinzhengjie 44 Please enter your password:>>>123 45 欢迎你,:yinzhengjie 46 welcome to bbs page!
6.定义有参装饰器
1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ 5 #EMAIL:[email protected] 6 #装饰器实战模版,模拟控制网络的登录方式。 7 # (实现了第一次登录成功后,第二次访问其他的网页就不需要重新输入密码,和上面的那个有点差别) 8 import time 9 def timmer(func): 10 def warpper(*args,**kwargs): 11 start_time = time.time() 12 func(*args,**kwargs) 13 stop_time = time.time() 14 print('the func tun time is %s' % (stop_time - start_time)) 15 return warpper 16 #定义一个函数,并且使用@符号调用装饰器即可! 17 accunts = {} #用于验证用户是否成功登录的容器 18 corrent_logon_user = None 19 def auth(auth_type): 20 def auth_deco(func): 21 def wrapper(*args,**kwargs): 22 if corrent_logon_user not in accunts: 23 user = input("please input your username:>>>") 24 passwd = input("please input your passward:>>>") 25 if auth_type == "file": 26 if user == "yinzhengjie" and passwd == "123": 27 accunts[user] = True 28 print(accunts) 29 global corrent_logon_user #可能会生成SyntaxWarning提醒,可忽略,可以用异常处理来过滤掉 30 corrent_logon_user = user 31 return func(*args,**kwargs) 32 else: 33 print("") 34 elif auth_type == "ldap": 35 print("===>ldap") 36 return func(*args,kwargs) 37 else: 38 return func(*args,**kwargs) 39 return wrapper 40 return auth_deco 41 @auth('file') 42 def index(msg): 43 print("in the index:",msg) 44 @auth('ldap') 45 def home(): 46 print("in the home") 47 return "66666" 48 index("test") 49 print(home()) 50 please input your username:>>> yinzhengjie 51 please input your passward:>>>123 52 {'yinzhengjie': True} 53 in the index: test 54 in the home 55 66666
三.生成器
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的,而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面的几个元素,那后面绝大多数元素占用的空间就白白浪费了。所以,如果列表元素可以按照某种算法推算出来,那我们是可以在循环中的过程中不断的推算出后续的元素呢?这样就不必创建完整的list,从而节省了大量的空间。在python中,这种一边循环一边计算的机制,称为生成器:generator.
生成器特点:
1.只有在调用的时候才会生成相应的数据,这是节省内存的核心因素;
2.只记录当前位置;
3.只有一个__next___()方法。 在python2.7中使用next方法则用:next().
1.开始写一个简单的生成器
1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ 5 #EMAIL:[email protected] 6 fist = (i*2 for i in range(10)) #列表生成式,可以使你的代码更加便捷!可以很下面的代码进行比较哟~ 7 # for i in fist: #查看这个生成器的所有元素 8 # print(i) 9 print(fist.__next__()) #打印第生成器的第一个数据 10 print(fist.__next__()) #打印生成器的第二个数据,并且会自动从内存中删除上一个数据所占的内存 11 print(fist.__next__()) #打印生成器的第三个数据,并且会自动从内存中删除之前所占的内存变量,也就是只保存当前的数据,不过__next__方法我们用的很少,一般都是用for循环实现,以减少代码的重复,不然的话1000w的数据我们得调用1000次就麻烦了,哈哈 12 print("*"*50,"我是分割线","*"*50) 13 #我们可以看下定义的列表,其实定义的一个列表就是把数据强行写到内存去了,直接就占用内存,下面有2种方法定义一个列表,效率差不多,但是第一种方法明显节省代码的容量啊~ 14 list_0 = [ i*2 for i in range(20)] #这种方法是列表生成生成式,和下面(list_1)的3行代码的效率是一样的,但是代码更加简洁。 15 list_1 = [] 16 for i in range(20): 17 list_1.append(i*2) 18 print(list_0) 19 print(list_1) 20 # 如果上面要循环1万次,会对内存占用很大的空间,而且还会浪费时间!python解释器有一个神器出现了,就是生成器,它生成的是一个内存地址,并没有真正的开辟内存空间!只有通过__next__方法(一般用循环)取值的时候才会去得到相应的数字。 21 list_3 = (i*2 for i in range(10000000)) #这就是定义一个生成器,如果用列表定义的话可能要等待3s左右,但是生成器则是你定义完毕就OK了,随时可以调用 22 print(list_3) #仅仅是生成了一个生成器的内存地址 23 24 #以上代码测试结果如下: 25 0 26 2 27 4 28 ************************************************** 我是分割线 ************************************************** 29 [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38] 30 [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38] 31at 0x01882B10>
2.用生成器写斐波那契数列
1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ 5 #EMAIL:[email protected] 6 #通过学习上面的生成器,只是一个开门见山,因为generator非常强大,如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现哟,比如著名的“斐波那契数列[Fibonacci]” 7 #"斐波那契数列"用列表生成式写不出来,但是,用函数就能把他打印出来却很容易哟: 8 def fib(max): 9 n,a,b, = 0,0,1 10 while n < max: 11 #print(b) 12 yield b #如果一个函数中有yield的存在就不能叫只叫它函数了,而是一个生成器 13 a,b = b,a+b #相当于:t = (b,a + b) ; a =t[0] ;b =t[1] 14 n = n + 1 15 return "done" 16 f = fib(100) 17 #print(f) 18 for i in range(10): #打印前10个"斐波那契数列",通过__next__的方法来取得想要的结果。 19 print(f.__next__()) 20 21 22 ''' 23 如果用__next__方法读取文件的话读到最后一行再往下读的话是会报错的,这个时候我们就可以用捕捉异常来出来,下面就简单的举个例子 24 ''' 25 #当使用循环迭代的时候会报错,我们可以通过捕捉异常的方法将数据进行抓取 26 g = fib(6) 27 while True: 28 try: #抓取这段代码进行操作 29 x = next(g) 30 print("g:",x) 31 except StopIteration as e: #如果报错是:StopIteration就执行以下的代码。 32 print("Generator return value:",e.value) 33 break 34 35 #以上代码执行结果如下: 36 1 37 1 38 2 39 3 40 5 41 8 42 13 43 21 44 34 45 55 46 g: 1 47 g: 1 48 g: 2 49 g: 3 50 g: 5 51 g: 8 52 Generator return value: done
3.生成器的send方法
1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ 5 #EMAIL:[email protected] 6 import time 7 def consumer(name): 8 print("%s 准备吃饺子啦!"% name) 9 while True: 10 dumplings = yield 11 print("饺子[%s]来了,被[%s]吃了!"% (dumplings,name)) 12 test_1 = consumer("yinzhengjie") 13 test_1.__next__() #__next__方法是调用"yield"但是不能传值 14 test_1.__next__() 15 filling = "猪肉大葱" 16 test_1.send(filling) #不仅仅可以调用“yield”还可以给它传一个值哟 17 18 def producer(name): 19 c = consumer("A") 20 c2 = consumer("B") 21 c.__next__() 22 c2.__next__() 23 print("俺要开始准备吃饺子了!") 24 for i in range(10): 25 time.sleep(1) 26 print("做了2个饺子") 27 c.send(i) 28 c2.send(i) 29 producer("尹正杰") 30 31 32 #以上代码执行结果如下: 33 yinzhengjie 准备吃饺子啦! 34 饺子[None]来了,被[yinzhengjie]吃了! 35 饺子[猪肉大葱]来了,被[yinzhengjie]吃了! 36 A 准备吃饺子啦! 37 B 准备吃饺子啦! 38 俺要开始准备吃饺子了! 39 做了2个饺子 40 饺子[0]来了,被[A]吃了! 41 饺子[0]来了,被[B]吃了! 42 做了2个饺子 43 饺子[1]来了,被[A]吃了! 44 饺子[1]来了,被[B]吃了! 45 做了2个饺子 46 饺子[2]来了,被[A]吃了! 47 饺子[2]来了,被[B]吃了! 48 做了2个饺子 49 饺子[3]来了,被[A]吃了! 50 饺子[3]来了,被[B]吃了! 51 做了2个饺子 52 饺子[4]来了,被[A]吃了! 53 饺子[4]来了,被[B]吃了! 54 做了2个饺子 55 饺子[5]来了,被[A]吃了! 56 饺子[5]来了,被[B]吃了! 57 做了2个饺子 58 饺子[6]来了,被[A]吃了! 59 饺子[6]来了,被[B]吃了! 60 做了2个饺子 61 饺子[7]来了,被[A]吃了! 62 饺子[7]来了,被[B]吃了! 63 做了2个饺子 64 饺子[8]来了,被[A]吃了! 65 饺子[8]来了,被[B]吃了! 66 做了2个饺子 67 饺子[9]来了,被[A]吃了! 68 饺子[9]来了,被[B]吃了!