库和扩展常见问题解答 — Python 文档

来自菜鸟教程
Python/docs/2.7/faq/library
跳转至:导航、​搜索

库和扩展常见问题解答

内容


一般图书馆问题

我如何找到一个模块或应用程序来执行任务 X?

检查 库参考 以查看是否有相关的标准库模块。 (最终,您将了解标准库中的内容,并且可以跳过此步骤。)

对于第三方包,搜索 Python 包索引 或尝试 Google 或其他网络搜索引擎。 搜索“Python”加上您感兴趣的主题的一两个关键字通常会找到有用的东西。


math.py(socket.py、regex.py 等)源文件在哪里?

如果找不到模块的源文件,它可能是用 C、C++ 或其他编译语言实现的内置或动态加载的模块。 在这种情况下,您可能没有源文件,或者它可能类似于 mathmodule.c,位于 C 源目录中的某处(不在 Python 路径上)。

Python中有(至少)三种模块:

  1. 用 Python (.py) 编写的模块;

  2. 用 C 编写并动态加载的模块(.dll、.pyd、.so、.sl 等);

  3. 用 C 语言编写并与解释器链接的模块; 要获取这些列表,请键入:

    import sys
    print sys.builtin_module_names


如何使 Python 脚本在 Unix 上可执行?

您需要做两件事:脚本文件的模式必须是可执行的,并且第一行必须以 #! 开头,后跟 Python 解释器的路径。

第一个是通过执行 chmod +x scriptfile 或 chmod 755 scriptfile 来完成的。

第二种可以通过多种方式完成。 最直接的方法是写

#!/usr/local/bin/python

作为文件的第一行,使用 Python 解释器在您的平台上安装位置的路径名。

如果您希望脚本独立于 Python 解释器所在的位置,您可以使用 env 程序。 几乎所有 Unix 变体都支持以下内容,假设 Python 解释器位于用户的 PATH 目录中:

#!/usr/bin/env python

不要 为 CGI 脚本执行此操作。 CGI 脚本的 PATH 变量通常非常小,因此您需要使用解释器的实际绝对路径名。

偶尔,某个用户的环境太满导致/usr/bin/env程序失败; 或者根本没有 env 程序。 在这种情况下,您可以尝试以下 hack(由于 Alex Rezinsky):

#! /bin/sh
""":"
exec python $0 ${1+"$@"}
"""

次要缺点是它定义了脚本的 __doc__ 字符串。 但是,您可以通过添加来解决这个问题

__doc__ = """...Whatever..."""

是否有适用于 Python 的 curses/termcap 包?

对于 Unix 变体,标准的 Python 源代码分发在 :source:`Modules` 子目录中带有一个 curses 模块,尽管它不是默认编译的。 (请注意,这在 Windows 发行版中不可用 - Windows 没有 Curses 模块。)

curses 模块支持基本的 curses 功能以及来自 ncurses 和 SYSV curses 的许多附加功能,例如颜色、替代字符集支持、pads 和鼠标支持。 这意味着该模块与只有 BSD 诅咒的操作系统不兼容,但似乎没有任何当前维护的操作系统属于这一类。

对于 Windows:使用 控制台库模块 。


Python 中是否有等效于 C 的 onexit() ?

atexit模块提供了类似于C的onexit()的寄存器功能。


为什么我的信号处理程序不起作用?

最常见的问题是使用错误的参数列表声明了信号处理程序。 它被称为

handler(signum, frame)

所以它应该用两个参数声明:

def handler(signum, frame):
    ...

常见任务

如何测试 Python 程序或组件?

Python 带有两个测试框架。 doctest 模块在模块的文档字符串中查找示例并运行它们,将输出与文档字符串中给出的预期输出进行比较。

unittest 模块是一个更高级的测试框架,它以 Java 和 Smalltalk 测试框架为模型。

