Python 3.2 中的新特性

作者:

Raymond Hettinger

本文件解釋了 Python 3.2 相較於 3.1 的新特性。Python 3.2 於 2011 年 2 月 20 日釋出。本文重點介紹了一些亮點並給出了一些示例。有關完整詳細資訊,請參閱 Misc/NEWS 檔案。

參見

PEP 392 - Python 3.2 釋出計劃

PEP 384: 定義穩定的 ABI

過去,為某個 Python 版本構建的擴充套件模組通常無法與其他 Python 版本一起使用。尤其是在 Windows 上,Python 的每個功能版本都需要重新構建所有要使用的擴充套件模組。此要求是擴充套件模組可以自由訪問 Python 直譯器內部的結果。

從 Python 3.2 開始,提供了一種替代方法:限制自身使用有限 API(透過定義 Py_LIMITED_API)的擴充套件模組不能使用許多內部功能,但受限於一組承諾在多個版本中保持穩定的 API 函式。因此,以這種模式為 3.2 構建的擴充套件模組也適用於 3.3、3.4 等。利用記憶體結構詳細資訊的擴充套件模組仍然可以構建,但需要針對每個功能版本重新編譯。

參見

PEP 384 - 定義穩定的 ABI

PEP 由 Martin von Löwis 撰寫。

PEP 389: Argparse 命令列解析模組

引入了一個新的命令列解析模組 argparse,以克服 optparse 的限制,後者不支援位置引數(不僅僅是選項)、子命令、必需選項以及其他常見的指定和驗證選項的模式。

作為第三方模組,該模組已在社群中取得了廣泛成功。與它的前身相比,argparse 模組功能更全面,現在是命令列處理的首選模組。舊模組仍然可用,因為它依賴於大量的舊程式碼。

這是一個帶註釋的解析器示例,展示了以下功能:將結果限制到一組選擇、在幫助螢幕中指定 metavar 、驗證一個或多個位置引數是否存在,以及建立一個必需選項。

import argparse
parser = argparse.ArgumentParser(
            description = 'Manage servers',         # main description for help
            epilog = 'Tested on Solaris and Linux') # displayed after help
parser.add_argument('action',                       # argument name
            choices = ['deploy', 'start', 'stop'],  # three allowed values
            help = 'action on each target')         # help msg
parser.add_argument('targets',
            metavar = 'HOSTNAME',                   # var name used in help msg
            nargs = '+',                            # require one or more targets
            help = 'url for target machines')       # help msg explanation
parser.add_argument('-u', '--user',                 # -u or --user option
            required = True,                        # make it a required argument
            help = 'login as user')

在命令字串上呼叫解析器的示例。

>>> cmd = 'deploy sneezy.example.com sleepy.example.com -u skycaptain'
>>> result = parser.parse_args(cmd.split())
>>> result.action
'deploy'
>>> result.targets
['sneezy.example.com', 'sleepy.example.com']
>>> result.user
'skycaptain'

解析器自動生成的幫助示例。

>>> parser.parse_args('-h'.split())

usage: manage_cloud.py [-h] -u USER
                       {deploy,start,stop} HOSTNAME [HOSTNAME ...]

Manage servers

positional arguments:
  {deploy,start,stop}   action on each target
  HOSTNAME              url for target machines

optional arguments:
  -h, --help            show this help message and exit
  -u USER, --user USER  login as user

Tested on Solaris and Linux

argparse 的一個特別好的功能是能夠定義子解析器,每個子解析器都有自己的引數模式和幫助顯示。

import argparse
parser = argparse.ArgumentParser(prog='HELM')
subparsers = parser.add_subparsers()

parser_l = subparsers.add_parser('launch', help='Launch Control')   # first subgroup
parser_l.add_argument('-m', '--missiles', action='store_true')
parser_l.add_argument('-t', '--torpedos', action='store_true')

parser_m = subparsers.add_parser('move', help='Move Vessel',        # second subgroup
                                 aliases=('steer', 'turn'))         # equivalent names
parser_m.add_argument('-c', '--course', type=int, required=True)
parser_m.add_argument('-s', '--speed', type=int, default=0)
$ ./helm.py --help                         # top level help (launch and move)
$ ./helm.py launch --help                  # help for launch options
$ ./helm.py launch --missiles              # set missiles=True and torpedos=False
$ ./helm.py steer --course 180 --speed 5   # set movement parameters

參見

PEP 389 - 新的命令列解析模組

PEP 由 Steven Bethard 撰寫。

有關 optparse 差異的詳細資訊,請參閱 將 optparse 程式碼遷移到 argparse

PEP 391: 基於字典的日誌配置

logging 模組提供了兩種配置:一種是為每個選項呼叫函式,另一種是由以 configparser 格式儲存的外部檔案驅動。這些選項不提供從 JSON 或 YAML 檔案建立配置的靈活性,也不支援增量配置,而增量配置是指定命令列日誌器選項所必需的。

為了支援更靈活的樣式,該模組現在提供了 logging.config.dictConfig() ,用於使用純 Python 字典指定日誌配置。配置選項包括格式化程式、處理程式、過濾器和日誌器。這是一個配置字典的實際示例:

{"version": 1,
 "formatters": {"brief": {"format": "%(levelname)-8s: %(name)-15s: %(message)s"},
                "full": {"format": "%(asctime)s %(name)-15s %(levelname)-8s %(message)s"}
                },
 "handlers": {"console": {
                   "class": "logging.StreamHandler",
                   "formatter": "brief",
                   "level": "INFO",
                   "stream": "ext://sys.stdout"},
              "console_priority": {
                   "class": "logging.StreamHandler",
                   "formatter": "full",
                   "level": "ERROR",
                   "stream": "ext://sys.stderr"}
              },
 "root": {"level": "DEBUG", "handlers": ["console", "console_priority"]}}

如果該字典儲存在一個名為 conf.json 的檔案中,則可以使用以下程式碼載入和呼叫它:

>>> import json, logging.config
>>> with open('conf.json') as f:
...     conf = json.load(f)
...
>>> logging.config.dictConfig(conf)
>>> logging.info("Transaction completed normally")
INFO    : root           : Transaction completed normally
>>> logging.critical("Abnormal termination")
2011-02-17 11:14:36,694 root            CRITICAL Abnormal termination

參見

PEP 391 - 基於字典的日誌配置

PEP 由 Vinay Sajip 撰寫。

PEP 3148: concurrent.futures 模組

用於建立和管理併發的程式碼正在收集到一個新的頂級名稱空間 concurrent 中。它的第一個成員是一個 futures 包,它提供了一個統一的高階介面來管理執行緒和程序。

concurrent.futures 的設計靈感來源於 java.util.concurrent 包。在該模型中,一個正在執行的呼叫及其結果由一個 Future 物件表示,該物件抽象了執行緒、程序和遠端過程呼叫的共同特性。該物件支援狀態檢查(執行中或已完成)、超時、取消、添加回調以及訪問結果或異常。

新模組的主要功能是提供一對執行器類,用於啟動和管理呼叫。執行器的目標是使並行呼叫現有工具變得更容易。它們省去了設定資源池、啟動呼叫、建立結果佇列、新增超時處理以及限制執行緒、程序或遠端過程呼叫總數所需的工作。

理想情況下,每個應用程式都應該在多個元件之間共享一個執行器,這樣就可以集中管理程序和執行緒限制。這解決了每個元件都有自己的競爭資源管理策略時出現的設計挑戰。

這兩個類共享一個通用介面,具有三個方法:submit() 用於排程可呼叫物件並返回一個 Future 物件;map() 用於一次排程許多非同步呼叫;以及 shutdown() 用於釋放資源。該類是一個 上下文管理器,可以在 with 語句中使用,以確保在當前待處理的 Future 執行完畢後自動釋放資源。

一個 ThreadPoolExecutor 的簡單示例是啟動四個並行執行緒來複制檔案:

import concurrent.futures, shutil
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as e:
    e.submit(shutil.copy, 'src1.txt', 'dest1.txt')
    e.submit(shutil.copy, 'src2.txt', 'dest2.txt')
    e.submit(shutil.copy, 'src3.txt', 'dest3.txt')
    e.submit(shutil.copy, 'src3.txt', 'dest4.txt')

參見

PEP 3148 - Futures – 非同步執行計算

PEP 由 Brian Quinlan 撰寫。

執行緒並行 URL 讀取程式碼,一個使用執行緒並行獲取多個網頁的示例。

平行計算素數程式碼,一個演示 ProcessPoolExecutor 的示例。

PEP 3147: PYC 儲存庫目錄

Python 的將位元組碼快取到 .pyc 檔案中的方案在多個 Python 直譯器環境中執行不佳。如果一個直譯器遇到由另一個直譯器建立的快取檔案,它將重新編譯原始碼並覆蓋快取檔案,從而失去快取的好處。

隨著 Linux 發行版普遍附帶多個 Python 版本,“pyc 衝突”問題變得更加突出。這些衝突也出現在 CPython 的替代品中,例如 Unladen Swallow。

為了解決這個問題,Python 的匯入機制已擴充套件為每個直譯器使用不同的檔名。Python 3.2、Python 3.3 和 Unladen Swallow 不再爭奪名為“mymodule.pyc”的檔案,而是會查詢“mymodule.cpython-32.pyc”、“mymodule.cpython-33.pyc”和“mymodule.unladen10.pyc”。為了防止所有這些新檔案弄亂源目錄,pyc 檔案現在收集在包目錄下的“__pycache__”目錄中。

除了檔名和目標目錄之外,新方案還有一些對程式設計師可見的方面:

  • 匯入的模組現在具有 __cached__ 屬性,該屬性儲存實際匯入的檔名。

    >>> import collections
    >>> collections.__cached__
    'c:/py32/lib/__pycache__/collections.cpython-32.pyc'
    
  • 每個直譯器唯一的標籤可從 imp 模組訪問。

    >>> import imp
    >>> imp.get_tag()
    'cpython-32'
    
  • 嘗試從匯入檔案推斷原始檔名的指令碼現在需要更智慧。簡單地從“.pyc”檔名中去掉“c”已不再足夠。相反,請使用 imp 模組中的新函式。

    >>> imp.source_from_cache('c:/py32/lib/__pycache__/collections.cpython-32.pyc')
    'c:/py32/lib/collections.py'
    >>> imp.cache_from_source('c:/py32/lib/collections.py')
    'c:/py32/lib/__pycache__/collections.cpython-32.pyc'
    
  • py_compilecompileall 模組已更新以反映新的命名約定和目標目錄。compileall 的命令列呼叫具有新選項:-i 用於指定要編譯的檔案和目錄列表,-b 用於將位元組碼檔案寫入其舊位置而不是 __pycache__

  • importlib.abc 模組已更新,其中包含用於載入位元組碼檔案的新 抽象基類。過時的 ABC,PyLoaderPyPycLoader,已被棄用(文件中包含如何保持 Python 3.1 相容性的說明)。

參見

PEP 3147 - PYC 儲存庫目錄

PEP 由 Barry Warsaw 撰寫。

PEP 3149: 帶 ABI 版本標籤的 .so 檔案

PYC 儲存庫目錄允許共同定位多個位元組碼快取檔案。此 PEP 為共享物件檔案實現了類似的機制,透過為它們提供一個公共目錄和每個版本的不同名稱。

公共目錄是“pyshared”,檔名透過標識 Python 實現(例如 CPython、PyPy、Jython 等)、主要和次要版本號以及可選的構建標誌(例如“d”表示除錯,“m”表示 pymalloc,“u”表示寬 Unicode)來區分。對於任意包“foo”,當安裝分發包時,您可能會看到這些檔案:

