python-08

一、内部函数:在一个函数的内部包含另一个函数
  1. #!/usr/bin/env python
  2. def foo():
  3. def bar():
  4. print 'hello world'
  5. bar()
  6. foo()
以上程序可以执行,但是如果在主程序中直接调用bar()会失败
a代表bar()别名
  1. #!/usr/bin/env python
  2. def foo():
  3. def bar():
  4. print 'hello world'
  5. return bar
  6. a = foo()
  7. a()
二、闭包
例: 我们需要使用多个计数器,这些技术器起始值不一样。希望只使用一个装饰器的功能,那么就可以使用闭包的技术:
  1. #!/usr/bin/env python
  2. def counter(start_at = 0):
  3. count = [start_at]
  4. def incr():
  5. count[0] += 1
  6. return count[0]
  7. return incr
  8. a = counter()
  9. print a()
  10. print a()
  11. print a()
  12. print a()
  13. b = counter(10)
  14. print b()
  15. print b()
  16. print a()
  17. print b()
三、偏函数
可以为某些函数提供默认参数。
  1. >>> from operator import add, mul
  2. >>> from functools import partial
  3. >>> add(10, 4)
  4. 14
  5. >>> add10 = partial(add, 10)
  6. >>> add10(4)
  7. 14
  8. >>> mul(2, 8)
  9. 16
  10. >>> mul2 = partial(mul, 2)
  11. >>> mul2(8)
  12. 16
例2:
为图形界面中的按钮设置默认的前景色、背景色等
安装Tkinter
#yum install -y tkinter
  1. #!/usr/bin/env python
  2. import Tkinter
  3. from functools import partial
  4. root = Tkinter.Tk()
  5. mybutton = partial(Tkinter.Button, root, fg = 'white', bg = 'blue')
  6. b1 = mybutton(text = 'button 1')
  7. b2 = mybutton(text = 'button 2')
  8. bq = mybutton(text = 'QUIT', bg = 'red', command = root.quit)
  9. b1.pack()
  10. b2.pack()
  11. bq.pack(fill = Tkinter.X, expand = True)
  12. root.title('test!')
  13. root.mainloop()
 
四、装饰器
考虑以下代码:当执行一个函数或程序的时候,希望知道它是什么时候开始,什么时候结束
  1. #!/usr/bin/env python
  2. import time
  3. def loop2(n = 10):
  4. time.sleep(1)
  5. mylist = []
  6. for i in range(n):
  7. if i % 2:
  8. mylist.append(i)
  9. return mylist
  10. print 'loop start at: ', time.ctime()
  11. print loop2()
 
通过以上的修改如果有新的函数需要知道开始、结束的时间,就可以把新的函数使用以上的方法,会改变原始函数的名字。所以就有了装饰器的用法。 
  1. #!/usr/bin/env python
  2. import time
  3. def deco(func):
  4. def timeit(n = 10):
  5. print 'prog start at: ', time.ctime()
  6. newlist = func(n)
  7. print 'prog done at: ', time.ctime()
  8. return newlist
  9. return timeit
  10. @deco
  11. def loop(n = 10):
  12. time.sleep(1)
  13. mylist = []
  14. for i in range(n):
  15. if i % 2:
  16. mylist.append(i)
  17. return mylist
  18. print loop()
  19. print loop(5)
 
一、模块
1、模块是以逻辑的方式组成的python代码,物理表现形式是文件。如果一个py或ZIP为扩展名,那么该文件也就可以当成模块导入了
全局作用域
  1. #!/usr/bin/env python
  2. x = 3
  3. def foo():
  4. print x
  5. foo()

局部作用域   会报错
  1. #!/usr/bin/env python
  2. def foo():
  3. x = 3
  4. foo()
  5. print x

全局、局部作用域
  1. #!/usr/bin/env python
  2. x = 3
  3. def foo():
  4. x = 4
  5. foo()
  6. print x

  1. vim foo.py
  2. #!/usr/bin/env python
  3. x = 3
  4. y = 4
  5. _z = 5

  1. >>> from foo import *
  2. >>> x
  3. 3
  4. >>> y
  5. 4
  6. >>> _z
  7. Traceback (most recent call last):
  8. File "<stdin>", line 1, in <module>
  9. NameError: name '_z' is not defined
  1. >>> from time import ctime
  2. >>> ctime()
  3. 'Tue Nov 29 17:11:26 2016'
  4. >>> import os, sys
  5. >>> import random as rdm
  6. >>> rdm.choice('hello')
  7. 'l'
从ZIP文件中导入模块
  1. [root@localhost bin]# ls
  2. foo.py foo.pyc
  3. [root@localhost bin]# zip abc.zip foo.py
  4. adding: foo.py (deflated 2%)
  5. [root@localhost bin]# python
  6. Python 2.6.6 (r266:84292, Feb 22 2013, 00:00:18)
  7. [GCC 4.4.7 20120313 (Red Hat 4.4.7-3)] on linux2
  8. Type "help", "copyright", "credits" or "license" for more information.
  9. >>> import sys
  10. >>> sys.path
  11. ['', '/usr/lib64/python26.zip', '/usr/lib64/python2.6', '/usr/lib64/python2.6/plat-linux2', '/usr/lib64/python2.6/lib-tk', '/usr/lib64/python2.6/lib-old', '/usr/lib64/python2.6/lib-dynload', '/usr/lib64/python2.6/site-packages', '/usr/lib64/python2.6/site-packages/gtk-2.0', '/usr/lib/python2.6/site-packages']
  12. >>> sys.path.append('/roo/bin/abc.zip')
  13. >>> import foo