为了使测试更容易,您应该在程序中使用良好的模块化设计。 你的程序应该几乎所有的功能都封装在函数或类方法中——这有时会产生令人惊讶和愉快的效果,使程序运行得更快(因为局部变量访问比全局访问更快)。 此外,程序应该避免依赖于变异的全局变量,因为这使得测试变得更加困难。

你程序的“全局主逻辑”可能很简单

if __name__ == "__main__":
    main_logic()

在程序主模块的底部。

一旦你的程序被组织成一个易于处理的函数和类行为的集合,你应该编写测试函数来练习这些行为。 自动化一系列测试的测试套件可以与每个模块相关联。 这听起来像很多工作,但由于 Python 如此简洁和灵活,所以它非常容易。 通过与“生产代码”并行编写测试函数,您可以使编码更加愉快和有趣,因为这样可以更早地发现错误甚至设计缺陷。

不打算成为程序主要模块的“支持模块”可能包括模块的自检。

if __name__ == "__main__":
    self_test()

当外部接口不可用时,即使是与复杂外部接口交互的程序也可以通过使用在 Python 中实现的“假”接口进行测试。


如何从文档字符串创建文档?

pydoc 模块可以从 Python 源代码中的文档字符串创建 HTML。 纯粹从文档字符串创建 API 文档的另一种方法是 epydoc。 Sphinx 还可以包含文档字符串内容。


如何一次获得一个按键?

对于 Unix 变体,有几种解决方案。 使用curses 执行此操作很简单,但curses 是一个相当大的模块,需要学习。 这是一个没有诅咒的解决方案:

import termios, fcntl, sys, os
fd = sys.stdin.fileno()

oldterm = termios.tcgetattr(fd)
newattr = termios.tcgetattr(fd)
newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO
termios.tcsetattr(fd, termios.TCSANOW, newattr)

oldflags = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)

try:
    while 1:
        try:
            c = sys.stdin.read(1)
            print "Got character", repr(c)
        except IOError: pass
finally:
    termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)
    fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)

您需要 termios 和 fcntl 模块才能使其中任何一个工作,我只在 Linux 上尝试过它,尽管它应该可以在其他地方工作。 在此代码中,一次读取和打印一个字符。

termios.tcsetattr() 关闭标准输入的回显并禁用规范模式。 fcntl.fnctl() 用于获取 stdin 的文件描述符标志并将其修改为非阻塞模式。 由于在 stdin 为空时读取 stdin 会导致 IOError,因此会捕获并忽略此错误。


线程

如何使用线程编程?

请务必使用 threading 模块而不是 thread 模块。 threading 模块在 thread 模块提供的低级原语之上构建了方便的抽象。

Aahz 在他的线程教程中有一组有用的幻灯片; 见 http://www.pythoncraft.com/OSCON2001/。


我的线程似乎都没有运行:为什么?

一旦主线程退出,所有线程都会被杀死。 您的主线程运行得太快,使线程没有时间做任何工作。

一个简单的解决方法是在程序末尾添加一个足够所有线程完成的睡眠:

import threading, time

def thread_task(name, n):
    for i in range(n): print name, i

for i in range(10):
    T = threading.Thread(target=thread_task, args=(str(i), i))
    T.start()

time.sleep(10) # <----------------------------!

但是现在(在许多平台上)线程不是并行运行,而是顺序运行,一次一个! 原因是操作系统线程调度程序在前一个线程被阻塞之前不会启动新线程。

一个简单的解决方法是在 run 函数的开头添加一个小睡眠:

def thread_task(name, n):
    time.sleep(0.001) # <---------------------!
    for i in range(n): print name, i

for i in range(10):
    T = threading.Thread(target=thread_task, args=(str(i), i))
    T.start()

time.sleep(10)

与其试图为 time.sleep() 猜测一个好的延迟值,不如使用某种信号量机制。 一种想法是使用 Queue 模块创建一个队列对象,让每个线程在完成时将一个令牌附加到队列中,并让主线程从队列中读取与线程数量一样多的令牌。