/usr/share/pyshared/foo.cpython-32m.so
/usr/share/pyshared/foo.cpython-33md.so

在 Python 本身中,標籤可以透過 sysconfig 模組中的函式訪問:

>>> import sysconfig
>>> sysconfig.get_config_var('SOABI')       # find the version tag
'cpython-32mu'
>>> sysconfig.get_config_var('EXT_SUFFIX')  # find the full filename extension
'.cpython-32mu.so'

參見

PEP 3149 - ABI 版本標記的 .so 檔案

PEP 由 Barry Warsaw 撰寫。

PEP 3333: Python Web 伺服器閘道器介面 v1.0.1

此資訊性 PEP 闡明瞭 WSGI 協議如何處理位元組/文字問題。挑戰在於 Python 3 中的字串處理最方便地使用 str 型別,儘管 HTTP 協議本身是面向位元組的。

該 PEP 區分了用於請求/響應頭和元資料的所謂 原生字串 與用於請求和響應主體的 位元組字串

原生字串 始終是 str 型別,但僅限於 U+0000U+00FF 之間的碼點,這些碼點可以使用 Latin-1 編碼轉換為位元組。這些字串用於環境字典中的鍵和值,以及 start_response() 函式中的響應頭和狀態。它們必須遵循 RFC 2616 關於編碼的規定。也就是說,它們必須是 ISO-8859-1 字元或使用 RFC 2047 MIME 編碼。

對於從 Python 2 移植 WSGI 應用程式的開發人員,以下是主要幾點:

  • 如果應用程式在 Python 2 中已經將字串用於頭部,則無需更改。

  • 如果應用程式而是編碼輸出頭部或解碼輸入頭部,則頭部需要重新編碼為 Latin-1。例如,以前使用 h.encode('utf-8') 編碼為 utf-8 的輸出頭部現在需要使用 h.encode('utf-8').decode('latin-1') 從位元組轉換為原生字串。

  • 應用程式生成或使用 write() 方法傳送的值必須是位元組字串。start_response() 函式和 environ 必須使用原生字串。兩者不能混用。

對於編寫 CGI 到 WSGI 路徑或其他 CGI 樣式協議的伺服器實現者,使用者必須能夠使用原生字串訪問環境,即使底層平臺可能有不同的約定。為了彌合這一差距,wsgiref 模組有一個新函式 wsgiref.handlers.read_environ(),用於將 os.environ 中的 CGI 變數轉碼為原生字串並返回一個新的字典。

參見

PEP 3333 - Python Web 伺服器閘道器介面 v1.0.1

PEP 由 Phillip Eby 撰寫。

其他語言更改

對核心 Python 語言做了一些較小的更改

  • format()str.format() 的字串格式化獲得了格式字元 # 的新功能。以前,對於二進位制、八進位制或十六進位制的整數,它會導致輸出分別以“0b”、“0o”或“0x”為字首。現在它還可以處理浮點數、複數和 Decimal,使輸出始終具有小數點,即使後面沒有數字。

    >>> format(20, '#o')
    '0o24'
    >>> format(12.34, '#5.0f')
    '  12.'
    

    (由 Mark Dickinson 建議,並由 Eric Smith 在 bpo-7094 中實現。)

  • 還有一個新的 str.format_map() 方法,它透過接受任意 對映 物件來擴充套件現有 str.format() 方法的功能。這種新方法使得可以使用 Python 眾多字典類物件(例如 defaultdictShelfConfigParserdbm)進行字串格式化。它對於在查詢之前規範化鍵或為未知鍵提供 __missing__() 方法的自定義 dict 子類也很有用:

    >>> import shelve
    >>> d = shelve.open('tmp.shl')
    >>> 'The {project_name} status is {status} as of {date}'.format_map(d)
    'The testing project status is green as of February 15, 2011'
    
    >>> class LowerCasedDict(dict):
    ...     def __getitem__(self, key):
    ...         return dict.__getitem__(self, key.lower())
    ...
    >>> lcd = LowerCasedDict(part='widgets', quantity=10)
    >>> 'There are {QUANTITY} {Part} in stock'.format_map(lcd)
    'There are 10 widgets in stock'
    
    >>> class PlaceholderDict(dict):
    ...     def __missing__(self, key):
    ...         return '<{}>'.format(key)
    ...
    >>> 'Hello {name}, welcome to {location}'.format_map(PlaceholderDict())
    'Hello <name>, welcome to <location>'
    

(由 Raymond Hettinger 建議,並由 Eric Smith 在 bpo-6081 中實現。)

  • 直譯器現在可以使用靜默選項 -q 啟動,以防止在互動模式下顯示版權和版本資訊。該選項可以使用 sys.flags 屬性進行自檢:

    $ python -q
    >>> sys.flags
    sys.flags(debug=0, division_warning=0, inspect=0, interactive=0,
    optimize=0, dont_write_bytecode=0, no_user_site=0, no_site=0,
    ignore_environment=0, verbose=0, bytes_warning=0, quiet=1)
    

    (由 Marcin Wojdyr 在 bpo-1772833 中貢獻)。

  • hasattr() 函式透過呼叫 getattr() 並檢測是否引發異常來工作。這種技術允許它檢測由 __getattr__()__getattribute__() 動態建立的方法,否則這些方法將不存在於類字典中。以前,hasattr 會捕獲任何異常,可能會掩蓋真正的錯誤。現在,hasattr 已收緊到只捕獲 AttributeError 並讓其他異常透過:

    >>> class A:
    ...     @property
    ...     def f(self):
    ...         return 1 // 0
    ...
    >>> a = A()
    >>> hasattr(a, 'f')
    Traceback (most recent call last):
      ...
    ZeroDivisionError: integer division or modulo by zero
    

    (由 Yury Selivanov 發現,Benjamin Peterson 修復;bpo-9666。)

  • 浮點數或複數的 str() 現在與它的 repr() 相同。以前,str() 形式更短,但這隻會導致混淆,現在預設顯示最短的 repr(),因此不再需要了:

    >>> import math
    >>> repr(math.pi)
    '3.141592653589793'
    >>> str(math.pi)
    '3.141592653589793'
    

    (由 Mark Dickinson 提出並實現;bpo-9337。)

  • memoryview 物件現在具有 release() 方法,並且它們現在也支援上下文管理協議。這允許及時釋放從原始物件請求緩衝區時獲取的任何資源。

    >>> with memoryview(b'abcdefgh') as v:
    ...     print(v.tolist())
    [97, 98, 99, 100, 101, 102, 103, 104]
    

    (由 Antoine Pitrou 新增;bpo-9757。)

  • 以前,如果一個名稱作為自由變量出現在巢狀塊中,則從區域性名稱空間中刪除該名稱是非法的:

    def outer(x):
        def inner():
            return x
        inner()
        del x
    

    現在允許這樣做。請記住,except 子句的目標會被清除,因此這段程式碼在 Python 2.6 中可以工作,但在 Python 3.1 中會引發 SyntaxError,現在又可以工作了:

    def f():
        def print_error():
            print(e)
        try:
            something
        except Exception as e:
            print_error()
            # implicit "del e" here
    

    (參見 bpo-4617。)

  • 結構序列型別 現在是元組的子類。這意味著 C 結構,例如由 os.stat()time.gmtime()sys.version_info 返回的那些,現在像 命名元組 一樣工作,並且現在可以與期望元組作為引數的函式和方法一起工作。這是使 C 結構像純 Python 對應物一樣靈活的一大步:

    >>> import sys
    >>> isinstance(sys.version_info, tuple)
    True
    >>> 'Version %d.%d.%d %s(%d)' % sys.version_info
    'Version 3.2.0 final(0)'
    

    (由 Arfrever Frehtes Taifersar Arahesis 建議,並由 Benjamin Peterson 在 bpo-8413 中實現。)

  • 現在,使用 PYTHONWARNINGS 環境變數可以更容易地控制警告,作為在命令列使用 -W 的替代方法:

    $ export PYTHONWARNINGS='ignore::RuntimeWarning::,once::UnicodeWarning::'
    

    (由 Barry Warsaw 建議,並由 Philip Jenvey 在 bpo-7301 中實現。)

  • 添加了一個新的警告類別 ResourceWarning。當檢測到資源消耗或清理的潛在問題時會發出該警告。在正常釋出版本中,它預設被停用,但可以透過 warnings 模組提供的方式或在命令列上啟用。

    如果 gc.garbage 列表不為空,並且 gc.DEBUG_UNCOLLECTABLE 已設定,則在直譯器關閉時會發出 ResourceWarning,並列印所有不可回收物件。這旨在讓程式設計師意識到他們的程式碼存在物件終結問題。

    當一個 檔案物件 在沒有明確關閉的情況下被銷燬時,也會發出 ResourceWarning。雖然此類物件的解構函式確保它關閉底層作業系統資源(通常是檔案描述符),但延遲釋放物件可能會產生各種問題,尤其是在 Windows 下。以下是從命令列啟用警告的示例:

    $ python -q -Wdefault
    >>> f = open("foo", "wb")
    >>> del f
    __main__:1: ResourceWarning: unclosed file <_io.BufferedWriter name='foo'>
    

    (由 Antoine Pitrou 和 Georg Brandl 在 bpo-10093bpo-477863 中新增。)

  • range 物件現在支援 indexcount 方法。這是為了使更多物件完全實現 collections.Sequence 抽象基類 的努力的一部分。因此,該語言將具有更統一的 API。此外,range 物件現在支援切片和負索引,即使值大於 sys.maxsize。這使得 range 與列表的互操作性更好:

    >>> range(0, 100, 2).count(10)
    1
    >>> range(0, 100, 2).index(10)
    5
    >>> range(0, 100, 2)[5]
    10
    >>> range(0, 100, 2)[0:5]
    range(0, 10, 2)
    

    (由 Daniel Stutzbach 在 bpo-9213 中貢獻,Alexander Belopolsky 在 bpo-2690 中貢獻,Nick Coghlan 在 bpo-10889 中貢獻。)

  • Py2.x 中的內建函式 callable() 被恢復了。它提供了一種簡潔、可讀的替代方法,用於在像 isinstance(x, collections.Callable) 這樣的表示式中使用 抽象基類

    >>> callable(max)
    True
    >>> callable(20)
    False
    

    (參見 bpo-10518。)

  • Python 的匯入機制現在可以載入安裝在路徑名中包含非 ASCII 字元的目錄中的模組。這解決了使用者主目錄中存在非 ASCII 字元時的一個令人惱火的問題。

(Victor Stinner 在 bpo-9425 中進行了大量工作才得以實現。)

新的、改進的和已棄用的模組

Python 的標準庫進行了大量的維護工作和質量改進。

Python 3.2 的最大新聞是 email 包、mailbox 模組和 nntplib 模組現在在 Python 3 中可以正確處理位元組/文字模型。首次正確處理了混合編碼的訊息。

在整個標準庫中,對編碼和文字與位元組問題給予了更仔細的關注。特別是,與作業系統的互動現在能夠更好地使用 Windows MBCS 編碼、區域設定感知編碼或 UTF-8 交換非 ASCII 資料。

另一個重要的勝利是為 SSL 連線和安全證書添加了顯著更好的支援。

此外,更多類現在實現了 上下文管理器,以支援使用 with 語句進行方便可靠的資源清理。

email

