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

Martin von Löwis 編寫的 PEP。

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 - 新的命令列解析模組

Steven Bethard 編寫的 PEP。

有關與 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 - 用於日誌記錄的基於字典的配置

Vinay Sajip 編寫的 PEP。

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 – 非同步執行計算

Brian Quinlan 編寫的 PEP。

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

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

PEP 3147:PYC 儲存庫目錄

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

隨著 Linux 發行版附帶多個版本的 Python 變得司空見慣,“pyc 衝突”的問題變得更加突出。這些衝突也會在使用諸如 Unladen Swallow 等 CPython 替代方案時出現。

為了解決這個問題,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 儲存庫目錄

由 Barry Warsaw 編寫的 PEP。

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 檔案

由 Barry Warsaw 編寫的 PEP。

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() 用於將 CGI 變數從 os.environ 轉碼為本地字串並返回一個新字典。

另請參閱

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

由 Phillip Eby 編寫的 PEP。

其他語言更改

對核心 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。它也適用於自定義的 dict 子類,這些子類在查詢之前對鍵進行規範化,或者為未知鍵提供 __missing__() 方法

    >>> 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 中實現。)

  • 直譯器現在可以使用 quiet 選項 -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。)

  • 結構序列型別 現在是元組的子類。這意味著像 os.stat()time.gmtime()sys.version_info 返回的 C 結構現在像一個 具名元組 一樣工作,並且現在可以與期望元組作為引數的函式和方法一起使用。這在使 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。雖然此類物件的 deallocator 確保它關閉底層作業系統資源(通常是檔案描述符),但延遲 deallocating 物件可能會產生各種問題,尤其是在 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 字元的使用者的 home 目錄帶來的煩人問題。

(需要在 bpo-9425 中由 Victor Stinner 進行大量工作。)

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

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

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

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

另一個重大的成功是增加了對 SSL 連線和安全證書的實質性更好支援。

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

電子郵件

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

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

  • 給定模型的位元組輸入,get_payload() 預設情況下會解碼 Content-Transfer-Encoding8bit 的訊息正文,使用 MIME 標頭中指定的字元集並返回結果字串。

  • 給定模型的位元組輸入,Generator 會將 Content-Transfer-Encoding8bit 的訊息正文轉換為 7bitContent-Transfer-Encoding

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

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

  • 現在,smtplib 模組的 SMTP 類接受位元組字串作為 sendmail() 方法的 *msg* 引數,並且新增了一個 send_message() 方法,該方法接受一個 Message 物件,並且可以選擇直接從該物件獲取 *from_addr* 和 *to_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)) 
    

    有關排序示例和簡短的排序教程,請參閱 排序指南教程。

    (由 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() 的示例,請參閱 隨機模組的示例

    (由 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)

在此示例中,屏障強制執行更健壯的規則。如果某些投票站未在午夜之前完成,則屏障會超時,選票將被密封並放入佇列中以便稍後處理。

有關如何在平行計算中使用屏障的更多示例,請參閱 屏障同步模式。此外,在 《訊號量小書》 的 *第 3.6 節* 中對屏障進行了簡單而透徹的解釋。

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

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,這意味著對於兩位數年份,世紀將根據控制 %y strptime 格式的 POSIX 規則進行猜測。

    從 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")

如果在發生日誌記錄事件之前沒有設定任何配置,則現在會有一個預設配置,該配置使用一個 StreamHandler,針對 WARNING 級別或更高級別的事件定向到 sys.stderr。以前,在設定配置之前發生的事件要麼引發異常,要麼根據 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 模組現在支援用於 zip 檔案、未壓縮的 tar 檔案、gzip 壓縮的 tar 檔案和 bzip2 壓縮的 tar 檔案的歸檔操作。還有用於註冊其他歸檔檔案格式(例如 xz 壓縮的 tar 檔案或自定義格式)的函式。

主要函式是 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 模組有兩個新的改進。

  • 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 證書無法驗證,它們將被報告為“未知演算法”錯誤。

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

(由 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 中的工作。)

mailbox

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

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

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

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 從 Demo 目錄移動,在 bpo-10199 中。)

多執行緒

  • 用於序列化併發執行的 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 中貢獻。)

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

    (由 Daniel Stutzbach 在 bpo-9915 中貢獻的補丁。)

  • JSON 解碼效能得到提高,並且當同一字串被多個鍵重複使用時,記憶體消耗會減少。此外,當 sort_keys 引數為 true 時,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 中貢獻的補丁。)

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

    bpo-6713 由 Gawain Bolton、Mark Dickinson 和 Victor Stinner 貢獻。)

還有一些其他的細微最佳化。現在,當一個運算元比另一個運算元大得多時,集合差分運算的執行速度更快(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 的更改包括

  • idlepydoc2to3 指令碼現在在 make altinstall 上安裝時帶有特定於版本的字尾 (bpo-10679)。

  • 訪問 Unicode 資料庫的 C 函式現在接受並返回完整 Unicode 範圍內的字元,即使在窄 Unicode 構建上也是如此(Py_UNICODE_TOLOWER、Py_UNICODE_ISDECIMAL 等)。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 位作業系統上,long 仍然只有 32 位長。由於此修復,setdict 現在可以在具有 64 位指標的構建上容納超過 2**32 個條目(以前,它們可以增長到該大小,但效能會急劇下降)。

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

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

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

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

  • 新增了一個函式 PyLong_AsLongLongAndOverflow(),它類似於 PyLong_AsLongAndOverflow()。它們都用於將 Python int 轉換為本機固定寬度型別,同時檢測轉換不適合的情況 (bpo-7767)。

  • 如果 Python 字串以 NUL 結尾,則 PyUnicode_CompareWithASCIIString() 函式現在返回 不相等

  • 新增了一個函式 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 模組進行了一些清理。主要的更改是用長期以來首選的替代方案 SafeConfigParser 替換舊的 ConfigParser 類。此外,還有一些較小的相容性問題

    • 現在,在 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 型別。要在 Python 物件中包裝不透明的 C 指標,應改用 PyCapsule API;新型別具有用於傳遞型別安全資訊的良好定義的介面,以及用於呼叫解構函式的更簡單的簽名。

  • 由於其設計存在缺陷,sys.setfilesystemencoding() 函式已被刪除。

  • 現在,random.seed() 函式和方法現在使用 sha512 雜湊函式對字串種子進行加鹽處理。要訪問先前版本的 seed 以重現 Python 3.1 序列,請將 version 引數設定為 1random.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,這會在開啟的檔案描述符洩漏到子程序中時產生難以解決的錯誤或競爭條件。

  • 已從 urllib.requesthttp.client 中移除了對舊版 HTTP 0.9 的支援。伺服器端(在 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() 之前呼叫。