如何在一堆工作线程之间分配工作?

使用 Queue 模块创建一个包含作业列表的队列。 Queue 类维护一个对象列表,并有一个 .put(obj) 方法将项目添加到队列和一个 .get() 方法返回它们。 该类将负责必要的锁定,以确保每个作业只分发一次。

这是一个简单的例子:

import threading, Queue, time

# The worker thread gets jobs off the queue.  When the queue is empty, it
# assumes there will be no more work and exits.
# (Realistically workers will run until terminated.)
def worker():
    print 'Running worker'
    time.sleep(0.1)
    while True:
        try:
            arg = q.get(block=False)
        except Queue.Empty:
            print 'Worker', threading.currentThread(),
            print 'queue empty'
            break
        else:
            print 'Worker', threading.currentThread(),
            print 'running with argument', arg
            time.sleep(0.5)

# Create queue
q = Queue.Queue()

# Start a pool of 5 workers
for i in range(5):
    t = threading.Thread(target=worker, name='worker %i' % (i+1))
    t.start()

# Begin adding work to the queue
for i in range(50):
    q.put(i)

# Give threads time to run
print 'Main thread sleeping'
time.sleep(5)

运行时,这将产生以下输出:

Running worker
Running worker
Running worker
Running worker
Running worker
Main thread sleeping
Worker <Thread(worker 1, started)> running with argument 0
Worker <Thread(worker 2, started)> running with argument 1
Worker <Thread(worker 3, started)> running with argument 2
Worker <Thread(worker 4, started)> running with argument 3
Worker <Thread(worker 5, started)> running with argument 4
Worker <Thread(worker 1, started)> running with argument 5
...

有关更多详细信息,请参阅模块的文档; Queue 类提供了一个功能强大的接口。


什么样的全局值变异是线程安全的?

内部使用 全局解释器锁 (GIL) 以确保一次在 Python VM 中仅运行一个线程。 一般来说,Python 只在字节码指令之间提供线程之间的切换; 可以通过 sys.setcheckinterval() 设置切换的频率。 因此,从 Python 程序的角度来看,每个字节码指令以及从每个指令到达的所有 C 实现代码都是原子的。

理论上,这意味着准确的记账需要对 PVM 字节码实现有准确的理解。 实际上,这意味着对“看起来原子”的内置数据类型(整数、列表、字典等)的共享变量的操作确实是。

例如,以下操作都是原子操作(L、L1、L2 是列表,D、D1、D2 是字典,x、y 是对象,i、j 是整数):

L.append(x)
L1.extend(L2)
x = L[i]
x = L.pop()
L1[i:j] = L2
L.sort()
x = y
x.field = y
D[x] = y
D1.update(D2)
D.keys()

这些不是:

i = i+1
L.append(L[-1])
L[i] = L[j]
D[x] = D[x] + 1

当其他对象的引用计数达到零时,替换其他对象的操作可能会调用这些其他对象的 __del__() 方法,这可能会影响事物。 对于字典和列表的大量更新尤其如此。 如有疑问,请使用互斥锁!


我们不能摆脱全局解释器锁吗?

全局解释器锁 (GIL) 通常被视为 Python 在高端多处理器服务器机器上部署的障碍,因为多线程 Python 程序实际上只使用一个 CPU,由于坚持(几乎) 所有 Python 代码只能在持有 GIL 时运行。

回到 Python 1.5 的时代,Greg Stein 实际上实现了一个全面的补丁集(“自由线程”补丁),它删除了 GIL 并用细粒度锁取而代之。 不幸的是,即使在 Windows(锁非常有效)上,它运行普通 Python 代码的速度也是使用 GIL 的解释器的两倍。 在 Linux 上,性能损失更严重,因为 pthread 锁效率不高。