在 Python 3 中,email 包的可用性已透過 R. David Murray 的大量努力基本修復。問題在於電子郵件通常以 bytes 而不是 str 文字的形式讀取和儲存,並且它們可能在單個電子郵件中包含多種編碼。因此,必須擴充套件 email 包以位元組格式解析和生成電子郵件訊息。

  • 新函式 message_from_bytes()message_from_binary_file(),以及新類 BytesFeedParserBytesParser 允許將二進位制訊息資料解析為模型物件。

  • 給定模型的位元組輸入,如果訊息正文的 Content-Transfer-Encoding8bit,則 get_payload() 預設會使用 MIME 頭部中指定的字元集對其進行解碼,並返回結果字串。

  • 給定模型的位元組輸入,Generator 將把 Content-Transfer-Encoding8bit 的訊息體轉換為 7bit Content-Transfer-Encoding

    帶有未編碼非 ASCII 位元組的頭部被視為使用 unknown-8bit 字元集進行 RFC 2047 編碼。

  • 新類 BytesGenerator 生成位元組輸出,保留用於構建模型的輸入中存在的任何未更改的非 ASCII 資料,包括 Content-Transfer-Encoding8bit 的訊息體。

  • smtplib SMTP 類現在接受用於 sendmail() 方法的 msg 引數的位元組字串,並且新方法 send_message() 接受 Message 物件,並且可以選擇直接從物件獲取 from_addrto_addrs 地址。

(由 R. David Murray 提出並實現,bpo-4661bpo-10321。)

elementtree

xml.etree.ElementTree 包及其對應的 xml.etree.cElementTree 已更新到版本 1.3。

添加了幾個新的有用函式和方法:

有兩個方法已被棄用:

  • xml.etree.ElementTree.getchildren() 改用 list(elem)

  • xml.etree.ElementTree.getiterator() 改用 Element.iter

有關更新詳情,請參閱 Fredrik Lundh 網站上的 Introducing ElementTree

(由 Florent Xicluna 和 Fredrik Lundh 貢獻,bpo-6472。)

functools

  • functools 模組包含一個用於快取函式呼叫的新裝飾器。functools.lru_cache() 可以節省對外部資源的重複查詢,只要結果預期相同。

    例如,向資料庫查詢函式新增快取裝飾器可以節省對流行搜尋的資料庫訪問:

    >>> import functools
    >>> @functools.lru_cache(maxsize=300)
    ... def get_phone_number(name):
    ...     c = conn.cursor()
    ...     c.execute('SELECT phonenumber FROM phonelist WHERE name=?', (name,))
    ...     return c.fetchone()[0]
    
    >>> for name in user_requests:
    ...     get_phone_number(name)        # cached lookup
    

    為了幫助選擇有效的快取大小,包裝函式會進行測量以跟蹤快取統計資訊:

    >>> get_phone_number.cache_info()
    CacheInfo(hits=4805, misses=980, maxsize=300, currsize=300)
    

    如果電話列表表已更新,可以使用以下方法清除快取中過時的內容:

    >>> get_phone_number.cache_clear()
    

    (由 Raymond Hettinger 貢獻,並結合了 Jim Baker、Miki Tebeka 和 Nick Coghlan 的設計思想;參見 recipe 498245recipe 577479bpo-10586bpo-10593。)

  • functools.wraps() 裝飾器現在添加了一個 __wrapped__ 屬性,指向原始可呼叫函式。這使得可以對包裝函式進行內省。如果定義了 __annotations__,它也會複製它。現在它還會優雅地跳過缺失的屬性,例如包裝的可呼叫函式可能未定義的 __doc__

    在上面的例子中,可以透過恢復原始函式來移除快取:

    >>> get_phone_number = get_phone_number.__wrapped__    # uncached function
    

    (由 Nick Coghlan 和 Terrence Cole;bpo-9567bpo-3445bpo-8814。)

  • 為了幫助編寫具有豐富比較方法的類,一個新的裝飾器 functools.total_ordering() 將使用現有的相等和不等方法來填充其餘的方法。

    例如,提供 __eq____lt__ 將使 total_ordering() 填充 __le____gt____ge__

    @total_ordering
    class Student:
        def __eq__(self, other):
            return ((self.lastname.lower(), self.firstname.lower()) ==
                    (other.lastname.lower(), other.firstname.lower()))
    
        def __lt__(self, other):
            return ((self.lastname.lower(), self.firstname.lower()) <
                    (other.lastname.lower(), other.firstname.lower()))
    

    使用 total_ordering 裝飾器,其餘的比較方法會自動填充。

    (由 Raymond Hettinger 貢獻。)

  • 為了幫助從 Python 2 移植程式,functools.cmp_to_key() 函式將舊式比較函式轉換為現代 鍵函式

    >>> # locale-aware sort order
    >>> sorted(iterable, key=cmp_to_key(locale.strcoll))
    

    有關排序示例和簡短排序教程,請參閱 Sorting HowTo 教程。

    (由 Raymond Hettinger 貢獻。)

itertools

  • itertools 模組有一個新的 accumulate() 函式,它模仿了 APL 的 scan 運算子和 Numpy 的 accumulate 函式:

    >>> from itertools import accumulate
    >>> list(accumulate([8, 2, 50]))
    [8, 10, 60]
    
    >>> prob_dist = [0.1, 0.4, 0.2, 0.3]
    >>> list(accumulate(prob_dist))      # cumulative probability distribution
    [0.1, 0.5, 0.7, 1.0]
    

    有關使用 accumulate() 的示例,請參閱 random 模組的示例

    (由 Raymond Hettinger 貢獻,並結合了 Mark Dickinson 的設計建議。)

collections

  • collections.Counter 類現在有兩種形式的原地減法,現有的 -= 運算子用於 飽和減法,以及新的 subtract() 方法用於常規減法。前者適用於只有正計數的 多重集,後者更適用於允許負計數的使用場景:

    >>> from collections import Counter
    >>> tally = Counter(dogs=5, cats=3)
    >>> tally -= Counter(dogs=2, cats=8)    # saturating subtraction
    >>> tally
    Counter({'dogs': 3})
    
    >>> tally = Counter(dogs=5, cats=3)
    >>> tally.subtract(dogs=2, cats=8)      # regular subtraction
    >>> tally
    Counter({'dogs': 3, 'cats': -5})
    

    (由 Raymond Hettinger 貢獻。)

  • collections.OrderedDict 類有一個新方法 move_to_end(),它接受一個現有鍵並將其移動到有序序列的第一個或最後一個位置。

    預設是將專案移動到最後一個位置。這相當於使用 od[k] = od.pop(k) 續訂條目。

    快速的移至末尾操作對於重新排序條目很有用。例如,有序字典可以用於透過使條目從最舊到最近訪問來跟蹤訪問順序。

    >>> from collections import OrderedDict
    >>> d = OrderedDict.fromkeys(['a', 'b', 'X', 'd', 'e'])
    >>> list(d)
    ['a', 'b', 'X', 'd', 'e']
    >>> d.move_to_end('X')
    >>> list(d)
    ['a', 'b', 'd', 'e', 'X']
    

    (由 Raymond Hettinger 貢獻。)

  • collections.deque 類新增了兩個方法 count()reverse(),使其更接近 list 物件的替代品:

    >>> from collections import deque
    >>> d = deque('simsalabim')
    >>> d.count('s')
    2
    >>> d.reverse()
    >>> d
    deque(['m', 'i', 'b', 'a', 'l', 'a', 's', 'm', 'i', 's'])
    

    (由 Raymond Hettinger 貢獻。)

threading

threading 模組有一個新的 Barrier 同步類,用於使多個執行緒等待所有執行緒都達到一個共同的屏障點。屏障對於確保具有多個前提條件的任務在所有前置任務完成之前不執行很有用。

屏障可以與任意數量的執行緒一起工作。這是 會合點 的泛化,後者僅適用於兩個執行緒。

作為兩階段迴圈屏障實現,Barrier 物件適合在迴圈中使用。獨立的 填充排出 階段確保所有執行緒在任何一個執行緒迴圈返回並重新進入屏障之前都被釋放(排出)。每個迴圈後屏障完全重置。

使用屏障的示例:

from threading import Barrier, Thread

def get_votes(site):
    ballots = conduct_election(site)
    all_polls_closed.wait()        # do not count until all polls are closed
    totals = summarize(ballots)
    publish(site, totals)

all_polls_closed = Barrier(len(sites))
for site in sites:
    Thread(target=get_votes, args=(site,)).start()

在此示例中,屏障強制執行以下規則:在所有投票站關閉之前,不得在任何投票站計票。請注意,使用屏障的解決方案與使用 threading.Thread.join() 的解決方案類似,但執行緒在屏障點之後仍然存活並繼續工作(彙總選票)。

如果任何前置任務可能掛起或延遲,則可以建立一個帶可選 timeout 引數的屏障。然後,如果在所有前置任務到達屏障點之前超時期限已過,則所有等待執行緒都將被釋放,並引發 BrokenBarrierError 異常:

def get_votes(site):
    ballots = conduct_election(site)
    try:
        all_polls_closed.wait(timeout=midnight - time.now())
    except BrokenBarrierError:
        lockbox = seal_ballots(ballots)
        queue.put(lockbox)
    else:
        totals = summarize(ballots)
        publish(site, totals)

在這個例子中,屏障強制執行更嚴格的規則。如果某些選舉站點在午夜之前未完成,則屏障超時,選票將被封存並存入佇列中以供以後處理。

有關如何在平行計算中使用屏障的更多示例,請參閱 Barrier Synchronization Patterns。此外,在 The Little Book of Semaphores3.6 節 中,對屏障有簡單而全面的解釋。

(由 Kristján Valur Jónsson 貢獻,API 審查由 Jeffrey Yasskin 在 bpo-8777 中完成。)

datetime 和 time

  • datetime 模組有一個新型別 timezone,它透過返回固定的 UTC 偏移量和時區名稱來實現 tzinfo 介面。這使得建立時區感知的 datetime 物件變得更容易:

    >>> from datetime import datetime, timezone
    
    >>> datetime.now(timezone.utc)
    datetime.datetime(2010, 12, 8, 21, 4, 2, 923754, tzinfo=datetime.timezone.utc)
    
    >>> datetime.strptime("01/01/2000 12:00 +0000", "%m/%d/%Y %H:%M %z")
    datetime.datetime(2000, 1, 1, 12, 0, tzinfo=datetime.timezone.utc)
    
  • 此外,timedelta 物件現在可以乘以 float,並可以除以 floatint 物件。並且 timedelta 物件現在可以相互除以。

  • datetime.date.strftime() 方法不再受限於 1900 年之後的年份。新的支援年份範圍為 1000 到 9999(含)。

  • 在時間元組中使用兩位數年份時,解釋由 time.accept2dyear 控制。預設值為 True,這意味著對於兩位數年份,世紀會根據 POSIX 規則(控制 %y strptime 格式)進行猜測。

    從 Py3.2 開始,使用世紀猜測啟發式將發出 DeprecationWarning。相反,建議將 time.accept2dyear 設定為 False,以便可以在不猜測的情況下使用大範圍日期:

    >>> import time, warnings
    >>> warnings.resetwarnings()      # remove the default warning filters
    
    >>> time.accept2dyear = True      # guess whether 11 means 11 or 2011
    >>> time.asctime((11, 1, 1, 12, 34, 56, 4, 1, 0))
    Warning (from warnings module):
      ...
    DeprecationWarning: Century info guessed for a 2-digit year.
    'Fri Jan  1 12:34:56 2011'
    
    >>> time.accept2dyear = False     # use the full range of allowable dates
    >>> time.asctime((11, 1, 1, 12, 34, 56, 4, 1, 0))
    'Fri Jan  1 12:34:56 11'
    

    現在有幾個函式具有顯著擴充套件的日期範圍。當 time.accept2dyear 為 false 時,time.asctime() 函式將接受適合 C int 的任何年份,而 time.mktime()time.strftime() 函式將接受相應作業系統函式支援的完整範圍。

