python模块

2.17.0.1. Example 2-29. 使用 random 模块获得随机数字 File: random-example-1.py
import random
for i in range(5):

# random float: 0.0 <= number < 1.0 print random.random(), # random float: 10 <= number < 20 print random.uniform(10, 20), # random integer: 100 <= number <= 1000 print random.randint(100, 1000), # random integer: even numbers in 100 <= number < 1000 print random.randrange(100, 1000, 2) 0.946842713956 19.5910069381 709 172 0.573613195398 16.2758417025 407 120 0.363241598013 16.8079747714 916 580 0.602115173978 18.386796935 531 774 0.526767588533 18.0783794596 223 344 注意这里的 randint 函数可以返回上界, 所有函数都有可能返回下界值. 而其他函数总是返回小于上界的值. Example 2-30 展示了 choice 函数, 它用来从一个序列里分拣出一个随机项目. 它可以用于列表, 元组, 以及其他序列(当然, 非空的). 2.17.0.2. Example 2-30. 使用 random 模块从序列取出随机项 File: random-example-2.py import random # random choice from a list for i in range(5): print random.choice([1, 2, 3, 5, 9]) 2 3 1 9 1 在 2.0 及以后版本, shuffle 函数可以用于打乱一个列表的内容 (也就是生成 一个该列表的随机全排列). Example 2-31 展示了如何在旧版本中实现该函数. 2.17.0.3. Example 2-31. 使用 random 模块打乱一副牌 File: random-example-4.py import random try: # available in 2.0 and later shuffle = random.shuffle except AttributeError: def shuffle(x): for i in xrange(len(x)-1, 0, -1): # pick an element in x[:i+1] with which to exchange x[i] j = int(random.random() * (i+1)) x[i], x[j] = x[j], x[i] cards = range(52) shuffle(cards) myhand = cards[:5] print myhand [4, 8, 40, 12, 30] random 模块也包含了非恒定分布的随机生成器函数. Example 2-32 使用了 gauss (高斯)函数来生成满足高斯分的布随机数字. 2.17.0.4. Example 2-32. 使用 random 模块生成高斯分布随机数 File: random-example-3.py import random histogram = [0] * 20 # calculate histogram for gaussian # noise, using average=5, stddev=1 for i in range(1000): i = int(random.gauss(5, 1) * 2) histogram[i] = histogram[i] + 1 # print the histogram m = max(histogram) for v in histogram: print "*" * (v * 50 / m) **** ********** ************************* *********************************** ************************************************ ************************************************** ************************************* *************************** ************* *** * 你可以在 Python Library Reference 找到更多关于非恒定分布随机生成器函数 的信息. 标准库中提供的随机数生成器都是伪随机数生成器. 不过这对于很多目的来说 已经足够了, 比如模拟, 数值分析, 以及游戏. 可以确定的是它不适合密码学 用途. 2.18. whrandom 模块 这个模块早在 2.1 就被声明不赞成, 早废了. 请使用 random 代替. - Feather Example 2-33 展示了 whrandom , 它提供了一个伪随机数生成器. (基于 Wichmann 和 Hill, 1982 的数学运算理论). 除非你需要不共享状态的多个生 成器(如多线程程序), 请使用 random 模块代替. 2.18.0.1. Example 2-33. 使用 whrandom 模块 File: whrandom-example-1.py import whrandom # same as random print whrandom.random() print whrandom.choice([1, 2, 3, 5, 9]) print whrandom.uniform(10, 20) print whrandom.randint(100, 1000) 0.113412062346  1 16.8778954689 799 Example 2-34 展示了如何使用 whrandom 类实例创建多个生成器. 2.18.0.2. Example 2-34. 使用 whrandom 模块创建多个随机生成器 File: whrandom-example-2.py import whrandom # initialize all generators with the same seed rand1 = whrandom.whrandom(4,7,11) rand2 = whrandom.whrandom(4,7,11) rand3 = whrandom.whrandom(4,7,11) for i in range(5): print rand1.random(), rand2.random(), rand3.random() 0.123993532536 0.123993532536 0.123993532536 0.180951499518 0.180951499518 0.180951499518 0.291924111809 0.291924111809 0.291924111809 0.952048889363 0.952048889363 0.952048889363 0.969794283643 0.969794283643 0.969794283643 2.19. md5 模块 md5 (Message-Digest Algorithm 5)模块用于计算信息密文(信息摘要). md5 算法计算一个强壮的 128 位密文. 这意味着如果两个字符串是不同的, 那 么有极高可能它们的 md5 也不同. 也就是说, 给定一个 md5 密文, 那么几乎 没有可能再找到另个字符串的密文与此相同. Example 2-35 展示了如何使用 md5 模块. 2.19.0.1. Example 2-35. 使用 md5 模块 File: md5-example-1.py import md5 hash = md5.new() hash.update("spam, spam, and eggs")  print repr(hash.digest()) 'L\005J\243\266\355\243u`\305r\203\267\020F\303' 注意这里的校验和是一个二进制字符串. Example 2-36 展示了如何获得一个十 六进制或 base64 编码的字符串. 2.19.0.2. Example 2-36. 使用 md5 模块获得十六进制或 base64 编码的 md5 值 File: md5-example-2.py import md5 import string import base64 hash = md5.new() hash.update("spam, spam, and eggs") value = hash.digest() print hash.hexdigest() # before 2.0, the above can be written as # 在 2.0 前, 以上应该写做: # print string.join(map(lambda v: "%02x" % ord(v), value), "") print base64.encodestring(value) 4c054aa3b6eda37560c57283b71046c3 TAVKo7bto3VgxXKDtxBGww== Example 2-37 展示了如何使用 md5 校验和来处理口令的发送与应答的验证(不 过我们将稍候讨论这里使用随机数字所带来的问题). 2.19.0.3. Example 2-37. 使用 md5 模块来处理口令的发送与应答的验证 File: md5-example-3.py import md5 import string, random def getchallenge(): # generate a 16-byte long random string. (note that the built- # in pseudo-random generator uses a 24-bit seed, so this is not # as good as it may seem...) # 生成一个 16 字节长的随机字符串. 注意内建的伪随机生成器 # 使用的是 24 位的种子(seed), 所以这里这样用并不好.. challenge = map(lambda i: chr(random.randint(0, 255)), range(16)) return string.join(challenge, "") def getresponse(password, challenge): # calculate combined digest for password and challenge # 计算密码和质询(challenge)的联合密文 m = md5.new() m.update(password) m.update(challenge) return m.digest() # # server/client communication # 服务器/客户端通讯 # 1. client connects. server issues challenge. # 1. 客户端连接, 服务器发布质询(challenge) print "client:", "connect" challenge = getchallenge() print "server:", repr(challenge) # 2. client combines password and challenge, and calculates # the response. # 2. 客户端计算密码和质询(challenge)的组合后的密文 client_response = getresponse("trustno1", challenge) print "client:", repr(client_response) # 3. server does the same, and compares the result with the # client response. the result is a safe login in which the # password is never sent across the communication channel. # 3. 服务器做同样的事, 然后比较结果与客户端的返回, # 判断是否允许用户登陆. 这样做密码没有在通讯中明文传输. server_response = getresponse("trustno1", challenge) if server_response == client_response: print "server:", "login ok" client: connect server: '\334\352\227Z#\272\273\212KG\330\265\032>\311o’ client: “l’\305\240-x\245\237\035\225A\254\233\337\225\001” server: login ok
Example 2-38 提供了 md5 的一个变种, 你可以通过标记信息来判断它是否在 网络传输过程中被修改(丢失).
2.19.0.4. Example 2-38. 使用 md5 模块检查数据完整性 File: md5-example-4.py
import md5
import array
class HMAC_MD5:
# keyed md5 message authentication
def _ _init_ _(self, key):
if len(key) > 64:
key = md5.new(key).digest()
ipad = array.array(“B”, [0x36] * 64)
opad = array.array(“B”, [0x5C] * 64)
for i in range(len(key)):
ipad[i] = ipad[i] ^ ord(key[i])
opad[i] = opad[i] ^ ord(key[i])
self.ipad = md5.md5(ipad.tostring())
self.opad = md5.md5(opad.tostring())
def digest(self, data):
ipad = self.ipad.copy()
opad = self.opad.copy()
ipad.update(data)
opad.update(ipad.digest())
return opad.digest()
#
# simulate server end # 模拟服务器端
key = “this should be a well-kept secret”
message = open(“samples/sample.txt”).read()
signature = HMAC_MD5(key).digest(message)
# (send message and signature across a public network) # (经过由网络发送信息和签名)
#
# simulate client end #模拟客户端
key = “this should be a well-kept secret”
client_signature = HMAC_MD5(key).digest(message)
if client_signature == signature:
print “this is the original message:”
print
print message
else:
print “someone has modified the message!!!”
copy 方法会对这个内部对象状态做一个快照( snapshot ). 这允许你预先计算 部分密文摘要(例如 Example 2-38 中的 padded key).
该算法的细节请参阅 HMAC-MD5:Keyed-MD5 for Message Authentication
( http://www.research.ibm.com/security/draft-ietf-ipsec-hmac-md5-00.t xt ) by Krawczyk, 或其他.
千万别忘记内建的伪随机生成器对于加密操作而言并不合适. 千万小心.
2.20. sha 模块
sha 模块提供了计算信息摘要(密文)的另种方法, 如 Example 2-39 所示. 它 与 md5 模块类似, 但生成的是 160 位签名.
2.20.0.1. Example 2-39. 使用 sha 模块 File: sha-example-1.py
import sha
hash = sha.new()
hash.update(“spam, spam, and eggs”)
print repr(hash.digest())

print hash.hexdigest()
‘\321\333\003\026I\331\272-j\303\247\240\345\343Tvq\364\346\311’ d1db031649d9ba2d6ac3a7a0e5e3547671f4e6c9
关于 sha 密文的使用, 请参阅 md5 中的例子.
2.21. crypt 模块
(可选, 只用于 Unix) crypt 模块实现了单向的 DES 加密, Unix 系统使用这个 加密算法来储存密码, 这个模块真正也就只在检查这样的密码时有用.
Example 2-40 展示了如何使用 crypt.crypt 来加密一个密码, 将密码和 salt 组合起来然后传递给函数, 这里的 salt 包含两位随机字符. 现在你可以扔掉 原密码而只保存加密后的字符串了.
2.21.0.1. Example 2-40. 使用 crypt 模块 File: crypt-example-1.py
import crypt
import random, string
def getsalt(chars = string.letters + string.digits):
# generate a random 2-character ‘salt’
# 生成随机的 2 字符 ‘salt’
return random.choice(chars) + random.choice(chars)
print crypt.crypt(“bananas”, getsalt())
‘py8UGrijma1j6’
确认密码时, 只需要用新密码调用加密函数, 并取加密后字符串的前两位作为 salt 即可. 如果结果和加密后字符串匹配, 那么密码就是正确的. Example 2-41 使用 pwd 模块来获取已知用户的加密后密码.
2.21.0.2. Example 2-41. 使用 crypt 模块身份验证 File: crypt-example-2.py
import pwd, crypt

def login(user, password):
“Check if user would be able to log in using password”
try:
pw1 = pwd.getpwnam(user)[1]
pw2 = crypt.crypt(password, pw1[:2])
return pw1 == pw2
except KeyError:
return 0 # no such user
user = raw_input(“username:”)
password = raw_input(“password:”)
if login(user, password):
print “welcome”, user
else:
print “login failed”
关于其他实现验证的方法请参阅 md5 模块一节.
2.22. rotor 模块
这个模块在 2.3 时被声明不赞成, 2.4 时废了. 因为它的加密算法不安全. – Feather
(可选) rotor 模块实现了一个简单的加密算法. 如 Example 2-42 所示. 它的 算法基于 WWII Enigma engine.
2.22.0.1. Example 2-42. 使用 rotor 模块 File: rotor-example-1.py
import rotor
SECRET_KEY = “spam”
MESSAGE = “the holy grail”
r = rotor.newrotor(SECRET_KEY)
encoded_message = r.encrypt(MESSAGE)
decoded_message = r.decrypt(encoded_message)

print “original:”, repr(MESSAGE)
print “encoded message:”, repr(encoded_message)
print “decoded message:”, repr(decoded_message)
original: ‘the holy grail’
encoded message: ‘\227\271\244\015\305sw\3340\337\252\237\340U’ decoded message: ‘the holy grail’
2.23. zlib 模块
(可选) zlib 模块为 “zlib” 压缩提供支持. (这种压缩方法是 “deflate”.)
Example 2-43 展示了如何使用 compress 和 decompress 函数接受字符串参 数.
2.23.0.1. Example 2-43. 使用 zlib 模块压缩字符串 File: zlib-example-1.py
import zlib
MESSAGE = “life of brian”
compressed_message = zlib.compress(MESSAGE)
decompressed_message = zlib.decompress(compressed_message)
print “original:”, repr(MESSAGE)
print “compressed message:”, repr(compressed_message)
print “decompressed message:”, repr(decompressed_message)
original: ‘life of brian’
compressed message: ‘x\234\313\311LKU\310OSH*\312L\314\003\000!\010\004\302’ decompressed message: ‘life of brian’
文件的内容决定了压缩比率, Example 2-44 说明了这点. 2.23.0.2. Example 2-44. 使用 zlib 模块压缩多个不同类型文件 File: zlib-example-2.py
import zlib
import glob

for file in glob.glob(“samples/*”):
indata = open(file, “rb”).read()
outdata = zlib.compress(indata, zlib.Z_BEST_COMPRESSION)
print file, len(indata), “=>”, len(outdata),
print “%d%%” % (len(outdata) * 100 / len(indata))
samples\sample.au 1676 => 1109 66% samples\sample.gz 42 => 51 121% samples\sample.htm 186 => 135 72% samples\sample.ini 246 => 190 77% samples\sample.jpg 4762 => 4632 97% samples\sample.msg 450 => 275 61% samples\sample.sgm 430 => 321 74% samples\sample.tar 10240 => 125 1% samples\sample.tgz 155 => 159 102% samples\sample.txt 302 => 220 72% samples\sample.wav 13260 => 10992 82%
你也可以实时地压缩或解压缩数据, 如 Example 2-45 所示. 2.23.0.3. Example 2-45. 使用 zlib 模块解压缩流
File: zlib-example-3.py
import zlib
encoder = zlib.compressobj()
data = encoder.compress(“life”)
data = data + encoder.compress(” of “)
data = data + encoder.compress(“brian”)
data = data + encoder.flush()
print repr(data)
print repr(zlib.decompress(data))
‘x\234\313\311LKU\310OSH*\312L\314\003\000!\010\004\302’ ‘life of brian’
Example 2-46 把解码对象封装到了一个类似文件对象的类中, 实现了一些文件 对象的方法, 这样使得读取压缩文件更方便.
2.23.0.4. Example 2-46. 压缩流的仿文件访问方式 File: zlib-example-4.py
import zlib
import string, StringIO
class ZipInputStream:
def _ _init_ _(self, file):
self.file = file
self._ _rewind()
def _ _rewind(self):
self.zip = zlib.decompressobj()
self.pos = 0 # position in zipped stream
self.offset = 0 # position in unzipped stream
self.data = “”
def _ _fill(self, bytes):
if self.zip:
# read until we have enough bytes in the buffer
while not bytes or len(self.data) < bytes: self.file.seek(self.pos) data = self.file.read(16384) if not data: self.data = self.data + self.zip.flush() self.zip = None # no more data break self.pos = self.pos + len(data) self.data = self.data + self.zip.decompress(data) def seek(self, offset, whence=0): if whence == 0: position = offset elif whence == 1: position = self.offset + offset else: raise IOError, "Illegal argument" if position < self.offset: raise IOError, "Cannot seek backwards" # skip forward, in 16k blocks while position > self.offset:
if not self.read(min(position – self.offset, 16384)):
break
def tell(self):
return self.offset
def read(self, bytes = 0):
self._ _fill(bytes)
if bytes:
data = self.data[:bytes]
self.data = self.data[bytes:]
else:
data = self.data
self.data = “”
self.offset = self.offset + len(data)
return data
def readline(self):
# make sure we have an entire line
while self.zip and “\n” not in self.data:
self._ _fill(len(self.data) + 512)
i = string.find(self.data, “\n”) + 1
if i <= 0: return self.read() return self.read(i) def readlines(self): lines = [] while 1: s = self.readline() if not s: break lines.append(s) return lines # # try it out data = open("samples/sample.txt").read() data = zlib.compress(data) file = ZipInputStream(StringIO.StringIO(data)) for line in file.readlines(): print line[:-1] We will perhaps eventually be writing only small modules which are identified by name as they are used to build larger ones, so that devices like indentation, rather than delimiters, might become feasible for expressing local structure in the source language. -- Donald E. Knuth, December 1974 2.24. code 模块 code 模块提供了一些用于模拟标准交互解释器行为的函数. compile_command 与内建 compile 函数行为相似, 但它会通过测试来保证你传 递的是一个完成的 Python 语句. 在 Example 2-47 中, 我们一行一行地编译一个程序, 编译完成后会执行所得 到的代码对象 (code object). 程序代码如下: a= ( 1, 2, 3 ) print a 注意只有我们到达第 2 个括号, 元组的赋值操作能编译完成. 2.24.0.1. Example 2-47. 使用 code 模块编译语句 File: code-example-1.py import code import string # SCRIPT = [ "a = (", " 1,", " 2,", " 3 ", ")", "print a"  ] script = "" for line in SCRIPT: script = script + line + "\n" co = code.compile_command(script, "“, “exec”)
if co:
# got a complete statement. execute it!
print “-“*40
print script,
print “-“*40
exec co
script = “”
—————————————- a=(
1, 2, 3
) —————————————- —————————————- print a —————————————- (1, 2, 3)
InteractiveConsole 类实现了一个交互控制台, 类似你启动的 Python 解释器 交互模式.
控制台可以是活动的(自动调用函数到达下一行) 或是被动的(当有新数据时调 用 push 方法). 默认使用内建的 raw_input 函数. 如果你想使用另个输入函 数, 你可以使用相同的名称重载这个方法. Example 2-48 展示了如何使用 code 模块来模拟交互解释器.
2.24.0.2. Example 2-48. 使用 code 模块模拟交互解释器
File: code-example-2.py
import code
console = code.InteractiveConsole()
console.interact()
Python 1.5.2
Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam (InteractiveConsole)
>>> a = (
… 1,
… 2,
… 3
… )
>>> print a
(1, 2, 3)
Example 2-49 中的脚本定义了一个 keyboard 函数. 它允许你在程序中手动控 制交互解释器.
2.24.0.3. Example 2-49. 使用 code 模块实现简单的 Debugging
File: code-example-3.py
def keyboard(banner=None):
import code, sys
# use exception trick to pick up the current frame
try:
raise None
except:
frame = sys.exc_info()[2].tb_frame.f_back
# evaluate commands in current namespace
namespace = frame.f_globals.copy()
namespace.update(frame.f_locals)
code.interact(banner=banner, local=namespace)
def func():
print “START”
a = 10
keyboard()
print “END”
func()
START
Python 1.5.2
Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam (InteractiveConsole)
>>> print a
10
>>> print keyboard
^Z
END

Posted in 未分类