从那以后,偶尔会出现摆脱 GIL 的想法,但没有人找到解决预期减速的方法,如果他们的代码以一半的速度运行,不使用线程的用户会不高兴。 Greg 的免费线程补丁集没有为以后的 Python 版本保持最新。

这并不意味着你不能在多 CPU 的机器上很好地使用 Python! 您只需要创造性地将工作划分到多个 进程 而不是多个 线程 。 明智地使用 C 扩展也会有所帮助; 如果您使用 C 扩展来执行耗时的任务,则该扩展可以在执行线程在 C 代码中时释放 GIL,并允许其他线程完成一些工作。

有人建议 GIL 应该是每个解释器状态的锁,而不是真正的全局锁; 然后解释器将无法共享对象。 不幸的是,这也不太可能发生。 这将是一项巨大的工作,因为目前许多对象实现都具有全局状态。 例如,缓存小整数和短字符串; 这些缓存必须移动到解释器状态。 其他对象类型有自己的空闲列表; 这些空闲列表必须移至口译状态。 等等。

而且我怀疑它甚至可以在有限的时间内完成,因为 3rd 方扩展也存在同样的问题。 很可能 3rd 方扩展的编写速度比您转换它们以将其所有全局状态存储在解释器状态中的速度要快。

最后,一旦你有多个解释器不共享任何状态,那么在单独的进程中运行每个解释器你有什么收获?


输入和输出

如何删除文件? (以及其他文件问题……)

使用 os.remove(filename) 或 os.unlink(filename); 有关文档,请参阅 os 模块。 这两个功能是相同的; unlink() 只是此函数的 Unix 系统调用的名称。

要删除目录,请使用 os.rmdir(); 使用 os.mkdir() 创建一个。 os.makedirs(path) 将在 path 中创建任何不存在的中间目录。 os.removedirs(path) 将删除中间目录,只要它们是空的; 如果要删除整个目录树及其内容,请使用 shutil.rmtree()。

要重命名文件,请使用 os.rename(old_path, new_path)。

要截断文件,请使用 f = open(filename, "r+") 打开它,然后使用 f.truncate(offset); offset 默认为当前搜索位置。 对于使用 os.open() 打开的文件,还有 os.ftruncate(fd, offset),其中 fd 是文件描述符(一个小整数)。

shutil 模块还包含许多处理文件的函数,包括 copyfile()、copytree() 和 rmtree() .


如何复制文件?

shutil 模块包含一个 copyfile() 函数。 请注意,在 MacOS 9 上,它不会复制资源分支和 Finder 信息。


如何读取(或写入)二进制数据?

要读取或写入复杂的二进制数据格式,最好使用 struct 模块。 它允许您获取包含二进制数据(通常是数字)的字符串并将其转换为 Python 对象; 反之亦然。

例如,以下代码从文件中读取两个 2 字节整数和一个大端格式的 4 字节整数:

import struct

f = open(filename, "rb")  # Open in binary mode for portability
s = f.read(8)
x, y, z = struct.unpack(">hhl", s)

格式字符串中的“>”强制大端数据; 字母“h”从字符串中读取一个“短整数”(2 个字节),而“l”从字符串中读取一个“长整数”(4 个字节)。

对于更规则的数据(例如 整数或浮点数的同类列表),您也可以使用 array 模块。


我似乎无法在用 os.popen() 创建的管道上使用 os.read(); 为什么?

os.read() 是一个低级函数,它接受一个文件描述符,一个代表打开文件的小整数。 os.popen() 创建一个高级文件对象,与内置 open() 函数返回的类型相同。 因此,要从使用 os.popen() 创建的管道 p 读取 n 字节,您需要使用 p.read(n)。


如何使用连接到输入和输出的管道运行子流程?

使用 popen2 模块。 例如:

import popen2
fromchild, tochild = popen2.popen2("command")
tochild.write("input\n")
tochild.flush()
output = fromchild.readline()