(由 Alexander Belopolsky 和 Victor Stinner 在 bpo-1289118bpo-5094bpo-6641bpo-2706bpo-1777412bpo-8013bpo-10827 中貢獻。)

math

math 模組已更新,增加了六個受 C99 標準啟發的函式。

isfinite() 函式提供了一種可靠快速的方式來檢測特殊值。它對常規數字返回 True,對 NanInfinity 返回 False

>>> from math import isfinite
>>> [isfinite(x) for x in (123, 4.56, float('Nan'), float('Inf'))]
[True, True, False, False]

expm1() 函式計算小 x 值的 e**x-1,而不會導致通常伴隨接近相等數量的減法而發生的精度損失:

>>> from math import expm1
>>> expm1(0.013671875)   # more accurate way to compute e**x-1 for a small x
0.013765762467652909

erf() 函式計算機率積分或 高斯誤差函式。互補誤差函式 erfc()1 - erf(x)

>>> from math import erf, erfc, sqrt
>>> erf(1.0/sqrt(2.0))   # portion of normal distribution within 1 standard deviation
0.682689492137086
>>> erfc(1.0/sqrt(2.0))  # portion of normal distribution outside 1 standard deviation
0.31731050786291404
>>> erf(1.0/sqrt(2.0)) + erfc(1.0/sqrt(2.0))
1.0

gamma() 函式是階乘函式的連續擴充套件。有關詳細資訊,請參見 https://en.wikipedia.org/wiki/Gamma_function。由於該函式與階乘相關,即使對於小 x 值,它也會變得很大,因此還有一個 lgamma() 函式用於計算伽馬函式的自然對數:

>>> from math import gamma, lgamma
>>> gamma(7.0)           # six factorial
720.0
>>> lgamma(801.0)        # log(800 factorial)
4551.950730698041

(由 Mark Dickinson 貢獻。)

abc

abc 模組現在支援 abstractclassmethod()abstractstaticmethod()

這些工具使得可以定義一個 抽象基類,該類要求實現特定的 classmethod()staticmethod()

class Temperature(metaclass=abc.ABCMeta):
    @abc.abstractclassmethod
    def from_fahrenheit(cls, t):
        ...
    @abc.abstractclassmethod
    def from_celsius(cls, t):
        ...

(Daniel Urban 提交的補丁;bpo-5867。)

io

io.BytesIO 有一個新方法 getbuffer(),它提供了類似於 memoryview() 的功能。它建立了資料的可編輯檢視,而無需進行復制。緩衝區的隨機訪問和對切片表示法的支援非常適合原地編輯:

>>> REC_LEN, LOC_START, LOC_LEN = 34, 7, 11

>>> def change_location(buffer, record_number, location):
...     start = record_number * REC_LEN + LOC_START
...     buffer[start: start+LOC_LEN] = location

>>> import io

>>> byte_stream = io.BytesIO(
...     b'G3805  storeroom  Main chassis    '
...     b'X7899  shipping   Reserve cog     '
...     b'L6988  receiving  Primary sprocket'
... )
>>> buffer = byte_stream.getbuffer()
>>> change_location(buffer, 1, b'warehouse  ')
>>> change_location(buffer, 0, b'showroom   ')
>>> print(byte_stream.getvalue())
b'G3805  showroom   Main chassis    '
b'X7899  warehouse  Reserve cog     '
b'L6988  receiving  Primary sprocket'

(由 Antoine Pitrou 在 bpo-5506 中貢獻。)

reprlib

在為自定義容器編寫 __repr__() 方法時,很容易忘記處理成員引用回容器本身的情況。Python 的內建物件,如 listset,透過在表示字串的遞迴部分顯示“...”來處理自引用。

為了幫助編寫此類 __repr__() 方法,reprlib 模組有一個新的裝飾器 recursive_repr(),用於檢測對 __repr__() 的遞迴呼叫並替換為佔位符字串:

>>> class MyList(list):
...     @recursive_repr()
...     def __repr__(self):
...         return '<' + '|'.join(map(repr, self)) + '>'
...
>>> m = MyList('abc')
>>> m.append(m)
>>> m.append('x')
>>> print(m)
<'a'|'b'|'c'|...|'x'>

(由 Raymond Hettinger 在 bpo-9826bpo-9840 中貢獻。)

logging

除了上面描述的基於字典的配置之外,logging 包還有許多其他改進。

日誌記錄文件已增加了 基本教程高階教程 和日誌記錄 食譜。這些文件是瞭解日誌記錄的最快方法。

