python-08
一、内部函数:在一个函数的内部包含另一个函数
#!/usr/bin/env python
def foo():
def bar():
print 'hello world'
bar()
foo()
以上程序可以执行,但是如果在主程序中直接调用bar()会失败
或
a代表bar()别名
#!/usr/bin/env python
def foo():
def bar():
print 'hello world'
return bar
a = foo()
a()
二、闭包
例: 我们需要使用多个计数器,这些技术器起始值不一样。希望只使用一个装饰器的功能,那么就可以使用闭包的技术:
#!/usr/bin/env python
def counter(start_at = 0):
count = [start_at]
def incr():
count[0] += 1
return count[0]
return incr
a = counter()
print a()
print a()
print a()
print a()
b = counter(10)
print b()
print b()
print a()
print b()
三、偏函数
可以为某些函数提供默认参数。
>>> from operator import add, mul
>>> from functools import partial
>>> add(10, 4)
14
>>> add10 = partial(add, 10)
>>> add10(4)
14
>>> mul(2, 8)
16
>>> mul2 = partial(mul, 2)
>>> mul2(8)
16
例2:
为图形界面中的按钮设置默认的前景色、背景色等
安装Tkinter
#yum install -y tkinter
#!/usr/bin/env python
import Tkinter
from functools import partial
root = Tkinter.Tk()
mybutton = partial(Tkinter.Button, root, fg = 'white', bg = 'blue')
b1 = mybutton(text = 'button 1')
b2 = mybutton(text = 'button 2')
bq = mybutton(text = 'QUIT', bg = 'red', command = root.quit)
b1.pack()
b2.pack()
bq.pack(fill = Tkinter.X, expand = True)
root.title('test!')
root.mainloop()
四、装饰器
考虑以下代码:当执行一个函数或程序的时候,希望知道它是什么时候开始,什么时候结束
#!/usr/bin/env python
import time
def loop2(n = 10):
time.sleep(1)
mylist = []
for i in range(n):
if i % 2:
mylist.append(i)
return mylist
print 'loop start at: ', time.ctime()
print loop2()
通过以上的修改如果有新的函数需要知道开始、结束的时间,就可以把新的函数使用以上的方法,会改变原始函数的名字。所以就有了装饰器的用法。
#!/usr/bin/env python
import time
def deco(func):
def timeit(n = 10):
print 'prog start at: ', time.ctime()
newlist = func(n)
print 'prog done at: ', time.ctime()
return newlist
return timeit
@deco
def loop(n = 10):
time.sleep(1)
mylist = []
for i in range(n):
if i % 2:
mylist.append(i)
return mylist
print loop()
print loop(5)
一、模块
1、模块是以逻辑的方式组成的python代码,物理表现形式是文件。如果一个py或ZIP为扩展名,那么该文件也就可以当成模块导入了
全局作用域
#!/usr/bin/env python
x = 3
def foo():
print x
foo()
局部作用域 会报错
#!/usr/bin/env python
def foo():
x = 3
foo()
print x
全局、局部作用域
#!/usr/bin/env python
x = 3
def foo():
x = 4
foo()
print x
vim foo.py
#!/usr/bin/env python
x = 3
y = 4
_z = 5
>>> from foo import *
>>> x
3
>>> y
4
>>> _z
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name '_z' is not defined
>>> from time import ctime
>>> ctime()
'Tue Nov 29 17:11:26 2016'
>>> import os, sys
>>> import random as rdm
>>> rdm.choice('hello')
'l'
从ZIP文件中导入模块
[root@localhost bin]# ls
foo.py foo.pyc
[root@localhost bin]# zip abc.zip foo.py
adding: foo.py (deflated 2%)
[root@localhost bin]# python
Python 2.6.6 (r266:84292, Feb 22 2013, 00:00:18)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', '/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']
>>> sys.path.append('/roo/bin/abc.zip')
>>> 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
>>> import tab
>>> import tarfile
>>> tar = tarfile.open('/home/demo.tar.gz', 'w:gz')
>>> tar.add('/home/demo')
>>> tar.close()
如果逐个文件压缩
>>> import tab
>>> import tarfile
>>> tar = tarfile.open('/home/demo.tar.gz', 'w:gz')
>>> tar.add('/home/demo')
>>> tar.close()
2、备份后的文件名,希望它的格式为full_src_日期.tar.gz / incr_src_日期.tar.gz
>>> import tarfile
>>> import time
>>> time.strftime('%Y%m%d')
'20161130'
>>> filename = 'full_src_' + time.strftime('%Y%m%d') + '.tar.gz'
>>> tar = tarfile.open('/home/%s' % filename, 'w:gz')
>>> tar.close()
3、检查文件是否有发动,可以计算文件的md5值。计算md5值的时候,注意 如果一个文件太大,直接读进来会消耗太大的内在。所以每次读取较小的数据,然后再更新MD5值。
>>> import tarfile
>>> f = file('/home/demo/passwd')
>>> import hashlib
>>> m = hashlib.md5()
>>> while True:
... a = f.read(1000)
... if len(a) == 0:
... break
... m.update(a)
...
>>> f.close()
>>> m.hexdigest()
'2a57f5d5a9fc0e1bc07d81261bef6b44'
数值推荐4096字节
练习代码,星期一开始完整备份,其他增量备份
#!/usr/bin/env python
import time
import os
import tarfile
import hashlib
import cPickle as p
basedir = '/home/demo'
srcdir = 'src'
dstdir = 'dst'
fullname = 'full_%s_%s.tar.gz' % (srcdir, time.strftime('%Y%m%d'))
incrname = 'incr_%s_%s.tar.gz' % (srcdir, time.strftime('%Y%m%d'))
md5file = 'md5.data'
def fullbackup():
md5dict = {}
filelist = os.listdir(os.path.join(basedir, srcdir))
for i in filelist:
md5dict[i] = md5sum(os.path.join(basedir, srcdir, i))
with file(os.path.join(basedir, dstdir, md5file), 'w') as f:
p.dump(md5dict, f)
tar = tarfile.open(os.path.join(basedir, dstdir, fullname), 'w:gz')
os.chdir(basedir)
tar.add(srcdir)
tar.close()
def incrbackup():
newmd5 = {}
filelist = os.listdir(os.path.join(basedir, srcdir))
for i in filelist:
newmd5[i] = md5sum(os.path.join(basedir, srcdir, i))
with file(os.path.join(basedir, dstdir, md5file)) as f:
storedmd5 = p.load(f)
tar = tarfile.open(os.path.join(basedir, dstdir, incrname), 'w:gz')
os.chdir(basedir)
for i in newmd5:
if (i not in storedmd5) or (newmd5[i] != storedmd5[i]):
tar.add(os.path.join(srcdir, i))
tar.close()
with file(os.path.join(basedir, dstdir, md5file), 'w') as f:
p.dump(newmd5, f)
def md5sum(fname):
m = hashlib.md5()
with file(fname) as f:
while True:
data = f.read(4096)
if len(data) == 0:
break
m.update(data)
return m.hexdigest()
def main():
if time.strftime('%a') == 'Mon':
fullbackup()
else:
incrbackup()
if __name__ == '__main__':
main()