十一、更多内置功能
前几章讨论了为现有的 Python 2 项目提供 Python 3 支持,但并没有涵盖所有内容。Python 3 中的大多数内置都进行了重组。本章介绍了其他内置函数,并讨论了如何实现它们的兼容性。
减少
如果您使用 Python 已经有一段时间了,您可能会遇到 reduce()函数,它对于在一系列元素上执行计算并返回结果非常有用和方便。它将参数中传递的特定函数应用于序列中提到的所有列表元素。
通常,像计算列表整数之和这样的任务是使用一个基本的 for 循环来完成的:
**Download MoreBuiltins/forloop.py**
def sum(list):
sum = 1
for num in list:
sum = sum + num
result = sum( [1, 2, 3, 4])
sum()方法接受整数列表并返回它们的和。给定前面的列表,结果的值是 10。
使用 reduce()可以实现相同的功能。在 Python 2 中,reduce()位于全局名称空间中,用作:
**Download MoreBuiltins/reducepy2.py**
def sum(list):
sum = reduce((lambda x, y: x + y), list)
result = sum( [1, 2, 3, 4])
调用带有整数列表的 sum()方法返回整数的和,就像前面使用 for 循环的方法一样。
注意
使用 reduce()还是 for 循环由您决定,但是 for 循环更容易阅读。
Python 3 引入了对 reduce()函数位置的更改。该函数已从 functools 模块的全局命名空间中移除。因此,为了兼容,请使用 functools.reduce()。
**Download MoreBuiltins/reducepy2.py**
from functools import reduce
def sum(list):
sum = reduce((lambda x, y: x + y), list)
result = sum( [1, 2, 3, 4])
需要导入,因为 reduce()不再是全局函数。
注意
reduce()在现代 Python 2 版本的 functools 中也有。
six 提供了一条通过它的假 six.moves 模块的出路。为了加载 Python 2 和 3 中具有 reduce()函数的模块,我们编写:
from six.moves import reduce
我们现在可以使用六个 as 来编辑我们的函数:
**Download MoreBuiltins/reduce_six.py**
from six.moves import reduce
def sum(list):
sum = reduce((lambda x, y: x + y), list)
result = sum( [1, 2, 3, 4])
在这种情况下,six.moves 别名指向 Python 3 模块,相当于调用 functools.reduce。
总之,为了 Python 2 和 3 的兼容性,在使用 reduce()时:
-
使用 functools.reduce()而不是全局 reduce()函数
-
或者使用六步。减少
原始输入和输入
Python 2 有两个请求用户输入的函数:raw_input()和 input()。
raw_input()接受以字符串形式提供给 stdin 的所有内容。
>>> a = raw_input("enter a number :- ")
enter a number :- 4
>>> type(a)
<type 'str'>
另一方面,input() *,*将用户输入计算为 int 或 float,或者其他任何类型。从技术上讲,从用户处读取的任何内容都使用 eval()进行评估。
>>> a = input("enter a number :- ")
enter a number :- 4
>>> type(a)
<type 'int'>
因此,input()与 eval(raw_input())相同。
>>> a = eval( raw_input("enter a number :- "))
enter a number :- 4
>>> type(a)
<type 'int'>
>>>
在 Python 3 中,raw_input()被重命名为 input(),它现在以字符串形式接受 stdin 中的用户输入。
>>> a = input("enter a number :- ")
enter a number :- 5
>>> type(a)
<class 'str'>
在 Python 3 中,raw_input()返回一个错误。
>>> a = raw_input("enter a number :- ")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'raw_input' is not defined
>>>
我们已经看到,在 Python 2 和 3 中,input()在语义上是不同的,而在 Python 3 中,raw_input()却不是。Python-future 和 six 都提供了包装器来规避这些变化。
使用 Python-未来
通过它的内置模块,Python-future 提供了一个函数输入,我们可以使用它来代替 Python 2 的 raw_ininput()。因此,这:
**Download MoreBuiltins/input_py2.py**
first = raw_input("enter first number: ")
second = raw_input("enter second number: ")
print first + second
变成了这样:
**Download MoreBuiltins/input_future.py**
**from builtins import** input
first = input("enter first number: ")
second = input("enter second number: ")
print first + second
当我们使用从 builtin 模块导入的 input()方法时,我们在 builtin input()方法中得到 Python 3 的行为。
对输入使用 eval()来实现 Python 2 的行为,其中输入被评估为其各自的类型。
**Download MoreBuiltins/input_eval_future.py**
**from builtins import** input
first = eval(input("enter first number: "))
second = eval(input("enter second number: "))
print first + second
注意
eval()使用不慎有其自身的危险性。对不信任的字符串使用 eval()是不安全的。
解析给定类型的用户输入的一种安全方式是将结果转换为所需的类型;例如:
**Download MoreBuiltins/input_cast_future.py**
**from builtins import** input
first = int(input("enter first number: "))
second = int(input("enter second number: "))
print first + second
使用六
我们还可以使用 six.moves.input(),它在 Python 2 中指向 raw_input(),在 Python 3 中指向 input()。
**Download MoreBuiltins/input_future.py**
**from six.moves import** input
first = input("enter first number: ")
second = input("enter second number: ")
print first + second
总之,为了在解析用户输入时的兼容性
-
使用 Python future 的 builtins.input()函数
-
可以选择使用 six.moves.input()函数
执行()
在 Python 中,exec()执行动态创建的 Python 代码。exec()接受一个字符串或对象。字符串被解析为一组 Python 语句,然后执行这些语句。一个对象被简单地执行。可以使用内置的 globals()和 locals()函数分别返回当前的全局和局部字典;这可能有助于作为 exec()的第二个和第三个参数传递。
在 Python 2 中,exec 是一个语句。
**Download MoreBuiltins/exec_py2.py**
globalsParameter = {'__builtins__' : None}
localsParameter = {'print': print, 'dir': dir}
exec 'print(dir())' in globalsParameter, localsParameter
在这段代码中,当需要指定全局和局部范围时,exec 是与关键字一起使用的语句。
然而,在 Python 3 中,exec 是一个函数,调用时将对象、全局范围和局部范围作为可选参数。
**Download MoreBuiltins/exec_py3.py**
globalsParameter = {'__builtins__' : None}
localsParameter = {'print': print, 'dir': dir}
exec ('print(dir())', globalsParameter, localsParameter)
为了兼容,最好的选择是使用 Python 3 语法,因为它在 Python 2 中也能工作。
另一个选择是使用 six.exec_()。
**Download MoreBuiltins/exec_six.py**
from math import *
globalsParameter = {'__builtins__' : None}
localsParameter = {'print': print, 'dir': dir}
six.exec_('print(dir())', globalsParameter, localsParameter)
这在全局参数和局部参数的范围内执行 print(dir())。在这种情况下,print(dir())是一个字符串。如果没有给出全局变量或局部变量,它们将默认为调用者的范围。如果只给了全局变量,那么它也被用作局部变量。
注意
在 Python 3.x 中,不应使用关键字参数调用 exec(),因为它不接受关键字参数。
总之,在为 exec 提供兼容性时
-
使用 Python 3 语法
-
使用 six.exec_()
execfile()
在 Python 2 中,execfile()是一个类似于 exec()的函数,但是它不是接受一个字符串,而是接受一个文件和两个可选的字典作为全局和本地名称空间。
**Download MoreBuiltins/execfile_py2.py**
import sys
sys.argv = ['arg1', 'arg2']
execfile('abc.py')
Python 3 中删除了这个函数;因此,如果您现有的 Python 2 代码使用这个函数,那么就需要进行修改。让我们来讨论如何做出这些改变。
使用 Python-未来
在 past.builtins 模块中,我们可以使用 execfile()方法,它将在两个 Python 版本中发挥神奇的作用。
**Download MoreBuiltins/execfile_future.py**
from past.builtins import execfile
import sys
sys.argv = ['arg1', 'arg2']
**execfile('abc.py')**
我们还可以选择使用 exec()函数和 compile 来以这种方式处理文件:
**Download MoreBuiltins/execfile_exec_compile.py**
from past.builtins import execfile
import sys
sys.argv = ['arg1', 'arg2']
**execfile(compile(open('abc.py').read()))**
注意
目前,six 还没有 execfile()的包装器方法,但是有一个公开的问题需要这个特性。当有人打开一个解决这个问题的拉请求时,你可以使用 six 来解决这个兼容性问题;但目前,六号无解。
总之,如果您在代码中使用 execfile(),那么为了兼容性
-
使用来自 past.builtins 模块的 Python-future 的 execfile()
-
将 exec()与 compile()一起使用
Unichr()
在 Python 2 中,Unichr()返回一个字符的字符串表示,该字符的 Unicode 码位作为参数给出;例如,
unichr(97)
返回
'a'
该参数的取值范围是从 1 到 1,114,111。超出此范围的任何内容都将返回 ValueError。
在 Python 3 中,这个方法被移除了。相反,使用 chr()获取字符的字符串表示,给出它的 Unicode 点。
Chr(97)
这也返回
'a'
为了兼容,six 和 future 都有 chr()和 unichr()方法。
使用 Python-未来
Python-future 有一个来自 builtins 模块的 chr()方法,该方法在语义上为两个 Python 版本提供了所需的功能。
**Download MoreBuiltins/unichr_future.py**
**from builtins import** chr
chr(8364)
使用六
six 有一个 Unicode()方法,它接受一个 Unicode 点并返回它各自的字符串表示。
**Download MoreBuiltins/unichr_six.py**
from six import unichr
unichr(8364)
总而言之,为了兼容使用
-
Python-future’s builtins.chr
-
six.chr()
实习生()
如果多次使用包含相同字符或文本的字符串,则每次都会创建一个新的 string 对象。例如,
>>> x = "I love chocolate"
>>> y = "I love chocolate"
>>> x is y
False
>>>
我们最终得到两个不同的 string 对象,它们具有相同的值,但不指向相同的值。然后它们被丢弃,因为它们不再被使用。
另一方面,如果我们使用被拘留的字符串,intern 函数保存字符串并从被拘留的字符串表中返回它们。
>>> a = intern("I love chocolate")
>>> b = intern("I love chocolate")
>>> a is b
True
>>>
由于字符串 a 和 b 被保留,它们现在持有相同的字符串对象;因此, a 为 b 返回真。intern 函数确保我们不会创建两个具有相同值的 string 对象。当我们试图请求创建与现有 string 对象具有相同值的第二个 string 对象时,我们获得了对现有 string 对象的引用。这样,我们节省了内存。相比之下,字符串对象非常有效,因为它们是通过比较两个字符串对象的内存地址而不是它们的内容来实现的。这就是 intern 函数有助于提高性能和优化代码的地方。
注意
互联网字符串在技术上不同于普通字符串,因为它们不允许我们创建两个具有相同值的字符串对象;而字符串为同一字符串创建两个单独的对象。
关于实习字符串,这就足够了,但在我们继续之前,我要提一下 Python 2 中的实习函数是全局的,因此使用如下:
**Download MoreBuiltins/internpy2.py**
a = intern ("I love Python")
b = intern ("I love Python")
a is b # returns True
在 Python 3 中,intern 函数不是全局函数,因为它被移到了 sys 模块中。因此,它的用法如下:
**Download MoreBuiltins/internpy2.py**
from sys import intern
a = intern ("I love Python")
b = intern ("I love Python")
a is b # returns True
这些对比可以通过使用可选导入来处理,这里我们使用一个 try catch 块,如下所示:
**Download MoreBuiltins/intern_optional_import.py**
try:
from sys import intern
except ImportError:
pass
a = intern ("I love Python")
b = intern ("I love Python")
a is b # returns True
在 Python 2 中,import 语句在执行 except 块时失败,在这里我们实际上什么也不做。这将执行全局实习生功能。在 Python 3 中,执行 try 块中的导入,而使用 sys 模块中的 intern 函数。这只是一种方式。Python-future 和 six 也解决了这个问题。
使用 Python-未来
future 确保 intern 函数兼容性的一种方法是利用它的 past.builtins 模块中的 intern 函数。
**Download MoreBuiltins/intern_future_pastbuiltins.py**
from past. import intern
a = intern ("I love Python")
b = intern ("I love Python")
a is b # returns True
future 为内部字符串提供兼容性的另一种方式是通过它的 install_aliases 函数。
**Download MoreBuiltins/intern_future_install_aliases.py**
install_aliases()
from sys import intern
a = intern ("I love Python")
b = intern ("I love Python")
a is b # returns True
当我们调用 install_aliases 时,未来的包使 Python 3 sys.intern 函数在 Python 2.x 中可用。
使用六
six 提供了 six.moves.intern 函数来解决 Python 2 和 3 之间的函数间差异。
**Download MoreBuiltins/intern_six.py**
from six.moves import intern
a = intern ("I love Python")
b = intern ("I love Python")
a is b # returns True
使用的 intern 函数相当于 Python 2 中的全局 intern 函数和 Python 3 中的 sys.intern 函数。
总之,为了保持内部字符串的兼容性
-
导入 six.moves 并使用 intern 函数。这相当于 Python 2 中的 intern 和 Python 3 中的 sys.intern。
-
调用 future 的 install_aliases 使 Python 3 的 sys.intern 函数在 Python 2.x 中可用
-
导入 past.builtins 并使用 intern 函数。
应用
apply 是一个 Python 2 函数,它基本上执行一个函数。它将函数和函数参数列表作为参数。
**Download MoreBuiltins/apply_py2.py**
def add(x, y):
return x + y
apply (add, [1,2])
在 Python 中,这个函数已经过时了;现在,我们必须以正常方式调用该函数,如下所示:
**Download MoreBuiltins/apply_py3.py**
def add(x, y):
return x + y
add (1,2)
因此,如果我们有使用 apply 方法的 Python 2 代码,那么我们应该将其更改为以正常方式调用函数,其中我们调用方法及其参数,而不是使用 apply 来执行函数以支持 Python 3。这节省了时间,并允许更快地执行我们的程序。如果您仍然想使用 apply 方法,那么使用 Python-future。
注意
在 Python 3 中,apply 方法已经过时。
使用 Python-未来
当我们从 future 的 past.builtins 模块调用 apply 函数时,我们可以继续使用 apply 函数,并且仍然支持 Python 3。
**Download MoreBuiltins/apply_future.py**
from past.builtins import apply
def add(x, y):
return x + y
apply (add, [1,2])
这使用了 Python 3 中的 apply 函数。
总之,为了在 Python 2 代码中使用 apply 函数时支持 Python 3
-
更改您的代码以正常调用有问题的方法,而不是通过 apply 函数执行它。
-
从 past.builtins 模块调用 future 的 apply 方法。
chr()
chr()通常接受一个整数,即字符的 Unicode 点,并返回一个或多个字符串。
在 Python 2.x 中,chr()将 0–255 范围内的数字转换为字节字符串;一个字符具有数值和 Unicode(),后者将 0–0x 10 ffff 范围内的数字转换为具有该 Unicode 码位的一个字符的 Unicode 字符串。
**Download MoreBuiltins/chr_py2.py**
chr(64)
chr(200)
如前所述,Python 3.x 用 chr()替换了 unichr()。因此,要实现旧的 chr()功能,我们有两个选择。一种是对 chr()的结果进行编码。
**Download MoreBuiltins/chr_py3_1.py**
chr(64).encode('latin-1')
chr(0xc8).encode('latin-1')
另一个选择是用我们想要得到的字符串的 Unicode 点来调用全局函数 bytes。
**Download MoreBuiltins/chr_py3_2.py**
bytes([64])
bytes([0xc8])
为了兼容性,six 和 future 都提供了避开这些语义差异的方法。让我们逐一探究。
使用 Python-未来
future 提供的一个选项是来自内置模块的 chr(),它使用与调用 chr()和编码结果相同的 Python 3 语法。
**Download MoreBuiltins/chr_future_1.py**
from builtins import chr
chr(64).encode('latin-1')
chr(0xc8).encode('latin-1')
或者,我们可以使用 future 内置模块中的 bytes 方法,它使用与 Python 3 的全局函数 bytes 相同的语法。
**Download MoreBuiltins/chr_future_2.py**
from builtins import bytes
bytes([64])
bytes([0xc8])
使用六
six 提供了 int2byte(i)函数,该函数接受(0,256)范围内的整数,并将其转换或返回为字节。
**Download MoreBuiltins/chr_six.py**
from six import int2byte
int2byte(64)
int2byte(0xc8)
总之,
-
chr()在 Python 2 中返回字节字符串,而在 Python 3 中它必须被编码。
-
使用 Python-future 的 bytes 或 chr()方法获取字节字符串。
-
我们还可以使用 six 的 Int2byte()方法来获取字节串。
化学机械抛光()
cmp()是一个比较值的 Python 2 函数;以两个值为例,a 和 b。
cmp(a, b)
结果是:
-
如果 a 小于 b,则为负数。
-
如果 a 等于 b,则为零。
-
如果 a 大于 b,则为正数。
Python 3 中不赞成使用该函数。让我们讨论如何为这种方法提供 Python 3 支持。
使用 Python-未来
我们应该使用 future’s past.builtins 模块中的 cmp()函数。
**Download MoreBuiltins/cmp_future.py**
from past.builtins import cmp
cmp('a', 'b') < 0
cmp('b', 'a') > 0
cmp('c', 'c') == 0
这使用了 Python 3 中的 cmp 函数。
重新加载()
reload 函数重新加载先前导入的模块。当您使用外部编辑器编辑了模块源文件,并且想要在不离开 Python 解释器的情况下尝试新版本时,这一点非常重要。返回值是模块对象。
注意
参数应该是已成功导入的模块。
在 Python 2 中,reload()是一个全局函数。
**Download MoreBuiltins/reload_py2.py**
reload(mymodule)
在 Python 3 中,方法是在 3.4 及更高版本中使用 importlib。
**Download MoreBuiltins/reload_py3.py**
from importlib import reload
reload(mymodule)
为了中立的兼容性,我们使用 imp.reload。
**Download MoreBuiltins/reload_neutral.py**
import imp
imp.reload(module)
注意
imp.reload()适用于 Python 版及更低版本。importlib.reload()适用于 Python 版及更高版本。
摘要
本章讨论了实现两个内置函数兼容性的技术,比如 reduce、input 和 cmp 等。这些函数中的大多数都已被弃用、重命名或重组。补救办法是 future 的内置包和 six 的 six.moves 包。
任务:巴格特大师
今天手头的任务是巴格特计划。这个项目包含一个 bagcat.py 文件,其中的方法仍然使用 Python 2 的 raw_ input。
**Download MoreBuiltins/task.py**
def write_config(args):
config_file = os.path.join(os.path.expanduser("∼"), '.bagcat')
if os.path.isfile(config_file):
if raw_input("overwrite existing %s [Y/N] " % config_file).upper() != "Y":
return
config = configparser.RawConfigParser()
for name in ['aws_access_key_id', 'aws_secret_access_key', 'bucket']:
value = raw_input("%s: " % name)
config.set('DEFAULT', name, value)
config.write(open(config_file, 'w'))
让我们看看这段代码兼容后是什么样子。
使用 Python-未来
如前所述,使用 builtins 包中的 input()。
**Download MoreBuiltins/task_future.py**
from builtins import input
def write_config(args):
config_file = os.path.join(os.path.expanduser("∼"), '.bagcat')
if os.path.isfile(config_file):
if input("overwrite existing %s [Y/N] " % config_file).upper() != "Y":
return
config = configparser.RawConfigParser()
for name in ['aws_access_key_id', 'aws_secret_access_key', 'bucket']:
value = input("%s: " % name)
config.set('DEFAULT', name, value)
config.write(open(config_file, 'w'))
使用六
与 Python-future 一样,使用 six.moves 中的 input()。
**Download MoreBuiltins/task_six.py**
from six.moves import input
def write_config(args):
config_file = os.path.join(os.path.expanduser("∼"), '.bagcat')
if os.path.isfile(config_file):
if input("overwrite existing %s [Y/N] " % config_file).upper() != "Y":
return
config = configparser.RawConfigParser()
for name in ['aws_access_key_id', 'aws_secret_access_key', 'bucket']:
value = input("%s: " % name)
config.set('DEFAULT', name, value)
config.write(open(config_file, 'w'))
十二、标准库模块
Python 标准库进行了重组,以使其更加简单和一致。许多模块被重命名以符合 PEP 8 和统一文件命名惯例。其他的合并将相关的模块放在一个公共的名称空间中。本章探讨了一些重新命名和重新组织的模块,并解释了如何为它们提供兼容性。
Tkinter
如果你尝试过使用图形用户界面来创建程序,那么你会遇到 Tkinter。它是一个标准的库模块,作为一个小型工具包 Tk 的接口。
该模块在 Python 2 中被称为 tkinter,但在 Python 3 中被重命名为 Tkinter(区别在于第一个字母的大小写)。
与 GUI 开发相关的其他模块从全局名称空间中移除,放在 tkinter 名称空间中。表 12-1 列出了这些模块。
表 12-1。Tkinter 命名空间模块
|Python 2
|
Python 3
|
| — | — |
| 对话 | tkinter 对话框 |
| 文件动态 | tkinter.filedialog 对话方块 |
| 滚动文本框 | tkinter . scroll ed text-滚动文字 |
| 简单对话 | tkinter . simple dialog-简易对话方块 |
| 置 | tkinter.tix |
| tk 常量 | tkinter 常量 |
| Tkdnd | tkinter.dnd |
| tkColorChooser | 克罗库瑟 |
| tkCommonDialog | tkinter . common dialog-tkinter .共用对话方块 |
| tkFileDialog | tkinter.filedialog 对话方块 |
| tkFont | tkinter 字体 |
| tkMessageBox | tkinter . message box-讯息方块 |
| tkSimpleDialog | tkinter . simple dialog-简易对话方块 |
| 天天快递 | tkinter.ttk |
Python-future 和 six 提供了包装器来保持代码库中使用 Tkinter 模块时的兼容性。以下是带有 Tkinter 导入的 Python 2 源代码:
**Download MoreBuiltins/tkinter_py2.py**
import Tkinter
import Dialog
import FileDialog
import ScrolledText
import SimpleDialog
import Tix
import Tkconstants
import Tkdnd
import tkColorChooser
import tkCommonDialog
import tkFileDialog
import tkFont
import tkMessageBox
import tkSimpleDialog
import ttk
使用 Python-未来
在 Python-future 中,前面的 Tkinter 模块可以按如下方式实现:
**Download MoreBuiltins/tkinter_future.py**
import tkinter
import tkinter.dialog
import tkinter.filedialog
import tkinter.scrolledtext
import tkinter.simpledialog
import tkinter.tix
import tkinter.constants
import tkinter.dnd
import tkinter.colorchooser
import tkinter.commondialog
import tkinter.filedialog
import tkinter.font
import tkinter.messagebox
import tkinter.simpledialog
import tkinter.ttk
这些未来的包装器在 Python 2 和 3 中调用正确的 tkinter 模块。
使用六
通过它的 six.moves 模块,six 以一个与 Python 2 和 3 都兼容的名称公开了所有重命名和公开的模块。
**Download MoreBuiltins/tkinter_future.py**
from six.moves import tkinter
from six.moves import dialog
from six.moves import filedialog
from six.moves import scrolledtext
from six.moves import simpledialog
from six.moves import tix
from six.moves import constants
from six.moves import dnd
from six.moves import colorchooser
from six.moves import commondialog
from six.moves import filedialog
from six.moves import font
from six.moves import messagebox
from six.moves import simpledialog
from six.moves import .ttk
推荐的固定器将导入更改为使用六步。
配置器
Configparser 是一个使用配置文件的 Python 模块。它与 Windows INI 文件有许多相似之处。它为任何应用处理用户可编辑的配置文件。配置文件分为几个部分,每个部分可以包含配置数据的名称-值对。通过查找以[和]开头的行来识别配置文件节。典型的配置文件如下所示:
**Download StandardLibraryModules/sample_config.py**
[*AWS_main*]
endpoint = https://www.amazon.com/
accesskey = mdl;ldklsld
secretkey = fkndjfdgkdfhsdfj
在 Python 2 中,这个模块被称为 Configparser(首字母大写;因此这是它的使用方式)。
**Download StandardLibraryModules/configparser_py2.py**
*from ConfigParser import ConfigParser*
ConfigParser.SafeConfigParser()
此模块已被重命名。
**Download StandardLibraryModules/configparser_py2.py**
*from* configparser *import ConfigParser*
configparser.ConfigParser()
从这个例子中,我们看到 SafeConfigParser 函数在 Python 3 中被重命名为 ConfigParser。
要解决这些差异并保持兼容性,请使用 six.moves 或 configparser backport。
使用 configparser 反向端口
configparser backport 是使用 pip install configparser 安装的 PyPi 可安装程序包。安装这个包,将它导入到您的代码中,并使用 Python 3 重命名的模块在两个 Python 版本上都有效。
**Download StandardLibraryModules/configparser_backport.py**
*from* configparser. *import ConfigParser*
configparser.ConfigParser()
用六招
从 six.moves 模块中,导入 configparser,它适用于 Python 2 和 3。
**Download StandardLibraryModules/configparser_six.py**
*import six*
*from six.moves import configparser*
*configparser.ConfigParser()*
总之,为了读写配置文件时的兼容性:
-
安装并使用后端口 configparser
-
使用 six.moves.configparser
长队
队列模块实现队列来帮助多线程编程。Python 队列对象可用于解决多生产者、多消费者的问题,其中消息必须在多个线程之间安全地交换。锁定语义已经在队列类中实现;因此,不需要处理低级锁定和解锁操作,这可能会导致死锁问题。
在 Python 3 中队列模块被重命名为“Queue”;因此,如果您想在 Python 2 中使用这个模块:
**Download StandardLibraryModules/queue_py2.py**
from Queue import Queue
在 Python 3 中应该是这样的:
**Download StandardLibraryModules/queue_py3.py**
from queue import Queue
通过使用 six 和 Python-future,我们可以导入与 Python 2 和 3 都兼容的同步队列类。
使用 Python-未来
在 Python-future 中,我们导入了一个在两个 Python 版本中都可靠运行的队列类。
**Download StandardLibraryModules/queue_future.py**
from queue import Queue
使用六
像 Python-future 一样,six 具有单个队列类,我们可以用它来确保 Python 2 和 3 的兼容性。
**Download StandardLibraryModules/queue_six.py**
import six
from six.moves.queue import Queue, heapq, deque
总之,为了兼容性,使用
-
来自 Python 的队列-未来
-
六.移动.排队
套接字服务器
socketserver 模块是一个简化网络服务器创建的框架。它提供了处理 TCP、UDP、Unix 流和 Unix 数据报上的同步网络请求的类。根据具体情况,它还提供了一些类来转换服务器,以便为每个请求使用单独的线程或进程。
socketserver 模块中定义了五个不同的服务器类;BaseServer 定义了 API。即使直接使用,这个类也不应该被实例化。TCPServer 使用 TCP/IP 套接字进行通信。UDPServer 使用数据报套接字。UnixStreamServer 和 UnixDatagramServer 使用 Unix 域套接字。
在 Python 2 中,socketserver 模块被拼写为“socket server”——使用骆驼大写字母。
**Download StandardLibraryModules/socketserver_py2.py**
import SocketServer
class MyTCPHandler(socketserver.BaseRequestHandler):
def handle(self):
# self.request is the TCP socket connected to the client
self.data = self.request.recv(1024).strip()
print("{} wrote:".format(self.client_address[0]))
print(self.data)
# just send back the same data, but upper-cased
self.request.sendall(self.data.upper())
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
# Create the server, binding to localhost on port 9999
server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
server.serve_forever()
在 Python 3 中,这个模块被更改并重命名为“socket server”——全是小写字母。
**Download StandardLibraryModules/socketserver_py2.** **py**
import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler):
def handle(self):
# self.request is the TCP socket connected to the client
self.data = self.request.recv(1024).strip()
print("{} wrote:".format(self.client_address[0]))
print(self.data)
# just send back the same data, but upper-cased
self.request.sendall(self.data.upper())
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
# Create the server, binding to localhost on port 9999
server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
server.serve_forever()
为了兼容 Python 2 和 3,Python-future 提供了 socketserver 模块,six 提供了 moves.socketserver 模块来解决这些差异。
使用 Python-未来
如果您 pip 安装了 Python-future,那么您应该可以访问 Python-future 的 socketsever 模块,您可以导入和使用该模块。
**Download StandardLibraryModules/socketserver_future.py**
import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler):
def handle(self):
# self.request is the TCP socket connected to the client
self.data = self.request.recv(1024).strip()
print("{} wrote:".format(self.client_address[0]))
print(self.data)
# just send back the same data, but upper-cased
self.request.sendall(self.data.upper())
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
# Create the server, binding to localhost on port 9999
server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
server.serve_forever()
就像导入的模块名称是 Python 3 的名称一样,如果不安装 future,那么这段代码将无法在 Python 2 上运行。
使用六
在 six.moves 中,我们可以导入和使用 socketserver 模块。
**Download StandardLibraryModules/socketserver_six.py**
from six.moves import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler):
def handle(self):
# self.request is the TCP socket connected to the client
self.data = self.request.recv(1024).strip()
print("{} wrote:".format(self.client_address[0]))
print(self.data)
# just send back the same data, but upper-cased
self.request.sendall(self.data.upper())
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
# Create the server, binding to localhost on port 9999
server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
server.serve_forever()
总之,为了在使用 socketserver 模块时保持兼容性,导入
-
来自 Python-future 的 socketserver
-
socketserver from six.moves
dbm 模块
Python 有一个数据库 API,在处理不同类型的数据库时非常有用。这些数据存储在一个名为 DBM 的数据库管理器中。从本质上讲,持久性字典的功能与普通的 Python 字典相同,只是数据是从磁盘上读写的。
有许多 DBM 模块不兼容。在 Python 2 中,其中一些模块的用法如下:
**Download StandardLibraryModules/dbmmodule_py2.py**
import anydbm
import whichdb
import dbm
import dumbdbm
import gdbm
在 Python 3 中,这些模块被重组并转移到子模块 DBM 中。
**Download StandardLibraryModules/dbmmodule_py3.py**
import dbm.anydbm
import dbm.whichdb
import dbm.dbm
import dbm.dumbdbm
import dbm.gdbm
不同之处在于子模块,模块被移到子模块中,因为它们在 Python 2 中不存在。让我们看看如何使用 Python-future 和 six 来平衡源代码。
使用 Python-未来
使用 Python-future,我们可以导入 standard_library 模块,调用 install_aliases()方法,然后使用 Python 3 语法。
**Download StandardLibraryModules/dbmmodule_future1.py**
from future import standard_library
standard_library.install_aliases()
import dbm
import dbm.ndbm
import dbm.dumb
import dbm.gnu
或者,我们可以从 future.moves 导入这些模块
**Download StandardLibraryModules/dbmmodule_future2.py**
from future.moves import dbm
from future.moves.dbm import dumb
from future.moves.dbm import ndbm
from future.moves.dbm import gnu
使用六
六提供了 DBM 的 gnu 模块;但是在写这本书的时候,它没有提供对其他不兼容模块的支持。
**Download StandardLibraryModules/dbmmodule_six.py**
from six.moves import dbm_gnu
http 模块
这个模块定义了处理 HTTP 和 HTTPS 协议客户端的类。大多数处理 HTTP 的模块都被移到了包 HTTP。
在 Python 2 中,HTTP 模块被全局访问使用,如下所示:
**Download StandardLibraryModules/http_py2.py**
import httplib
import Cookie
import cookielib
import BaseHTTPServer
import SimpleHTTPServer
import CGIHttpServer
在 Python 3 中,这些模块被重组;BaseHTTPServer 等模块在 http.server 中。
**Download StandardLibraryModules/http_py3.py**
import http.client
import http.cookies
import http.cookiejar
import http.server
为了兼容性,我们可以使用 Python-future 或 six 来实现平衡。
使用 Python-未来
在 pip 安装 future 之后,相应的 Python 3 语法应该可以在两个 Python 版本中可靠地工作。
Download StandardLibraryModules/http_future.py
import http.client
import http.cookies
import http.cookiejar
import http.server
使用六
在 six.moves 包中,我们也可以导入这些模块,让它们在 Python 2 和 3 中都能很好地工作。
Download StandardLibraryModules/http_future.py
from six.moves import http.client
from six.moves import http.cookies
from six.moves import http.cookiejar
from six.moves import http.server
XML-RPC
XML-RPC 是一个远程过程调用方法,它使用通过 HTTP 传递的 XML 作为传输。 1 因此,客户端可以在远程服务器上调用带参数的方法来获取结构化数据。
在 Python 2 中,有两个模块——DocXMLRPCServer 和 SimpleXMLRPCServer——和 xmlrpclib 来处理服务器和客户端 XML-RPC。
Download StandardLibraryModules/xmlrpc_py2.py
# for servers
import DocXMLRPCServer
import SimpleXMLRPCServer
# for clients
import xmlrpclib
前面的模块都组织在一个包 xmlrpc 中,该包包含两个模块,分别为客户机和服务器处理 xmlrpc。
**Download StandardLibraryModules/xmlrpc_py3.py**
import xmlrpc.client
import xmlrpc.server
在 pip 安装 future 之后,我们可以使用 Python 3 语法,它在 Python 2 和 Python 3 中都可以可靠地工作。
**Download StandardLibraryModules/xmlrpc_future.py**
import xmlrpc.client
import xmlrpc server
ifilterfalse
根据定义,ifilterfalse 返回那些 function(item)为 false 的序列项。如果函数为 None,则返回 false 项。在 Python 3 中,这个函数被重命名为 filterfalse。为了保持兼容性,我们将使用 Python-future 或 six,如下所示。
使用六
导入并使用重命名的值;也就是说,使用 filterfalse 而不是 ifilterfalse。
**Download StandardLibraryModules/filterfalse_six.py**
from six.moves import filterfalse
list=[1,2,3,4,5]
list(itertools.filterfalse(filterfalse, list))
使用未来
与 six 一样,从 future.moves.itertools 导入并使用 filterfalse。
**Download StandardLibraryModules/filterfalse_six.py**
from future.moves.itertools import filterfalse
list=[1,2,3,4,5]
list(itertools.filterfalse(filterfalse, list)
izip_longest
在 Python 3 中 izip_longest 被重命名为 zip _ longest 因此,为了兼容,请使用六个或更多选项。
使用六
导入并使用重命名的值;也就是用 zpl_longest 代替 iziplongest。
**Download StandardLibraryModules/filterfalse_six.py**
from six.moves import zip_longest
def solve(seq):
sentinel = object()
return [tuple(x for x in item if x is not sentinel) for item zip_longest(*seq, fillvalue=sentinel)]
使用未来
与 six 一样,从 future.moves.itertools 导入并使用 zip_longest。
**Download StandardLibraryModules/filterfalse_six.py**
from future.moves.itertools import zip+longest
def solve(seq):
sentinel = object()
return [tuple(x for x in item if x is not sentinel) for item zip_longest(*seq, fillvalue=sentinel)]
用户字典、用户列表和用户字符串
如果我们想在 Python 2 中导入这些模块,那么我们从单独的包中导入它们。
**Download StandardLibraryModules/user_py2.py**
from UserDict import UserDict
from UserList import UserList
from UserString import UserString
在 Python 3 中,它们都被重组为一个公共包,称为集合;因此,我们按如下方式导入它们:
**Download StandardLibraryModules/user_py3.py**
from collections import UserDict, UserList, UserString
For compatibility, we will use future or six.
使用六
从通用的 six.moves 包中导入它们。
from six.moves import UserDict, UserList, UserString
使用未来
从 future.moves.collections 包中导入它们。
from future.moves.collections import UserDict, UserList, UserString
Copy_reg
Python 2 中的 copy_reg 模块提供了一个注册表来注册我们自己的扩展类型。
**Download StandardLibraryModules/copy_reg_py2.py**
import copy_reg
def test_class(self):
self.assertRaises(TypeError, copy_reg.pickle, C, None, None)
这个模块在 Python 3 中被重命名为 copyreg。
**Download StandardLibraryModules/copy_reg_py.py**
import copyreg
def test_class(self):
self.assertRaises(TypeError, copyreg.pickle, C, None, None)
为了兼容,使用 future 或 six,如下所示。
使用六
从 six.moves 导入模块。
**Download StandardLibraryModules/copy_reg_six.py**
From six.moves import copyreg
def test_class(self):
self.assertRaises(TypeError, copyreg.pickle, C, None, None)
使用未来
pip 安装 future 后导入 copyreg,在 Python 2 和 3 中都能可靠工作。
**Download StandardLibraryModules/copy_reg_future.py**
import copyreg
def test_class(self):
self.assertRaises(TypeError, copyreg.pickle, C, None, None)
摘要
本章讨论了实现 socketserver、zip_longest 等标准库函数兼容性的技术。大多数函数都被弃用、重命名或重新组织。Python-future 的内置包和 six 的 six.moves 包给出了补救办法。
任务:Python-Jenkins
今天,你的任务来自一个叫做 Python-jenkins 的项目。该项目位于具有不兼容的 init 方法的 helper.py 文件中。
**Download StandardLibraryModules/task.py**
def __init__(self, server_address, *args, **kwargs):
# TCPServer is old style in python 2.x so cannot use
# super() correctly, explicitly call __init__.
# simply init'ing is sufficient to open the port, which
# with the server not started creates a black hole server
socketserver.TCPServer.__init__(
self, server_address, socketserver.BaseRequestHandler,
*args, **kwargs)
经过一些编辑,这段代码的兼容版本如下所示。
使用六
使用 six.moves 中的 socketserver 模块。
**Download StandardLibraryModules/task_six.py**
from six.moves import socketserver
def __init__(self, server_address, *args, **kwargs):
# TCPServer is old style in python 2.x so cannot use
# super() correctly, explicitly call __init__.
# simply init'ing is sufficient to open the port, which
# with the server not started creates a black hole server
socketserver.TCPServer.__init__(
self, server_address, socketserver.BaseRequestHandler,
*args, **kwargs)
使用未来
将来使用 socketserver 模块。
**Download StandardLibraryModules/task_future.py**
import socketserver
def __init__(self, server_address, *args, **kwargs):
# TCPServer is old style in python 2.x so cannot use
# super() correctly, explicitly call __init__.
# simply init'ing is sufficient to open the port, which
# with the server not started creates a black hole server
socketserver.TCPServer.__init__(
self, server_address, socketserver.BaseRequestHandler,
*args, **kwargs)