logging.basicConfig() 設定函式獲得了 style 引數,以支援三種不同型別的字串格式化。它預設為“%”用於傳統 % 格式化,可以設定為“{”用於新的 str.format() 樣式,或者可以設定為“$”用於 string.Template 提供的 shell 樣式格式化。以下三種配置是等效的:

>>> from logging import basicConfig
>>> basicConfig(style='%', format="%(name)s -> %(levelname)s: %(message)s")
>>> basicConfig(style='{', format="{name} -> {levelname} {message}")
>>> basicConfig(style='$', format="$name -> $levelname: $message")

如果在日誌事件發生之前沒有進行任何配置,現在會有一個預設配置,使用一個指向 sys.stderrStreamHandler,用於 WARNING 級別或更高級別的事件。以前,在配置設定之前發生的事件會根據 logging.raiseExceptions 的值引發異常或默默丟棄事件。新的預設處理程式儲存在 logging.lastResort 中。

過濾器的使用已簡化。現在,謂詞可以是任何返回 TrueFalse 的 Python 可呼叫物件,而無需建立 Filter 物件。

還有許多其他改進增加了靈活性並簡化了配置。有關 Python 3.2 中所有更改的完整列表,請參閱模組文件。

csv

csv 模組現在支援一種新的方言,unix_dialect,它對所有欄位應用引用,並使用傳統的 Unix 樣式,以 '\n' 作為行終止符。註冊的方言名稱是 unix

csv.DictWriter 有一個新方法 writeheader(),用於寫入初始行以記錄欄位名稱:

>>> import csv, sys
>>> w = csv.DictWriter(sys.stdout, ['name', 'dept'], dialect='unix')
>>> w.writeheader()
"name","dept"
>>> w.writerows([
...     {'name': 'tom', 'dept': 'accounting'},
...     {'name': 'susan', 'dept': 'Salesl'}])
"tom","accounting"
"susan","sales"

(新方言由 Jay Talbot 在 bpo-5975 中建議,新方法由 Ed Abraham 在 bpo-1537721 中建議。)

contextlib

有一個新的、稍微令人驚歎的工具 ContextDecorator,它對於建立既能充當 上下文管理器 又能充當函式裝飾器的工具很有幫助。

為方便起見,contextmanager() 使用了此新功能,因此無需額外努力即可支援這兩種角色。

基本思想是,上下文管理器和函式裝飾器都可以用於前置動作和後置動作的包裝器。上下文管理器使用 with 語句包裝一組語句,而函式裝飾器包裝函式中包含的一組語句。因此,有時需要編寫一個既能作為前置動作或後置動作包裝器又能作為函式裝飾器的包裝器。

例如,有時用一個可以跟蹤進入和退出時間的日誌器來包裝函式或語句組是很有用的。與其為該任務編寫一個函式裝飾器和一個上下文管理器,contextmanager() 在一個定義中提供了這兩種功能:

from contextlib import contextmanager
import logging

logging.basicConfig(level=logging.INFO)

@contextmanager
def track_entry_and_exit(name):
    logging.info('Entering: %s', name)
    yield
    logging.info('Exiting: %s', name)

以前,這隻能作為上下文管理器使用:

with track_entry_and_exit('widget loader'):
    print('Some time consuming activity goes here')
    load_widget()

現在,它也可以用作裝飾器:

@track_entry_and_exit('widget loader')
def activity():
    print('Some time consuming activity goes here')
    load_widget()

試圖同時扮演兩個角色對這種技術施加了一些限制。上下文管理器通常可以靈活地返回一個可被 with 語句使用的引數,但函式裝飾器沒有類似的並行功能。

在上面的例子中,track_entry_and_exit 上下文管理器沒有一種乾淨的方法可以返回一個日誌例項,供包含的語句體使用。

(由 Michael Foord 在 bpo-9110 中貢獻。)

decimal 和 fractions

Mark Dickinson 精心設計了一個優雅而高效的方案,用於確保當不同數字資料型別的實際值相等時,它們將具有相同的雜湊值 (bpo-8188)

assert hash(Fraction(3, 2)) == hash(1.5) == \
       hash(Decimal("1.5")) == hash(complex(1.5, 0))

一些雜湊細節透過一個新屬性 sys.hash_info 暴露出來,它描述了雜湊值的位寬、素數模、_無窮大_和 _nan_ 的雜湊值,以及用於數字虛部的乘數。

>>> sys.hash_info
sys.hash_info(width=64, modulus=2305843009213693951, inf=314159, nan=0, imag=1000003)

早期限制各種數字型別互操作性的決定已放寬。在算術表示式中仍然不支援(也不建議)隱式混合,例如 Decimal('1.1') + float('1.1'),因為後者在構建二進位制浮點數時會丟失資訊。然而,由於現有的浮點值可以無損地轉換為十進位制或有理數表示,因此將它們新增到建構函式並支援混合型別比較是有意義的。

fractions.Fraction 也進行了類似更改,因此不再需要 from_float()from_decimal() 方法 (bpo-8294)。

>>> from decimal import Decimal
>>> from fractions import Fraction
>>> Decimal(1.1)
Decimal('1.100000000000000088817841970012523233890533447265625')
>>> Fraction(1.1)
Fraction(2476979795053773, 2251799813685248)

decimal 模組的另一個有用更改是 Context.clamp 屬性現在是公共的。這在建立與 IEEE 754 中指定的十進位制交換格式對應的上下文時很有用(參見 bpo-8540)。

(由 Mark Dickinson 和 Raymond Hettinger 貢獻。)

FTP

ftplib.FTP 類現在支援上下文管理協議,以無條件地處理 socket.error 異常並在完成後關閉 FTP 連線。

>>> from ftplib import FTP
>>> with FTP("ftp1.at.proftpd.org") as ftp:
        ftp.login()
        ftp.dir()

'230 Anonymous login ok, restrictions apply.'
dr-xr-xr-x   9 ftp      ftp           154 May  6 10:43 .
dr-xr-xr-x   9 ftp      ftp           154 May  6 10:43 ..
dr-xr-xr-x   5 ftp      ftp          4096 May  6 10:43 CentOS
dr-xr-xr-x   3 ftp      ftp            18 Jul 10  2008 Fedora

其他類檔案物件,例如 mmap.mmapfileinput.input() 也獲得了自動關閉上下文管理器。

with fileinput.input(files=('log1.txt', 'log2.txt')) as f:
    for line in f:
        process(line)

(由 Tarek Ziadé 和 Giampaolo Rodolà 在 bpo-4972 中貢獻,以及 Georg Brandl 在 bpo-8046bpo-1286 中貢獻。)

FTP_TLS 類現在接受一個 _context_ 引數,它是一個 ssl.SSLContext 物件,允許將 SSL 配置選項、證書和私鑰捆綁到一個單一的(可能長期存在的)結構中。

(由 Giampaolo Rodolà 貢獻;bpo-8806。)

popen

os.popen()subprocess.Popen() 函式現在支援 with 語句,用於自動關閉檔案描述符。

(由 Antoine Pitrou 和 Brian Curtin 在 bpo-7461bpo-10554 中貢獻。)

select

select 模組現在公開了一個新的常量屬性 PIPE_BUF,它表示當 select.select() 指示管道可寫入時,保證不會阻塞的最小位元組數。

>>> import select
>>> select.PIPE_BUF
512

(在 Unix 系統上可用。補丁由 Sébastien Sablé 在 bpo-9862 中提交)

gzip 和 zipfile

gzip.GzipFile 現在實現了 io.BufferedIOBase 抽象基類(除了 truncate())。它還有一個 peek() 方法,並支援不可查詢和零填充的檔案物件。

gzip 模組還新增了 compress()decompress() 函式,用於更簡單的記憶體壓縮和解壓縮。請記住,文字在壓縮和解壓縮之前需要編碼為 bytes

>>> import gzip
>>> s = 'Three shall be the number thou shalt count, '
>>> s += 'and the number of the counting shall be three'
>>> b = s.encode()                        # convert to utf-8
>>> len(b)
89
>>> c = gzip.compress(b)
>>> len(c)
77
>>> gzip.decompress(c).decode()[:42]      # decompress and convert to text
'Three shall be the number thou shalt count'

(由 Anand B. Pillai 在 bpo-3488 中貢獻;以及 Antoine Pitrou、Nir Aides 和 Brian Curtin 在 bpo-9962bpo-1675951bpo-7471bpo-2846 中貢獻。)

此外,zipfile.ZipExtFile 類在內部進行了重新設計,以表示儲存在存檔中的檔案。新實現顯著提高了速度,並且可以包裝在 io.BufferedReader 物件中以獲得更高的速度。它還解決了一個問題,即交錯呼叫 _read_ 和 _readline_ 會產生錯誤的結果。

(補丁由 Nir Aides 在 bpo-7610 中提交。)

tarfile

TarFile 類現在可以用作上下文管理器。此外,它的 add() 方法有一個新選項 _filter_,它控制哪些檔案被新增到存檔中,並允許編輯檔案元資料。

新的 _filter_ 選項取代了舊的、靈活性較差的 _exclude_ 引數,後者現在已棄用。如果指定,可選的 _filter_ 引數需要是一個 關鍵字引數。使用者提供的過濾函式接受一個 TarInfo 物件並返回一個更新的 TarInfo 物件,或者如果它希望排除該檔案,則函式可以返回 None

>>> import tarfile, glob

>>> def myfilter(tarinfo):
...     if tarinfo.isfile():             # only save real files
...         tarinfo.uname = 'monty'      # redact the user name
...         return tarinfo

>>> with tarfile.open(name='myarchive.tar.gz', mode='w:gz') as tf:
...     for filename in glob.glob('*.txt'):
...         tf.add(filename, filter=myfilter)
...     tf.list()
-rw-r--r-- monty/501        902 2011-01-26 17:59:11 annotations.txt
-rw-r--r-- monty/501        123 2011-01-26 17:59:11 general_questions.txt
-rw-r--r-- monty/501       3514 2011-01-26 17:59:11 prion.txt
-rw-r--r-- monty/501        124 2011-01-26 17:59:11 py_todo.txt
-rw-r--r-- monty/501       1399 2011-01-26 17:59:11 semaphore_notes.txt

(由 Tarek Ziadé 提出,Lars Gustäbel 在 bpo-6856 中實現。)

hashlib

hashlib 模組有兩個新的常量屬性,列出了所有實現中保證存在的雜湊演算法以及當前實現中可用的雜湊演算法。

>>> import hashlib

>>> hashlib.algorithms_guaranteed
{'sha1', 'sha224', 'sha384', 'sha256', 'sha512', 'md5'}

>>> hashlib.algorithms_available
{'md2', 'SHA256', 'SHA512', 'dsaWithSHA', 'mdc2', 'SHA224', 'MD4', 'sha256',
'sha512', 'ripemd160', 'SHA1', 'MDC2', 'SHA', 'SHA384', 'MD2',
'ecdsa-with-SHA1','md4', 'md5', 'sha1', 'DSA-SHA', 'sha224',
'dsaEncryption', 'DSA', 'RIPEMD160', 'sha', 'MD5', 'sha384'}

(由 Carl Chenet 在 bpo-7418 中建議。)

ast

ast 模組提供了一個出色的通用工具,用於使用 Python 字面量語法安全地評估表示式字串。ast.literal_eval() 函式作為內建 eval() 函式的安全替代品,後者很容易被濫用。Python 3.2 將 bytesset 字面量新增到支援的型別列表:字串、位元組、數字、元組、列表、字典、集合、布林值和 None

>>> from ast import literal_eval

>>> request = "{'req': 3, 'func': 'pow', 'args': (2, 0.5)}"
>>> literal_eval(request)
{'args': (2, 0.5), 'req': 3, 'func': 'pow'}

>>> request = "os.system('do something harmful')"
>>> literal_eval(request)
Traceback (most recent call last):
  ...
ValueError: malformed node or string: <_ast.Call object at 0x101739a10>

(由 Benjamin Peterson 和 Georg Brandl 實現。)

os

不同的作業系統對檔名和環境變數使用不同的編碼。os 模組提供了兩個新函式 fsencode()fsdecode(),用於編碼和解碼檔名。

>>> import os
>>> filename = 'Sehenswürdigkeiten'
>>> os.fsencode(filename)
b'Sehensw\xc3\xbcrdigkeiten'

一些作業系統允許直接訪問環境中編碼的位元組。如果是這樣,os.supports_bytes_environ 常量將為真。

為了直接訪問編碼的環境變數(如果可用),請使用新的 os.getenvb() 函式,或者使用 os.environb,它是 os.environ 的位元組版本。

(由 Victor Stinner 貢獻。)

shutil

shutil.copytree() 函式有兩個新選項。

  • _ignore_dangling_symlinks_:當 symlinks=False 時,函式會複製符號連結指向的檔案,而不是符號連結本身。如果檔案不存在,此選項將抑制引發的錯誤。

  • _copy_function_:是一個可呼叫物件,將用於複製檔案。shutil.copy2() 預設使用。

(由 Tarek Ziadé 貢獻。)

此外,shutil 模組現在支援 zipfile、未壓縮 tarfile、gzipped tarfile 和 bzipped tarfile 的歸檔操作。並且有函式用於註冊額外的歸檔檔案格式(例如 xz 壓縮的 tarfile 或自定義格式)。

主要函式是 make_archive()unpack_archive()。預設情況下,兩者都在當前目錄(可以透過 os.chdir() 設定)和任何子目錄上操作。存檔檔名需要指定完整的路徑名。歸檔步驟是非破壞性的(原始檔案保持不變)。

>>> import shutil, pprint

>>> os.chdir('mydata')  # change to the source directory
>>> f = shutil.make_archive('/var/backup/mydata',
...                         'zip')      # archive the current directory
>>> f                                   # show the name of archive
'/var/backup/mydata.zip'
>>> os.chdir('tmp')                     # change to an unpacking
>>> shutil.unpack_archive('/var/backup/mydata.zip')  # recover the data

>>> pprint.pprint(shutil.get_archive_formats())  # display known formats
[('bztar', "bzip2'ed tar-file"),
 ('gztar', "gzip'ed tar-file"),
 ('tar', 'uncompressed tar file'),
 ('zip', 'ZIP file')]

>>> shutil.register_archive_format(     # register a new archive format
...     name='xz',
...     function=xz.compress,           # callable archiving function
...     extra_args=[('level', 8)],      # arguments to the function
...     description='xz compression'
... )

(由 Tarek Ziadé 貢獻。)

sqlite3

sqlite3 模組已更新到 pysqlite 版本 2.6.0。它有兩個新功能。

(由 R. David Murray 和 Shashwat Anand 貢獻;bpo-8845。)

html

引入了一個新的 html 模組,其中只有一個函式 escape(),用於轉義 HTML 標記中的保留字元。

>>> import html
>>> html.escape('x > 2 && x < 7')
'x &gt; 2 &amp;&amp; x &lt; 7'

socket

socket 模組有兩個新改進。

  • 套接字物件現在有一個 detach() 方法,它將套接字置於關閉狀態,而無需實際關閉底層檔案描述符。後者可以用於其他目的。(由 Antoine Pitrou 新增;bpo-8524。)

  • socket.create_connection() 現在支援上下文管理協議,以無條件地處理 socket.error 異常並在完成後關閉套接字。(由 Giampaolo Rodolà 貢獻;bpo-9794。)

ssl

ssl 模組添加了許多功能,以滿足安全(加密、認證)網際網路連線的常見要求。

  • 一個新類 SSLContext,用作持久 SSL 資料的容器,例如協議設定、證書、私鑰和各種其他選項。它包括一個 wrap_socket() 用於從 SSL 上下文建立 SSL 套接字。

  • 一個新函式 ssl.match_hostname() 透過實現 HTTPS 規則(來自 RFC 2818),支援更高級別協議的伺服器身份驗證,這些規則也適用於其他協議。

  • ssl.wrap_socket() 建構函式現在接受一個 _ciphers_ 引數。_ciphers_ 字串列出了允許的加密演算法,其格式在 OpenSSL 文件 中描述。

  • 當連結到最新版本的 OpenSSL 時,ssl 模組現在支援 TLS 協議的伺服器名稱指示擴充套件,允許在單個 IP 埠上使用不同證書的多個“虛擬主機”。此擴充套件僅在客戶端模式下受支援,並透過將 _server_hostname_ 引數傳遞給 ssl.SSLContext.wrap_socket() 來啟用。

  • ssl 模組中添加了各種選項,例如 OP_NO_SSLv2,它停用不安全且已過時的 SSLv2 協議。

  • 該擴充套件現在載入所有 OpenSSL 密碼和摘要演算法。如果某些 SSL 證書無法驗證,則報告為“未知演算法”錯誤。

  • 正在使用的 OpenSSL 版本現在可以透過模組屬性 ssl.OPENSSL_VERSION(字串)、ssl.OPENSSL_VERSION_INFO(5 元組)和 ssl.OPENSSL_VERSION_NUMBER(整數)訪問。

(由 Antoine Pitrou 在 bpo-8850bpo-1589bpo-8322bpo-5639bpo-4870bpo-8484bpo-8321 中貢獻。)

NNTP

nntplib 模組進行了改進的實現,具有更好的位元組和文字語義以及更實用的 API。這些改進打破了與 Python 3.1 中 nntplib 版本的相容性,該版本本身部分功能失調。

還增加了透過隱式(使用 nntplib.NNTP_SSL)和顯式(使用 nntplib.NNTP.starttls())TLS 支援安全連線。

(由 Antoine Pitrou 在 bpo-9360 中貢獻,以及 Andrew Vant 在 bpo-1926 中貢獻。)

證書

http.client.HTTPSConnectionurllib.request.HTTPSHandlerurllib.request.urlopen() 現在接受可選引數,以允許根據一組證書頒發機構檢查伺服器證書,這在公共 HTTPS 使用中是推薦的。

(由 Antoine Pitrou 新增,bpo-9003。)

imaplib

透過新的 imaplib.IMAP4.starttls 方法,在標準 IMAP4 連線上增加了對顯式 TLS 的支援。

(由 Lorenzo M. Catucci 和 Antoine Pitrou 貢獻,bpo-4471。)

http.client

http.client 模組中有許多小的 API 改進。不再支援舊式的 HTTP 0.9 簡單響應,並且所有類中的 _strict_ 引數都已棄用。

HTTPConnectionHTTPSConnection 類現在有一個 _source_address_ 引數,用於指示 HTTP 連線來自何處的(主機,埠)元組。

證書檢查和 HTTPS 虛擬主機支援已新增到 HTTPSConnection

連線物件上的 request() 方法允許可選的 _body_ 引數,以便可以使用 檔案物件 提供請求的內容。方便的是,_body_ 引數現在也接受一個 可迭代物件,只要它包含一個顯式的 Content-Length 標頭。這個擴充套件介面比以前靈活得多。

為了透過代理伺服器建立 HTTPS 連線,有一個新的 set_tunnel() 方法,用於設定 HTTP Connect 隧道的宿主和埠。

為了與 http.server 的行為匹配,HTTP 客戶端庫現在也使用 ISO-8859-1 (Latin-1) 編碼對標頭進行編碼。它已經對傳入標頭執行此操作,因此現在傳入和傳出流量的行為是一致的。(參見 Armin Ronacher 在 bpo-10980 中的工作。)

unittest

unittest 模組有許多改進,支援包的測試發現,在互動式提示符下更容易進行實驗,新的測試用例方法,改進的測試失敗診斷訊息,以及更好的方法名稱。

  • 命令列呼叫 python -m unittest 現在可以接受檔案路徑而不是模組名稱來執行特定的測試 (bpo-10620)。新的測試發現可以發現包內的測試,查詢從頂層目錄可匯入的任何測試。頂層目錄可以用 -t 選項指定,匹配檔案的模式用 -p,開始發現的目錄用 -s

    $ python -m unittest discover -s my_proj_dir -p _test.py
    

    (由 Michael Foord 貢獻。)

  • 現在在互動式提示符下進行實驗更容易了,因為 unittest.TestCase 類現在可以不帶引數例項化。

    >>> from unittest import TestCase
    >>> TestCase().assertEqual(pow(2, 3), 8)
    

    (由 Michael Foord 貢獻。)

  • unittest 模組有兩個新方法,assertWarns()assertWarnsRegex(),用於驗證測試程式碼是否觸發了給定的警告型別。

    with self.assertWarns(DeprecationWarning):
        legacy_function('XYZ')
    

    (由 Antoine Pitrou 貢獻,bpo-9754。)

    另一個新方法 assertCountEqual() 用於比較兩個可迭代物件,以確定它們的元素計數是否相等(無論順序如何,是否存在相同的元素,且出現次數相同)。

    def test_anagram(self):
        self.assertCountEqual('algorithm', 'logarithm')
    

    (由 Raymond Hettinger 貢獻。)

  • unittest 模組的一個主要特點是努力在測試失敗時生成有意義的診斷。如果可能,將記錄失敗以及輸出的差異。這對於分析失敗測試執行的日誌檔案特別有用。然而,由於差異有時會非常龐大,因此有一個新的 maxDiff 屬性,用於設定顯示差異的最大長度。

  • 此外,模組中的方法名稱經過了多次清理。

    例如,assertRegex()assertRegexpMatches() 的新名稱,後者命名不當,因為測試使用 re.search(),而不是 re.match()。其他使用正則表示式的方法現在使用短形式“Regex”而不是“Regexp”命名——這與在其他 unittest 實現中使用的名稱匹配,與 Python 對 re 模組的舊名稱匹配,並且具有明確的駝峰命名法。

    (由 Raymond Hettinger 貢獻,Ezio Melotti 實現。)

  • 為了提高一致性,一些長期存在的方法別名正在被棄用,轉而使用首選名稱。

    舊名稱

    首選名稱

    assert_()

    assertTrue()

    assertEquals()

    assertEqual()

    assertNotEquals()

    assertNotEqual()

    assertAlmostEquals()

    assertAlmostEqual()

    assertNotAlmostEquals()

    assertNotAlmostEqual()

    同樣,Python 3.1 中已棄用的 TestCase.fail* 方法預計將在 Python 3.3 中刪除。

    (由 Ezio Melotti 貢獻;bpo-9424。)

  • assertDictContainsSubset() 方法已棄用,因為它實現錯誤,引數順序不正確。這會造成難以除錯的視覺錯覺,例如 TestCase().assertDictContainsSubset({'a':1, 'b':2}, {'a':1}) 這樣的測試會失敗。

    (由 Raymond Hettinger 貢獻。)

random

random 模組中的整數方法現在能更好地生成均勻分佈。以前,它們透過 int(n*random()) 計算選擇,只要 _n_ 不是 2 的冪,就會存在輕微偏差。現在,從下一個 2 的冪的範圍中進行多次選擇,並且只有當選擇落在範圍 0 <= x < n 內時才保留。受影響的函式和方法是 randrange()randint()choice()shuffle()sample()

(由 Raymond Hettinger 貢獻;bpo-9025。)

poplib

POP3_SSL 類現在接受一個 _context_ 引數,它是一個 ssl.SSLContext 物件,允許將 SSL 配置選項、證書和私鑰捆綁到一個單一的(可能長期存在的)結構中。

(由 Giampaolo Rodolà 貢獻;bpo-8807。)

asyncore

asyncore.dispatcher 現在提供了一個 handle_accepted() 方法,該方法返回一個 (sock, addr) 對,當與新的遠端端點實際建立連線時會呼叫它。這應該用於替換舊的 handle_accept(),並避免使用者直接呼叫 accept()

(由 Giampaolo Rodolà 貢獻;bpo-6706。)

tempfile

tempfile 模組有一個新的上下文管理器 TemporaryDirectory,它提供了臨時目錄的簡單確定性清理。

with tempfile.TemporaryDirectory() as tmpdirname:
    print('created temporary dir:', tmpdirname)

(由 Neil Schemenauer 和 Nick Coghlan 貢獻;bpo-5178。)

inspect

  • inspect 模組有一個新函式 getgeneratorstate(),可以輕鬆識別生成器迭代器的當前狀態。

    >>> from inspect import getgeneratorstate
    >>> def gen():
    ...     yield 'demo'
    ...
    >>> g = gen()
    >>> getgeneratorstate(g)
    'GEN_CREATED'
    >>> next(g)
    'demo'
    >>> getgeneratorstate(g)
    'GEN_SUSPENDED'
    >>> next(g, None)
    >>> getgeneratorstate(g)
    'GEN_CLOSED'
    

    (由 Rodolpho Eckhardt 和 Nick Coghlan 貢獻,bpo-10220。)

  • 為了支援在不啟用動態屬性的情況下進行查詢,inspect 模組有一個新函式 getattr_static()。與 hasattr() 不同,這是一個真正的只讀搜尋,保證在搜尋時不會改變狀態。

    >>> class A:
    ...     @property
    ...     def f(self):
    ...         print('Running')
    ...         return 10
    ...
    >>> a = A()
    >>> getattr(a, 'f')
    Running
    10
    >>> inspect.getattr_static(a, 'f')
    <property object at 0x1022bd788>
    

(由 Michael Foord 貢獻。)

pydoc

pydoc 模組現在提供了改進的 Web 伺服器介面,以及一個新的命令列選項 -b,用於自動開啟瀏覽器視窗顯示該伺服器。

$ pydoc3.2 -b

(由 Ron Adam 貢獻;bpo-2001。)

dis

dis 模組新增了兩個用於檢查程式碼的函式 code_info()show_code()。兩者都為提供的函式、方法、原始碼字串或程式碼物件提供詳細的程式碼物件資訊。前者返回一個字串,後者列印它。

>>> import dis, random
>>> dis.show_code(random.choice)
Name:              choice
Filename:          /Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/random.py
Argument count:    2
Kw-only arguments: 0
Number of locals:  3
Stack size:        11
Flags:             OPTIMIZED, NEWLOCALS, NOFREE
Constants:
   0: 'Choose a random element from a non-empty sequence.'
   1: 'Cannot choose from an empty sequence'
Names:
   0: _randbelow
   1: len
   2: ValueError
   3: IndexError
Variable names:
   0: self
   1: seq
   2: i

此外,dis() 函式現在接受字串引數,因此常見的慣用法 dis(compile(s, '', 'eval')) 可以縮短為 dis(s)

>>> dis('3*x+1 if x%2==1 else x//2')
  1           0 LOAD_NAME                0 (x)
              3 LOAD_CONST               0 (2)
              6 BINARY_MODULO
              7 LOAD_CONST               1 (1)
             10 COMPARE_OP               2 (==)
             13 POP_JUMP_IF_FALSE       28
             16 LOAD_CONST               2 (3)
             19 LOAD_NAME                0 (x)
             22 BINARY_MULTIPLY
             23 LOAD_CONST               1 (1)
             26 BINARY_ADD
             27 RETURN_VALUE
        >>   28 LOAD_NAME                0 (x)
             31 LOAD_CONST               0 (2)
             34 BINARY_FLOOR_DIVIDE
             35 RETURN_VALUE

總而言之,這些改進使探索 CPython 的實現以及瞭解語言語法在底層如何工作變得更加容易。

(由 Nick Coghlan 在 bpo-9147 中貢獻。)

dbm

所有資料庫模組現在都支援 get()setdefault() 方法。

(由 Ray Allen 在 bpo-9523 中建議。)

ctypes

一個新型別 ctypes.c_ssize_t 表示 C ssize_t 資料型別。

site

site 模組有三個新函式,可用於報告給定 Python 安裝的詳細資訊。

>>> import site
>>> site.getsitepackages()
['/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/site-packages',
 '/Library/Frameworks/Python.framework/Versions/3.2/lib/site-python',
 '/Library/Python/3.2/site-packages']
>>> site.getuserbase()
'/Users/raymondhettinger/Library/Python/3.2'
>>> site.getusersitepackages()
'/Users/raymondhettinger/Library/Python/3.2/lib/python/site-packages'

方便的是,site 的某些功能可以直接從命令列訪問。

$ python -m site --user-base
/Users/raymondhettinger/.local
$ python -m site --user-site
/Users/raymondhettinger/.local/lib/python3.2/site-packages

(由 Tarek Ziadé 在 bpo-6693 中貢獻。)

sysconfig

新的 sysconfig 模組使得發現因平臺和安裝而異的安裝路徑和配置變數變得簡單明瞭。

該模組提供對平臺和版本資訊的簡單訪問函式。

它還提供對與 distutils 使用的七個命名方案之一對應的路徑和變數的訪問。其中包括 _posix_prefix_、_posix_home_、_posix_user_、_nt_、_nt_user_、_os2_、_os2_home_。

還有一個方便的命令列介面。

C:\Python32>python -m sysconfig
Platform: "win32"
Python version: "3.2"
Current installation scheme: "nt"

Paths:
        data = "C:\Python32"
        include = "C:\Python32\Include"
        platinclude = "C:\Python32\Include"
        platlib = "C:\Python32\Lib\site-packages"
        platstdlib = "C:\Python32\Lib"
        purelib = "C:\Python32\Lib\site-packages"
        scripts = "C:\Python32\Scripts"
        stdlib = "C:\Python32\Lib"

Variables:
        BINDIR = "C:\Python32"
        BINLIBDEST = "C:\Python32\Lib"
        EXE = ".exe"
        INCLUDEPY = "C:\Python32\Include"
        LIBDEST = "C:\Python32\Lib"
        SO = ".pyd"
        VERSION = "32"
        abiflags = ""
        base = "C:\Python32"
        exec_prefix = "C:\Python32"
        platbase = "C:\Python32"
        prefix = "C:\Python32"
        projectbase = "C:\Python32"
        py_version = "3.2"
        py_version_nodot = "32"
        py_version_short = "3.2"
        srcdir = "C:\Python32"
        userbase = "C:\Documents and Settings\Raymond\Application Data\Python"

(由 Tarek Ziadé 從 Distutils 中移出。)

pdb

pdb 偵錯程式模組獲得了許多可用性改進。

  • pdb.py 現在有一個 -c 選項,它執行 .pdbrc 指令碼檔案中給出的命令。

  • 一個 .pdbrc 指令碼檔案可以包含 continuenext 命令以繼續除錯。

  • Pdb 類建構函式現在接受一個 _nosigint_ 引數。

  • 新命令:l(list)ll(long list)source,用於列出原始碼。

  • 新命令:displayundisplay,用於顯示或隱藏表示式的值(如果已更改)。

  • 新命令:interact,用於啟動一個互動式直譯器,其中包含當前作用域中的全域性和區域性名稱。

  • 斷點可以透過斷點號清除。

(由 Georg Brandl、Antonio Cuni 和 Ilya Sandler 貢獻。)

configparser

configparser 模組經過修改,以提高預設解析器及其支援的 INI 語法的可用性和可預測性。舊的 ConfigParser 類已移除,取而代之的是 SafeConfigParser,後者又被重新命名為 ConfigParser。預設情況下,現在關閉對行內註釋的支援,並且在單個配置源中不允許重複的節或選項。

配置解析器獲得了基於對映協議的新 API。

>>> parser = ConfigParser()
>>> parser.read_string("""
... [DEFAULT]
... location = upper left
... visible = yes
... editable = no
... color = blue
...
... [main]
... title = Main Menu
... color = green
...
... [options]
... title = Options
... """)
>>> parser['main']['color']
'green'
>>> parser['main']['editable']
'no'
>>> section = parser['options']
>>> section['title']
'Options'
>>> section['title'] = 'Options (editable: %(editable)s)'
>>> section['title']
'Options (editable: no)'

新的 API 是在經典 API 之上實現的,因此自定義解析器子類應該能夠在不修改的情況下使用它。

現在可以自定義配置解析器接受的 INI 檔案結構。使用者可以指定替代的選項/值分隔符和註釋字首,更改 _DEFAULT_ 節的名稱或切換插值語法。

支援可插入的插值,包括一個額外的插值處理器 ExtendedInterpolation

>>> parser = ConfigParser(interpolation=ExtendedInterpolation())
>>> parser.read_dict({'buildout': {'directory': '/home/ambv/zope9'},
...                   'custom': {'prefix': '/usr/local'}})
>>> parser.read_string("""
... [buildout]
... parts =
...   zope9
...   instance
... find-links =
...   ${buildout:directory}/downloads/dist
...
... [zope9]
... recipe = plone.recipe.zope9install
... location = /opt/zope
...
... [instance]
... recipe = plone.recipe.zope9instance
... zope9-location = ${zope9:location}
... zope-conf = ${custom:prefix}/etc/zope.conf
... """)
>>> parser['buildout']['find-links']
'\n/home/ambv/zope9/downloads/dist'
>>> parser['instance']['zope-conf']
'/usr/local/etc/zope.conf'
>>> instance = parser['instance']
>>> instance['zope-conf']
'/usr/local/etc/zope.conf'
>>> instance['zope9-location']
'/opt/zope'

還引入了許多小功能,例如支援在讀取操作中指定編碼,為 get 函式指定回退值,或者直接從字典和字串讀取。

(所有更改均由 Łukasz Langa 貢獻。)

urllib.parse

urllib.parse 模組進行了多項可用性改進。

urlparse() 函式現在支援 IPv6 地址,如 RFC 2732 中所述。

>>> import urllib.parse
>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/')
ParseResult(scheme='http',
            netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]',
            path='/foo/',
            params='',
            query='',
            fragment='')

