On this page
库和扩展常见问题
Contents
一般 Library 问题
如何找到执行任务 X 的模块或应用程序?
检查Library 参考以查看是否有相关的标准库模块。 (finally,您将了解标准库中的内容,并且可以跳过此步骤.)
对于第三方程序包,请搜索Python 包索引或tryGoogle或其他 Web 搜索引擎。搜索“ Python”以及一个或两个与您感兴趣的主题相关的关键字通常会发现有帮助。
math.py(socket.py,regex.py 等)的源文件在哪里?
如果找不到模块的源文件,则它可能是以 C,C 或其他编译语言实现的内置或动态加载的模块。在这种情况下,您可能没有源文件,或者可能是mathmodule.c
之类的东西,位于 C 源目录的某个位置(不在 Python 路径上)。
Python 中至少有三种模块:
用 Python(.py)编写的模块;
用 C 语言编写并动态加载的模块(.dll,.pyd,.so,.sl 等);
用 C 编写并与解释器链接的模块;要获取这些列表,请键入:
import sys
print(sys.builtin_module_names)
如何在 Unix 上使 Python 脚本可执行?
您需要做两件事:脚本文件的模式必须是可执行的,第一行必须以#!
开头,后跟 Python 解释器的路径。
首先pass执行chmod +x scriptfile
或chmod 755 scriptfile
完成。
第二种方法可以pass多种方式完成。最直接的方法是写
#!/usr/local/bin/python
作为文件的第一行,使用平台上安装 Python 解释器的路径名。
如果您希望脚本独立于 Python 解释器所在的位置,则可以使用 env 程序。假设 Python 解释器位于用户 PATH
的目录中,几乎所有的 Unix 变体都支持以下内容:
#!/usr/bin/env python
不要对 CGI 脚本执行此操作。 CGI 脚本的 PATH
变量通常很小,因此您需要使用解释器的实际绝对路径名。
有时,用户环境太满了,以致 /usr/bin/env 程序失败;或根本没有 env 程序。在这种情况下,您可以try以下破解(由于 Alex Rezinsky):
#! /bin/sh
""":"
exec python $0 ${1+"$@"}
"""
较小的缺点是,它定义了脚本的__doc_字符串。但是,您可以pass添加
__doc__ = """...Whatever..."""
是否有适用于 Python 的 curses/termcap 软件包?
对于 Unix 变体:标准的 Python 源发行版在Modules子目录中带有 curses 模块,尽管默认情况下未编译。 (请注意,这在 Windows 发行版中不可用– Windows 没有 curses 模块.)
curses模块支持基本 curses Function以及 ncurses 和 SYSV curses 的许多其他Function,例如颜色,备用字符集支持,填充和鼠标支持。这意味着该模块与仅具有 BSD curses 的 os 不兼容,但是目前似乎没有任何维护的 os 属于此类。
对于 Windows:使用consolelib 模块。
Python 中是否有相当于 C 的 onexit()的代码?
atexit模块提供类似于 C 的onexit()
的寄存器Function。
为什么我的 signal 处理程序不起作用?
最常见的问题是使用错误的参数列表语句 signal 处理程序。被称为
handler(signum, frame)
所以应该用两个参数语句它:
def handler(signum, frame):
...
Common tasks
如何测试 Python 程序或组件?
Python 带有两个测试框架。 doctest模块在模块的文档字符串中查找示例并运行它们,将输出与文档字符串中给出的预期输出进行比较。
unittest模块是一个模仿 Java 和 Smalltalk 测试框架的高级测试框架。
为了简化测试,您应该在程序中使用良好的模块化设计。您的程序应该将几乎所有Function封装在函数或类方法中–有时会产生令人惊讶和令人愉悦的效果,使程序运行更快(因为局部变量访问比全局访问快)。此外,程序应避免依赖于更改全局变量,因为这会使测试变得更加困难。
程序的“全局主逻辑”可能很简单
if __name__ == "__main__":
main_logic()
在程序主模块的底部。
一旦您的程序被组织为Function和类行为的可收拾的集合,您就应该编写测试Function以测试行为。自动化测试序列的测试套件可以与每个模块关联。这听起来需要做很多工作,但是由于 Python 非常简洁灵活,因此非常容易。pass与“生产代码”并行编写测试函数,可以使编码更加令人愉悦和有趣,因为这样可以更容易地发现错误,甚至可以早期发现设计缺陷。
并非旨在作为程序主要模块的“支持模块”可以包括对该模块的自检。
if __name__ == "__main__":
self_test()
当外部接口不可用时,即使使用复杂的外部接口进行交互的程序也可以pass使用 Python 中实现的“伪”接口进行测试。
如何从文档字符串创建文档?
pydoc模块可以从 Python 源代码中的文档字符串创建 HTML。纯粹从文档字符串创建 API 文档的替代方法是epydoc。 Sphinx还可以包含文档字符串内容。
如何一次获得一次按键?
对于 Unix 变体,有几种解决方案。使用 curses 做到这一点很简单,但是 curses 是一个需要学习的相当大的模块。
Threads
如何使用线程编程?
确保使用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) # <---------------------------!
但是现在(在许多平台上)线程不再并行运行,而是 Sequences 运行,一次运行一次!原因是 OS 线程调度程序在阻塞前一个线程之前不会启动新线程。
一个简单的解决方法是在 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)
与其try猜测time.sleep()的延迟值,不如使用某种 signal 量机制。一种想法是使用queue模块创建队列对象,让每个线程在完成时将一个令牌附加到队列中,并让主线程从队列中读取与线程数量一样多的令牌。
如何在许多工作线程中分配工作?
最简单的方法是使用新的concurrent.futures模块,尤其是ThreadPoolExecutor类。
或者,如果您希望更好地控制调度算法,则可以手动编写自己的逻辑。使用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(), end=' ')
print('queue empty')
break
else:
print('Worker', threading.currentThread(), end=' ')
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 130283832797456)> running with argument 0
Worker <Thread(worker 2, started 130283824404752)> running with argument 1
Worker <Thread(worker 3, started 130283816012048)> running with argument 2
Worker <Thread(worker 4, started 130283807619344)> running with argument 3
Worker <Thread(worker 5, started 130283799226640)> running with argument 4
Worker <Thread(worker 1, started 130283832797456)> running with argument 5
...
有关更多详细信息,请查阅模块的文档。 Queue类提供了Function丰富的界面。
哪种全局值突变是线程安全的?
内部使用全局解释器锁(GIL)来确保一次仅一个线程在 Python VM 中运行。通常,Python 仅在字节码指令之间提供在线程之间切换的Function。可passsys.setswitchinterval()设置切换的频率。因此,从 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()
These aren't:
i = i+1
L.append(L[-1])
L[i] = L[j]
D[x] = D[x] + 1
当其他对象的引用计数达到零时,替换其他对象的操作可能会调用其他对象的del()方法,这可能会影响事物。对于字典和列表的大量更新尤其如此。如有疑问,请使用互斥锁!
我们不能摆脱全局翻译锁定吗?
全局解释器锁(GIL)通常被认为是在高端 multiprocessing 器服务器计算机上部署 Python 的障碍,因为坚持认为(几乎)所有 Python 代码只能在运行时运行,因此多线程 Python 程序实际上仅使用一个 CPU。举行了 GIL。
在 Python 1.5 时代,Greg Stein 实际上实现了一个全面的补丁集(“自由线程”补丁),该补丁集删除了 GIL,并用细粒度的锁定代替了它。亚当·奥尔森(Adam Olsen)最近在他的python-safethread项目中进行了类似的实验。不幸的是,由于补偿了删除 GIL 所需的细粒度锁定,两个实验都显示出单线程性能急剧下降(至少慢了 30%)。
这并不意味着您不能在多 CPU 机器上充分利用 Python!您只需要 Creating 性地将工作分成多个进程而不是多个线程即可。新的concurrent.futures模块中的ProcessPoolExecutor类提供了一种简便的方法。 multiprocessing模块提供了较低级别的 API,以防您需要对任务的分派进行更多控制。
明智地使用 Cextensions 也将有所帮助;如果使用 Cextensions 执行耗时的任务,则该 extensions 可以在执行线程位于 C 代码中时释放 GIL,并允许其他线程完成某些工作。某些标准库模块(例如zlib和hashlib)已经做到了。
有人建议,GIL 应该是每个解释器状态的锁,而不是 true 的全局锁。则解释器将无法共享对象。不幸的是,这也不可能发生。这将是一项巨大的工作,因为当前许多对象实现都具有全局状态。例如,小整数和短字符串被缓存;这些缓存将必须移至解释器状态。其他对象类型有其自己的空闲列表。这些空闲列表将必须移至解释器状态。等等。
而且我怀疑它是否可以在有限的时间内完成,因为第三方扩展存在相同的问题。第三方扩展的写入速度可能比您将其转换为将其所有全局状态存储在解释器状态时要快。
最后,一旦多个解释器不共享任何状态,在单独的过程中运行每个解释器会获得什么yield?
Importing 和输出
如何删除文件? (以及其他文件问题...)
使用os.remove(filename)
或os.unlink(filename)
;有关文档,请参见os模块。这两个Function是相同的。 unlink()只是此Function的 Unix 系统调用的名称。
要删除目录,请使用os.rmdir();使用os.mkdir()创建一个。 os.makedirs(path)
将在path
中创建任何不存在的中间目录。 os.removedirs(path)
将删除中间目录,只要它们为空;如果要删除整个目录树及其内容,请使用shutil.rmtree()。
要重命名文件,请使用os.rename(old_path, new_path)
。
要截断文件,请使用f = open(filename, "rb+")
打开它,然后使用f.truncate(offset)
;偏移量默认为当前搜索位置。用os.open()打开的文件也有os.ftruncate(fd, offset)
,其中* fd *是文件 Descriptors(一个小整数)。
shutil模块还包含用于处理文件的许多Function,包括copyfile(),copytree()和rmtree()。
如何复制文件?
shutil模块包含copyfile()函数。请注意,在 MacOS 9 上,它不会复制资源派生和 Finder 信息。
如何读取(或写入)二进制数据?
要读取或写入复杂的二进制数据格式,最好使用struct模块。它允许您获取包含二进制数据(通常是数字)的字符串,并将其转换为 Python 对象。反之亦然。
例如,以下代码从文件中读取两个 2 字节整数和一个 4 字节大端格式的整数:
import struct
with open(filename, "rb") as f:
s = f.read(8)
x, y, z = struct.unpack(">hhl", s)
格式字符串中的'>'强制使用大端数据。字母“ h”从字符串中读取一个“短整数”(2 字节),“ l”从字符串中读取一个“长整数”(4 字节)。
对于更常规的数据(例如,整数或浮点数的同类列表),您还可以使用array模块。
Note
我似乎无法在使用 os.popen()创建的管道上使用 os.read();为什么?
os.read()是一个低级函数,它带有文件 Descriptors,这是一个小的整数,表示打开的文件。 os.popen()创建一个高级文件对象,其类型与内置open()函数返回的类型相同。因此,要从使用os.popen()创建的管道* p 中读取 n *个字节,您需要使用p.read(n)
。
如何访问串行(RS232)端口?
对于 Win32,POSIX(Linux,BSD 等),Jython:
对于 Unix,请参见 Mitch Chapman 的 Usenet post:
为什么不关闭 sys.stdout(stdin,stderr)却真的将其关闭?
Python file objects是底层 C 文件 Descriptors 上的高层抽象层。
对于您pass内置的open()函数在 Python 中创建的大多数文件对象,f.close()
将 Python 文件对象从 Python 的角度标记为已关闭,并且还安排了关闭基础 C 文件 Descriptors。当f
变成垃圾时,这也会在f
的析构函数中自动发生。
但是 st,stdout 和 stderr 会被 Python 特殊对待,因为 C 还会赋予它们特殊的状态。运行sys.stdout.close()
会将 Python 级别的文件对象标记为已关闭,但不会会关闭关联的 C 文件 Descriptors。
要关闭这三个文件之一的基础 C 文件 Descriptors,首先应确保这是您 true 想要做的(例如,您可能会混淆try执行 I/O 的扩展模块)。如果是,请使用os.close():
os.close(stdin.fileno())
os.close(stdout.fileno())
os.close(stderr.fileno())
或者,您可以分别使用数字常数 0、1 和 2.
Network/Internet Programming
有哪些适用于 Python 的 WWW 工具?
请参见《Library 参考手册》中标题为互联网协议和支持和互联网数据处理的章节。 Python 有许多模块,可帮助您构建服务器端和 Client 端 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)?
我想检索张贴表单的结果的网页。是否有现有的代码可以让我轻松地做到这一点?
是。这是一个使用 urllib.request 的简单示例:
#!/usr/local/bin/python
import urllib.request
# build the query string
qs = "First=Josephine&MI=Q&Last=Public"
# connect and send the server a path
req = urllib.request.urlopen('http://www.some-server.out-there'
'/cgi-bin/some-cgi-script', data=qs)
with req:
msg, hdrs = req.read(), req.info()
请注意,通常对于百分比编码的 POST 操作,查询字符串必须使用urllib.parse.urlencode()引起来。例如,发送name=Guy Steele, Jr.
:
>>> import urllib.parse
>>> urllib.parse.urlencode({'name': 'Guy Steele, Jr.'})
'name=Guy+Steele%2C+Jr.'
See also
我应该使用哪个模块来帮助生成 HTML?
您可以在Web 编程 Wiki 页面上找到有用链接的集合。
如何从 Python 脚本发送邮件?
使用标准库模块smtplib。
这是一个使用它的非常简单的交互式邮件发件人。此方法将在任何支持 SMTP 侦听器的主机上工作。
import sys, smtplib
fromaddr = input("From: ")
toaddrs = 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
表示连接正在进行中,但尚未完成。不同的 os 将返回不同的值,因此您将必须检查系统返回的内容。
您可以使用connect_ex()
方法来避免创建异常。它只会返回 errno 值。要进行轮询,您可以稍后再调用connect_ex()
– 0
或errno.EISCONN
表示您已连接–或可以pass此套接字选择以检查其是否可写。
Databases
Python 中是否有任何数据库包接口?
Yes.
标准 Python 也包含与基于磁盘的哈希(例如DBM和GDBM)的接口。还有sqlite3模块,它提供了基于磁盘的轻量级关系数据库。
支持大多数关系数据库。有关详情,请参见DatabaseProgramming Wiki 页面。
如何在 Python 中实现持久对象?
pickle库模块以非常通用的方式解决了这个问题(尽管您仍然无法存储打开的文件,套接字或窗口之类的东西),而shelve库模块使用 pickle 和(g)dbm 创建包含任意 Python 对象的持久 Map。
math 与数值
如何在 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
类来创建独立的多个随机数生成器。