警告:通常这样做是不明智的,因为你很容易导致死锁,你的进程被阻塞等待子进程的输出,而子进程阻塞等待你的输入。 这可能是由于父级期望子级输出的文本比它输出的文本多,或者由于缺乏刷新而导致数据卡在 stdio 缓冲区中。 Python 父级当然可以在读取任何输出之前显式刷新它发送给子级的数据,但是如果子级是一个幼稚的 C 程序,它可能已经被编写为从不显式刷新其输出,即使它是交互式的,因为刷新通常是自动的。

请注意,如果您使用 popen3() 读取 stdout 和 stderr,也可能出现死锁。 如果两者之一对于内部缓冲区来说太大(增加缓冲区大小无济于事)并且您 read() 另一个第一个,也会出现死锁。

请注意 popen2 中的一个错误:除非您的程序调用 wait() 或 waitpid(),否则永远不会删除已完成的子进程,并且由于子进程数量的限制,最终对 popen2 的调用将失败。 使用 os.WNOHANG 选项调用 os.waitpid() 可以防止这种情况; 插入这样一个调用的好地方是在再次调用 popen2 之前。

在许多情况下,您真正需要的只是通过命令运行一些数据并返回结果。 除非数据量非常大,否则最简单的方法是将其写入临时文件并以该临时文件作为输入运行命令。 标准模块 tempfile 导出一个 mktemp() 函数来生成唯一的临时文件名。

import tempfile
import os

class Popen3:
    """
    This is a deadlock-safe version of popen that returns
    an object with errorlevel, out (a string) and err (a string).
    (capturestderr may not work under windows.)
    Example: print Popen3('grep spam','\n\nhere spam\n\n').out
    """
    def __init__(self,command,input=None,capturestderr=None):
        outfile=tempfile.mktemp()
        command="( %s ) > %s" % (command,outfile)
        if input:
            infile=tempfile.mktemp()
            open(infile,"w").write(input)
            command=command+" <"+infile
        if capturestderr:
            errfile=tempfile.mktemp()
            command=command+" 2>"+errfile
        self.errorlevel=os.system(command) >> 8
        self.out=open(outfile,"r").read()
        os.remove(outfile)
        if input:
            os.remove(infile)
        if capturestderr:
            self.err=open(errfile,"r").read()
            os.remove(errfile)

请注意,许多交互式程序(例如 vi) 用管道代替标准输入和输出不能很好地工作。 您将不得不使用伪 ttys(“ptys”)而不是管道。 或者您可以使用 Python 接口连接 Don Libes 的“expect”库。 与预期接口的 Python 扩展称为“expy”,可从 http://expectpy.sourceforge.net 获得。 一个像expect一样工作的纯Python解决方案是pexpect。


如何访问串行 (RS232) 端口?

对于 Win32、POSIX(Linux、BSD 等)、Jython:

对于 Unix,请参阅 Mitch Chapman 的 Usenet 帖子:

为什么不关闭 sys.stdout (stdin, stderr) 真的关闭它?

Python 文件对象是 C 流之上的高级抽象层,而 C 流又是(除其他外)低级 C 文件描述符之上的中级抽象层。

对于您通过内置的 file 构造函数在 Python 中创建的大多数文件对象,f.close() 从 Python 的角度将 Python 文件对象标记为已关闭,并安排关闭底层 C 流. 当 f 变成垃圾时,这也会在 f 的析构函数中自动发生。

但是 stdin、stdout 和 stderr 被 Python 特殊对待,因为 C 也赋予了它们特殊的地位。 运行 sys.stdout.close() 将 Python 级别的文件对象标记为已关闭,但 不会 关闭关联的 C 流。

要关闭这三个中的一个的底层 C 流,您应该首先确定这是您真正想要做的(例如,您可能会混淆尝试执行 I/O 的扩展模块)。 如果是,请使用 os.close:

os.close(0)   # close C's stdin stream
os.close(1)   # close C's stdout stream
os.close(2)   # close C's stderr stream