urldefrag() 函式現在返回一個 命名元組

>>> r = urllib.parse.urldefrag('https://python.club.tw/about/#target')
>>> r
DefragResult(url='https://python.club.tw/about/', fragment='target')
>>> r[0]
'https://python.club.tw/about/'
>>> r.fragment
'target'

而且,urlencode() 函式現在更加靈活,接受字串或位元組型別作為 _query_ 引數。如果是字串,則將 _safe_、_encoding_ 和 _error_ 引數傳送給 quote_plus() 進行編碼。

>>> urllib.parse.urlencode([
...      ('type', 'telenovela'),
...      ('name', '¿Dónde Está Elisa?')],
...      encoding='latin-1')
'type=telenovela&name=%BFD%F3nde+Est%E1+Elisa%3F'

解析 ASCII 編碼位元組 中詳述,所有 urllib.parse 函式現在都接受 ASCII 編碼的位元組字串作為輸入,只要它們不與常規字串混合。如果 ASCII 編碼的位元組字串作為引數給出,則返回型別也將是 ASCII 編碼的位元組字串。

>>> urllib.parse.urlparse(b'https://python.club.tw:80/about/')
ParseResultBytes(scheme=b'http', netloc=b'www.python.org:80',
                 path=b'/about/', params=b'', query=b'', fragment=b'')