2、搜索路径
>>> sys.path    //查看加载模块时所要搜索的路径
>>> sys.path.append('/root/bin')    //追加搜索路径

3、名称空间
程序运行的时候,会有二或在三个名称空间。一旦python运行,就会加载内建所加载全局名称空间,当函数运行的时候,再加载局部名称空间。

4、名称查找顺序
首先从局部名称空间查找,没有找到则查找全局名称空间,最好后查找内建名称

5、加载模块的注意事项
(1)导入模块在加载的时候,顶层代码会执行
(2) 无论模块被导入(import)多少次,只会被 加载(load)一次。
(3)支持从zip文件中导入模块。如存在一个zip文件/root/abc.zip。   abc.zip文件foo.py,那么导入时应该执行:
>>> import sys
>>> sys.path.append('/root/abc.zip')

二、包
1、可以认 为包是特殊的模块。包是一个层次的目录结构。
2、把一些模块文件存到一个文件夹中,该文件夹不会自动成为一个包。必须在该文件夹下创建一个名为__init__.py的文件(即使这个文件是空的)。
3、包里面还可以有子包(子目录),每个子目录也必须有相关的__init__.py
4、导入包中的模块使用的语法是:
>>> import  包.子包.模块

练习:
实现操作文件的备份。既要支持完全备份,也要支持增量备份。比如,/home/demo/src要备份的目录,/home/demo/dst是备份目标目录。要求备份的数据节省内存空间
1、实现压缩操作
比如,将/home/demo/目录压缩成 /home/demo.tar.gz
  1. >>> import tab
  2. >>> import tarfile
  3. >>> tar = tarfile.open('/home/demo.tar.gz', 'w:gz')
  4. >>> tar.add('/home/demo')
  5. >>> tar.close()
如果逐个文件压缩
  1. >>> import tab
  2. >>> import tarfile
  3. >>> tar = tarfile.open('/home/demo.tar.gz', 'w:gz')
  4. >>> tar.add('/home/demo')
  5. >>> tar.close()
 2、备份后的文件名,希望它的格式为full_src_日期.tar.gz / incr_src_日期.tar.gz
  1. >>> import tarfile
  2. >>> import time
  3. >>> time.strftime('%Y%m%d')
  4. '20161130'
  5. >>> filename = 'full_src_' + time.strftime('%Y%m%d') + '.tar.gz'
  6. >>> tar = tarfile.open('/home/%s' % filename, 'w:gz')
  7. >>> tar.close()
3、检查文件是否有发动,可以计算文件的md5值。计算md5值的时候,注意 如果一个文件太大,直接读进来会消耗太大的内在。所以每次读取较小的数据,然后再更新MD5值。
  1. >>> import tarfile
  2. >>> f = file('/home/demo/passwd')
  3. >>> import hashlib
  4. >>> m = hashlib.md5()
  5. >>> while True:
  6. ... a = f.read(1000)
  7. ... if len(a) == 0:
  8. ... break
  9. ... m.update(a)
  10. ...
  11. >>> f.close()
  12. >>> m.hexdigest()
  13. '2a57f5d5a9fc0e1bc07d81261bef6b44'
数值推荐4096字节

练习代码,星期一开始完整备份,其他增量备份
  1. #!/usr/bin/env python
  2. import time
  3. import os
  4. import tarfile
  5. import hashlib
  6. import cPickle as p
  7. basedir = '/home/demo'
  8. srcdir = 'src'
  9. dstdir = 'dst'
  10. fullname = 'full_%s_%s.tar.gz' % (srcdir, time.strftime('%Y%m%d'))
  11. incrname = 'incr_%s_%s.tar.gz' % (srcdir, time.strftime('%Y%m%d'))
  12. md5file = 'md5.data'
  13. def fullbackup():
  14. md5dict = {}
  15. filelist = os.listdir(os.path.join(basedir, srcdir))
  16. for i in filelist:
  17. md5dict[i] = md5sum(os.path.join(basedir, srcdir, i))
  18. with file(os.path.join(basedir, dstdir, md5file), 'w') as f:
  19. p.dump(md5dict, f)
  20. tar = tarfile.open(os.path.join(basedir, dstdir, fullname), 'w:gz')
  21. os.chdir(basedir)
  22. tar.add(srcdir)
  23. tar.close()
  24. def incrbackup():
  25. newmd5 = {}
  26. filelist = os.listdir(os.path.join(basedir, srcdir))
  27. for i in filelist:
  28. newmd5[i] = md5sum(os.path.join(basedir, srcdir, i))
  29. with file(os.path.join(basedir, dstdir, md5file)) as f:
  30. storedmd5 = p.load(f)
  31. tar = tarfile.open(os.path.join(basedir, dstdir, incrname), 'w:gz')
  32. os.chdir(basedir)
  33. for i in newmd5:
  34. if (i not in storedmd5) or (newmd5[i] != storedmd5[i]):
  35. tar.add(os.path.join(srcdir, i))
  36. tar.close()
  37. with file(os.path.join(basedir, dstdir, md5file), 'w') as f:
  38. p.dump(newmd5, f)
  39. def md5sum(fname):
  40. m = hashlib.md5()
  41. with file(fname) as f:
  42. while True:
  43. data = f.read(4096)
  44. if len(data) == 0:
  45. break
  46. m.update(data)
  47. return m.hexdigest()
  48. def main():
  49. if time.strftime('%a') == 'Mon':
  50. fullbackup()
  51. else:
  52. incrbackup()
  53. if __name__ == '__main__':
  54. main()

 




posted @ 2016-12-19 14:27  Final233  阅读(222)  评论(0编辑  收藏  举报