网络/互联网编程

有哪些适用于 Python 的 WWW 工具?

请参阅库参考手册中标题为 Internet 协议和支持 和 Internet 数据处理 的章节。 Python 有许多模块可以帮助您构建服务器端和客户端 Web 系统。

可用框架的摘要由 Paul Boddie 在 https://wiki.python.org/moin/WebProgramming 维护。

Cameron Laird 在 http://phaseit.net/claird/comp.lang.python/web_python 维护了一组关于 Python Web 技术的有用页面。


如何模拟 CGI 表单提交 (METHOD=POST)?

我想检索作为 POST 表单结果的网页。 是否有现有的代码可以让我轻松地做到这一点?

是的。 这是一个使用 httplib 的简单示例:

#!/usr/local/bin/python

import httplib, sys, time

# build the query string
qs = "First=Josephine&MI=Q&Last=Public"

# connect and send the server a path
httpobj = httplib.HTTP('www.some-server.out-there', 80)
httpobj.putrequest('POST', '/cgi-bin/some-cgi-script')
# now generate the rest of the HTTP headers...
httpobj.putheader('Accept', '*/*')
httpobj.putheader('Connection', 'Keep-Alive')
httpobj.putheader('Content-type', 'application/x-www-form-urlencoded')
httpobj.putheader('Content-length', '%d' % len(qs))
httpobj.endheaders()
httpobj.send(qs)
# find out what the server said in response...
reply, msg, hdrs = httpobj.getreply()
if reply != 200:
    sys.stdout.write(httpobj.getfile().read())

请注意,通常对于百分比编码的 POST 操作,必须使用 urllib.urlencode() 引用查询字符串。 例如,发送 name=Guy Steele, Jr.:

>>> import urllib
>>> urllib.urlencode({'name': 'Guy Steele, Jr.'})
'name=Guy+Steele%2C+Jr.'

我应该使用什么模块来帮助生成 HTML?

您可以在 Web 编程 wiki 页面 上找到一系列有用的链接。


如何从 Python 脚本发送邮件?

使用标准库模块 smtplib。

这是一个使用它的非常简单的交互式邮件发件人。 此方法适用于任何支持 SMTP 侦听器的主机。

import sys, smtplib

fromaddr = raw_input("From: ")
toaddrs  = raw_input("To: ").split(',')
print "Enter message, end with ^D:"
msg = ''
while True:
    line = sys.stdin.readline()
    if not line:
        break
    msg += line

# The actual mail send
server = smtplib.SMTP('localhost')
server.sendmail(fromaddr, toaddrs, msg)
server.quit()

仅 Unix 的替代方案使用 sendmail。 sendmail 程序的位置因系统而异; 有时是 /usr/lib/sendmail,有时是 /usr/sbin/sendmail。 sendmail 手册页将帮助您。 这是一些示例代码:

import os

SENDMAIL = "/usr/sbin/sendmail"  # sendmail location
p = os.popen("%s -t -i" % SENDMAIL, "w")
p.write("To: receiver@example.com\n")
p.write("Subject: test\n")
p.write("\n") # blank line separating headers from body
p.write("Some text\n")
p.write("some more text\n")
sts = p.close()
if sts != 0:
    print "Sendmail exit status", sts

如何避免在套接字的 connect() 方法中阻塞?

select 模块通常用于帮助处理套接字上的异步 I/O。

为了防止 TCP 连接阻塞,您可以将套接字设置为非阻塞模式。 然后,当您执行 connect() 时,您将立即(不太可能)连接或获得包含错误编号为 .errno 的异常。 errno.EINPROGRESS 表示连接正在进行中,但尚未完成。 不同的操作系统将返回不同的值,因此您将不得不检查系统上返回的内容。