(由 Nick Coghlan、Dan Mahn 和 Senthil Kumaran 在 bpo-2987bpo-5468bpo-9873 中完成。)

郵箱

感謝 R. David Murray 的共同努力,mailbox 模組已針對 Python 3.2 進行了修復。挑戰在於 mailbox 最初是為文字介面設計的,但電子郵件訊息最好用 bytes 表示,因為訊息的各個部分可能具有不同的編碼。

該解決方案利用了 email 包的二進位制支援來解析任意電子郵件訊息。此外,該解決方案需要對 API 進行一些更改。

正如預期,mailbox.Mailbox 物件的 add() 方法現在接受二進位制輸入。

StringIO 和文字檔案輸入已棄用。此外,如果使用非 ASCII 字元,字串輸入將提前失敗。以前它會在稍後處理電子郵件時失敗。

還支援二進位制輸出。get_file() 方法現在以二進位制模式返回檔案(以前它錯誤地將檔案設定為文字模式)。還有一個新的 get_bytes() 方法,它返回與給定 _key_ 對應的訊息的 bytes 表示。

仍然可以使用舊 API 的 get_string() 方法獲取非二進位制輸出,但這種方法不是很有用。相反,最好從 Message 物件中提取訊息或從二進位制輸入載入它們。

(由 R. David Murray 貢獻,Steffen Daode Nurpmeso 協助,Victor Stinner 在 bpo-9124 中提交了初始補丁。)

turtledemo

turtle 模組的演示程式碼已從 _Demo_ 目錄移至主庫。它包括十多個帶有生動顯示的示例指令碼。由於位於 sys.path 上,它現在可以直接從命令列執行。

$ python -m turtledemo

(由 Alexander Belopolsky 在 bpo-10199 中從 Demo 目錄移出。)

多執行緒

  • 用於序列化併發執行的 Python 執行緒執行的機制(通常稱為 GIL 或全域性直譯器鎖)已重寫。目標包括更可預測的切換間隔以及減少由於鎖競爭和隨之而來的系統呼叫數量而產生的開銷。“檢查間隔”以允許執行緒切換的概念已被放棄,並替換為以秒錶示的絕對持續時間。此引數可透過 sys.setswitchinterval() 進行調整。目前預設為 5 毫秒。

    有關實現的更多詳細資訊,請參閱 python-dev 郵件列表訊息(但是,此訊息中公開的“優先順序請求”未被納入)。

    (由 Antoine Pitrou 貢獻。)

  • 常規鎖和遞迴鎖現在接受其 acquire() 方法的可選 _timeout_ 引數。(由 Antoine Pitrou 貢獻;bpo-7316。)

  • 同樣,threading.Semaphore.acquire() 也獲得了 _timeout_ 引數。(由 Torsten Landschoff 貢獻;bpo-850728。)

  • 在使用 Pthreads 的平臺上,常規鎖和遞迴鎖的獲取現在可以被訊號中斷。這意味著在獲取鎖時死鎖的 Python 程式可以透過重複向程序傳送 SIGINT(在大多數 shell 中按 Ctrl+C)來成功終止。(由 Reid Kleckner 貢獻;bpo-8844。)

最佳化

添加了一些小的效能增強。

  • Python 的窺孔最佳化器現在識別模式,例如 x in {1, 2, 3},作為對常量集合中的成員資格測試。最佳化器將 set 重塑為 frozenset 並存儲預構建的常量。

    現在速度損失已經消失,使用集合符號編寫成員資格測試變得實用。這種風格既語義清晰,又操作快速。

    extension = name.rpartition('.')[2]
    if extension in {'xml', 'html', 'xhtml', 'css'}:
        handle(name)
    

    (補丁和附加測試由 Dave Malcolm 貢獻;bpo-6690)。

  • 使用 pickle 模組序列化和反序列化資料現在快了幾倍。

    (由 Alexandre Vassalotti、Antoine Pitrou 和 Unladen Swallow 團隊在 bpo-9410bpo-3873 中貢獻。)

  • list.sort()sorted() 中使用的 Timsort 演算法在呼叫時帶有 key function,現在執行更快,使用的記憶體更少。以前,列表的每個元素都被一個臨時物件包裝,該物件記住了與每個元素關聯的鍵值。現在,兩個鍵和值陣列並行排序。這節省了排序包裝器消耗的記憶體,並節省了委託比較所浪費的時間。

    (Daniel Stutzbach 在 bpo-9915 中提交的補丁。)

  • 當相同的字串重複用於多個鍵時,JSON 解碼效能得到提高,記憶體消耗減少。此外,當 sort_keys 引數為真時,JSON 編碼現在使用 C 加速。

    (由 Antoine Pitrou 在 bpo-7451 中貢獻,Raymond Hettinger 和 Antoine Pitrou 在 bpo-10314 中貢獻。)

  • 遞迴鎖(使用 threading.RLock() API 建立)現在受益於 C 實現,這使得它們與常規鎖一樣快,並且比以前的純 Python 實現快 10 到 15 倍。

    (由 Antoine Pitrou 貢獻;bpo-3001。)

  • stringlib 中的快速搜尋演算法現在被 split()rsplit()splitlines()replace() 方法用於 bytesbytearraystr 物件。同樣,該演算法也用於 rfind()rindex()rsplit()rpartition()

    (由 Florent Xicluna 在 bpo-7622bpo-7462 中提交的補丁。)

  • 整數到字串的轉換現在一次處理兩個“數字”,減少了除法和模運算的次數。

    (由 Gawain Bolton、Mark Dickinson 和 Victor Stinner 在 bpo-6713 中完成。)

還有其他一些小的最佳化。當一個運算元比另一個大得多時,集合差異運算現在執行得更快(Andress Bennetts 在 bpo-8685 中提交的補丁)。array.repeat() 方法有一個更快的實現(Alexander Belopolsky 的 bpo-1569291)。BaseHTTPRequestHandler 具有更高效的緩衝(Andrew Schaaf 的 bpo-3709)。operator.attrgetter() 函式已加速(Christos Georgiou 的 bpo-10160)。並且 ConfigParser 載入多行引數稍微快一些(Łukasz Langa 的 bpo-7113)。

Unicode

Python 已更新至 Unicode 6.0.0。此次標準更新增加了 2000 多個新字元,包括對手機至關重要的 表情符號

此外,更新後的標準更改了兩個卡納達語字元 (U+0CF1, U+0CF2) 和一個新傣仂數字字元 (U+19DA) 的字元屬性,使前者有資格用於識別符號,而後者則取消資格。有關更多資訊,請參閱 Unicode 字元資料庫更改

編解碼器

增加了對 _cp720_ 阿拉伯 DOS 編碼的支援 (bpo-1616979)。

MBCS 編碼不再忽略錯誤處理器引數。在預設嚴格模式下,當遇到不可解碼的位元組序列時,它會引發 UnicodeDecodeError,當遇到不可編碼的字元時,它會引發 UnicodeEncodeError

MBCS 編解碼器支援解碼的 'strict''ignore' 錯誤處理器,以及編碼的 'strict''replace'

要模擬 Python3.1 MBCS 編碼,請選擇解碼的 'ignore' 處理器和編碼的 'replace' 處理器。

在 Mac OS X 上,Python 使用 'utf-8' 而不是區域設定編碼來解碼命令列引數。

預設情況下,tarfile 在 Windows 上使用 'utf-8' 編碼(而不是 'mbcs'),並在所有作業系統上使用 'surrogateescape' 錯誤處理器。

文件

文件持續改進。

  • 在冗長的章節(如 內建函式)頂部添加了快速連結表。對於 itertools,連結旁邊還附有備忘錄風格的摘要表,以便在無需閱讀所有文件的情況下提供概述和記憶提示。

  • 在某些情況下,純 Python 原始碼可以作為文件的有用補充,因此現在許多模組都提供了指向最新版本原始碼的快速連結。例如,functools 模組文件頂部有一個名為“原始碼”的快速連結。

    原始碼 Lib/functools.py

    (由 Raymond Hettinger 貢獻;參見 理由。)

  • 文件現在包含更多示例和食譜。特別是,re 模組有一個廣泛的部分,正則表示式示例。同樣,itertools 模組也持續更新新的 Itertools 食譜

  • datetime 模組現在有一個純 Python 的輔助實現。功能沒有改變。這只是提供了一個更易於閱讀的替代實現。

    (由 Alexander Belopolsky 在 bpo-9528 中貢獻。)

  • 已移除未維護的 Demo 目錄。一些演示已整合到文件中,一些已移至 Tools/demo 目錄,還有一些則完全移除。

    (由 Georg Brandl 在 bpo-7962 中貢獻。)

IDLE

  • 格式選單現在有一個選項,可以透過去除尾隨空格來清理原始檔。

    (由 Raymond Hettinger 貢獻;bpo-5150。)

  • Mac OS X 上的 IDLE 現在支援 Carbon AquaTk 和 Cocoa AquaTk。

    (由 Kevin Walzer、Ned Deily 和 Ronald Oussoren 貢獻;bpo-6075。)

程式碼倉庫

除了現有的 Subversion 程式碼倉庫 https://svn.python.org 之外,現在還有一個 Mercurial 倉庫,地址是 https://hg.python.org/

3.2 版本釋出後,計劃將主要倉庫切換到 Mercurial。這個分散式版本控制系統應該能讓社群成員更容易建立和共享外部變更集。有關詳細資訊,請參閱 PEP 385

要學習使用新版本控制系統,請參閱快速入門Mercurial工作流指南

構建和 C API 更改

Python 的構建過程和 C API 的更改包括

  • 在執行make altinstall時,idlepydoc2to3指令碼現在會安裝一個帶有版本特定字尾的檔案(bpo-10679)。

  • 即使在窄字元unicode構建(Py_UNICODE_TOLOWER、Py_UNICODE_ISDECIMAL等)上,訪問Unicode資料庫的C函式現在也接受並返回完整Unicode範圍內的字元。Python中一個可見的區別是,unicodedata.numeric()現在返回大碼點的正確值,並且repr()可能會將更多字元視為可列印字元。

    (由Bupjoe Lee報告,Amaury Forgeot D’Arc修復;bpo-5127。)

  • 現在,在受支援的編譯器上(由配置指令碼檢測),預設啟用計算goto。透過指定--without-computed-gotos仍然可以選擇性地停用它們。

    (由Antoine Pitrou貢獻;bpo-9203。)

  • 選項--with-wctype-functions已刪除。所有函式現在都使用內建的unicode資料庫。

    (由Amaury Forgeot D’Arc貢獻;bpo-9210。)

  • 雜湊值現在是一個新型別Py_hash_t的值,它被定義為與指標大小相同。以前它們的型別是long,在某些64位作業系統上仍然只有32位長。由於此修復,在具有64位指標的構建中,setdict現在可以容納超過2**32個條目(以前,它們可以增長到該大小,但效能會災難性下降)。

    (由Raymond Hettinger建議,Benjamin Peterson實現;bpo-9778。)

  • 新的宏Py_VA_COPY複製可變引數列表的狀態。它等效於C99的va_copy,但可在所有Python平臺上使用(bpo-2443)。

  • 一個新的C API函式PySys_SetArgvEx()允許嵌入式直譯器設定sys.argv,而無需同時修改sys.pathbpo-5753)。

  • PyEval_CallObject()現在僅以宏形式提供。為了向後相容而保留的函式宣告現已刪除——該宏於1997年引入(bpo-8276)。

  • 新增函式PyLong_AsLongLongAndOverflow(),類似於PyLong_AsLongAndOverflow()。它們都用於將Python int轉換為原生定長型別,同時檢測轉換是否溢位(bpo-7767)。

  • PyUnicode_CompareWithASCIIString() 函式現在在Python字串以 NUL 終止時返回 不相等

  • 新增函式PyErr_NewExceptionWithDoc(),類似於PyErr_NewException(),但允許指定文件字串。這使得C異常具有與純Python對應項相同的自文件能力(bpo-7033)。

  • 使用--with-valgrind選項編譯時,pymalloc分配器在Valgrind下執行時將自動停用。這在Valgrind下執行時提供了改進的記憶體洩漏檢測,同時在其他時間利用了pymalloc(bpo-2422)。

  • PyArg_Parse函式中刪除了O?格式。該格式不再使用,也從未被文件化(bpo-8837)。

C-API還有一些其他小的更改。完整列表請參見Misc/NEWS檔案。

此外,Mac OS X 版本構建也進行了多次更新,詳情請參閱 Mac/BuildScript/README.txt。對於執行 32/64 位構建的使用者,Mac OS X 10.6 上的預設 Tcl/Tk 存在已知問題。因此,我們建議安裝更新的替代版本,例如 ActiveState Tcl/Tk 8.5.9。有關更多詳細資訊,請參閱 https://python.club.tw/download/mac/tcltk/

移植到Python 3.2

本節列出以前描述的更改以及可能需要更改您的程式碼的其他錯誤修復

  • configparser 模組進行了多項清理。主要更改是將舊的 ConfigParser 類替換為長期首選的替代方案 SafeConfigParser。此外,還有一些較小的相容性問題

    • 現在,在get()set()操作期間,插值語法會進行驗證。在預設插值方案中,只有兩個帶有百分號的標記有效:%(name)s%%,後者是轉義的百分號。

    • set()add_section()方法現在驗證值是否為實際字串。以前,可能會無意中引入不受支援的型別。

    • 來自單個源的重複節或選項現在會引發DuplicateSectionErrorDuplicateOptionError。以前,重複項會靜默覆蓋之前的條目。

    • 內聯註釋現在預設停用,因此 ; 字元現在可以安全地用於值中。

    • 註釋現在可以縮排。因此,對於多行值中行首的 ;#,必須進行插值。這可以防止值中的註釋字首字元被誤認為是註釋。

    • ""現在是一個有效值,不再自動轉換為一個空字串。對於空字串,請在一行中使用"option ="

  • nntplib 模組經過了大量重構,這意味著其 API 通常與 3.1 API 不相容。

  • bytearray 物件不能再用作檔名;相反,它們應該轉換為bytes

  • array.tostring()array.fromstring()為清晰起見已分別更名為array.tobytes()array.frombytes()。舊名稱已被棄用。(參見bpo-8990。)

  • PyArg_Parse*() 函式

    • “t#”格式已刪除:請改用“s#”或“s*”

    • “w”和“w#”格式已刪除:請改用“w*”

  • 在3.1中已棄用的PyCObject型別已刪除。要將不透明的C指標包裝到Python物件中,應改用PyCapsule API;新型別具有用於傳遞型別安全資訊的明確介面和更簡單的解構函式呼叫簽名。

  • sys.setfilesystemencoding()函式因其有缺陷的設計而被移除。

  • random.seed()函式和方法現在使用sha512雜湊函式對字串種子進行加鹽。要訪問以前版本的seed以重現Python 3.1序列,請將version引數設定為1,即random.seed(s, version=1)

  • 之前已棄用的string.maketrans()函式已移除,取而代之的是靜態方法bytes.maketrans()bytearray.maketrans()。此更改解決了圍繞string模組支援哪些型別產生的困惑。現在,strbytesbytearray各自擁有自己的maketranstranslate方法,並使用相應型別的中間翻譯表。

    (由Georg Brandl貢獻;bpo-5675。)

  • 之前已棄用的contextlib.nested()函式已移除,取而代之的是可以接受多個上下文管理器的普通with語句。後一種技術更快(因為它內建),並且在其中一個上下文管理器引發異常時能更好地完成多個上下文管理器的最終處理。

    with open('mylog.txt') as infile, open('a.out', 'w') as outfile:
        for line in infile:
            if '<critical>' in line:
                outfile.write(line)
    

    (由Georg Brandl和Mattias Brändström貢獻;appspot issue 53094。)

  • struct.pack()現在只允許使用位元組作為s字串打包程式碼。以前,它會接受文字引數並隱式地使用UTF-8將其編碼為位元組。這有問題,因為它對正確的編碼做了假設,並且可變長度編碼在寫入結構的固定長度段時可能會失敗。

    諸如struct.pack('<6sHHBBB', 'GIF87a', x, y)之類的程式碼應該重寫為使用位元組而不是文字,即struct.pack('<6sHHBBB', b'GIF87a', x, y)

    (由David Beazley發現,Victor Stinner修復;bpo-10783。)

  • xml.etree.ElementTree 類現在在解析失敗時引發 xml.etree.ElementTree.ParseError。以前它會引發 xml.parsers.expat.ExpatError

  • 浮點數上新的、更長的str()值可能會破壞依賴於舊輸出格式的doctest。

  • subprocess.Popen中,Unix下close_fds的預設值現在是True;Windows下,如果三個標準流都設定為None,則為True,否則為False。以前,close_fds預設始終為False,這會導致開啟的檔案描述符洩漏到子程序中,從而產生難以解決的錯誤或競爭條件。

  • 對傳統 HTTP 0.9 的支援已從 urllib.requesthttp.client 中移除。伺服器端仍存在此支援(在 http.server 中)。

    (由Antoine Pitrou貢獻,bpo-10711。)

  • 處於超時模式的SSL套接字現在在超時發生時引發socket.timeout,而不是通用的SSLError

    (由Antoine Pitrou貢獻,bpo-10272。)

  • 誤導性函式PyEval_AcquireLock()PyEval_ReleaseLock()已正式棄用。應改用執行緒狀態感知API(例如PyEval_SaveThread()PyEval_RestoreThread())。

  • 由於安全風險,asyncore.handle_accept()已被棄用,並添加了一個新函式asyncore.handle_accepted()來替換它。

    (由Giampaolo Rodola在bpo-6706中貢獻。)

  • 由於新的GIL實現,PyEval_InitThreads()不能再在Py_Initialize()之前呼叫。