您可以使用 connect_ex() 方法来避免创建异常。 它只会返回 errno 值。 要轮询,您可以稍后再次调用 connect_ex() - 0 或 errno.EISCONN 表示您已连接 - 或者您可以通过此套接字来选择以检查它是否可写。


数据库

Python 中是否有数据库包的接口?

是的。

Python 2.3 包含 bsddb 包,它提供了一个到 BerkeleyDB 库的接口。 标准 Python 还包含基于磁盘的哈希接口,例如 DBM 和 GDBM。

支持大多数关系数据库。 有关详细信息,请参阅 DatabaseProgramming wiki 页面 。


你如何在 Python 中实现持久对象?

pickle 库模块以一种非常通用的方式解决了这个问题(尽管你仍然无法存储打开的文件、套接字或窗口之类的东西),而 shelf 库模块使用 pickle 和 ( g)dbm 创建包含任意 Python 对象的持久映射。 为了获得更好的性能,您可以使用 cPickle 模块。

更别扭的做事方式是用泡菜的小姐姐元帅。 marshal 模块提供了非常快速的方法来将非循环基本 Python 类型存储到文件和字符串,然后再返回。 尽管 marshal 不会做一些花哨的事情,比如存储实例或正确处理共享引用,但它确实运行得非常快。 例如,加载半兆字节的数据可能需要不到三分之一秒。 这通常胜过做一些更复杂和更通用的事情,比如使用带有 pickle/shelve 的 gdbm。


为什么 cPickle 这么慢?

默认情况下,pickle 使用相对较旧且速度较慢的格式以实现向后兼容。 但是,您可以指定其他更快的协议版本:

largeString = 'z' * (100 * 1024)
myPickle = cPickle.dumps(largeString, protocol=1)

如果我的程序在打开 bsddb(或 anydbm)数据库时崩溃,它就会被破坏。 怎么来的?

必须使用数据库的 .close() 方法显式关闭使用 bsddb 模块(通常由 anydbm 模块,因为它会优先使用 bsddb)进行写访问的数据库。 底层库缓存需要转换为磁盘形式并写入的数据库内容。

如果你已经初始化了一个新的 bsddb 数据库,但在程序崩溃之前没有向它写入任何内容,你通常会得到一个零长度的文件,并在下次打开文件时遇到异常。


我试图打开 Berkeley DB 文件,但 bsddb 产生 bsddb.error: (22, 'Invalid argument')。 帮助! 如何恢复我的数据?

不要惊慌! 您的数据可能完好无损。 导致该错误的最常见原因是您尝试使用较新版本的 Berkeley DB 库打开较早的 Berkeley DB 文件。

现在,许多 Linux 系统都可以使用所有三个版本的 Berkeley DB。 如果要从版本 1 迁移到较新版本,请使用 db_dump185 转储数据库的纯文本版本。 如果要从版本 2 迁移到版本 3,请使用 db2_dump 创建数据库的纯文本版本。 在任一情况下,使用 db_load 为您计算机上安装的最新版本创建新的本机数据库。 如果您安装了版本 3 的 Berkeley DB,您应该能够使用 db2_load 创建本机版本 2 数据库。

您应该远离 Berkeley DB 版本 1 文件,因为哈希文件代码包含可能损坏数据的已知错误。


数学和数字

如何在 Python 中生成随机数?

标准模块 random 实现了一个随机数生成器。 用法很简单:

import random
random.random()

这将返回 [0, 1) 范围内的随机浮点数。

该模块中还有许多其他专门的生成器,例如:

  • randrange(a, b) 选择 [a, b) 范围内的整数。
  • uniform(a, b) 在 [a, b) 范围内选择一个浮点数。
  • normalvariate(mean, sdev) 对正态(高斯)分布进行采样。

一些更高级别的函数直接对序列进行操作,例如:

  • choice(S) 从给定序列中选择随机元素
  • shuffle(L) 原地打乱列表,即 随机排列

还有一个 Random 类,您可以实例化以创建独立的多个随机数生成器。