Following system colour scheme - Python 增強提案 Selected dark colour scheme - Python 增強提案 Selected light colour scheme - Python 增強提案

Python 增強提案

PEP 416 – 新增一個內建的 frozendict 型別

作者:
Victor Stinner <vstinner at python.org>
狀態:
已拒絕
型別:
標準跟蹤
建立日期:
2012年2月29日
Python 版本:
3.3

目錄

拒絕通知

我拒絕此 PEP。原因有(不詳盡)

  • 根據 Raymond Hettinger 的說法,frozendict 的使用率很低。那些使用它的人傾向於將其僅用作提示,例如宣告全域性或類級別的“常量”:它們並非真正不可變,因為任何人仍然可以為該名稱賦值。
  • 存在避免可變預設值的現有習慣用法。
  • 在 PyPy 中使用 frozendict 最佳化程式碼的潛力是不確定的;許多其他事情需要先改變。編譯時查詢一般也是如此。
  • 多個執行緒可以透過約定不同意修改共享的字典,沒有太大的強制需求。多個程序無法共享字典。
  • 許多人反對用 Python 編寫安全沙箱,即使範圍有限,因為永遠無法證明沙箱實際上是安全的。因此,我們近期不會將其新增到標準庫中,因此這種用例超出了 PEP 的範圍。

另一方面,將現有的只讀字典代理暴露為內建型別對我來說聽起來不錯。(它需要被修改為允許呼叫建構函式。)GvR。

更新(2012-04-15):Python 3.3 的 types 模組中添加了一個新的 MappingProxyType 型別。

摘要

新增一個新的內建 frozendict 型別。

基本原理

frozendict 是一個只讀對映:不能新增或刪除鍵,並且鍵始終對映到相同的值。但是,frozendict 的值可能不可雜湊。frozendict 僅當所有值都可雜湊時才可雜湊。

用例

  • 不可變全域性變數,如預設配置。
  • 函式引數的預設值。避免可變預設引數的問題。
  • 實現快取:frozendict 可用於儲存函式關鍵字。frozendict 可用作對映的鍵或集合的成員。
  • frozendict 避免了在 frozendict 被多個執行緒或程序共享時需要鎖,特別是可雜湊的 frozendict。它還有助於禁止協程(生成器 + greenlet)修改全域性狀態。
  • 由於對映是隻讀的,因此可以在編譯時而不是執行時進行 frozendict 查詢。frozendict 可用於代替預處理器來在編譯時刪除條件程式碼,例如特定於除錯構建的程式碼。
  • frozendict 有助於為安全模組實現只讀物件代理。例如,可以使用 frozendict 型別作為 `__builtins__` 對映或 `type.__dict__`。這是可能的,因為 frozendict 與 PyDict C API 相容。
  • frozendict 在某些情況下可以避免使用只讀代理。frozendict 比代理快,因為在 frozendict 中獲取項是一個快速查詢,而代理需要函式呼叫。

限制

  • frozendict 必須實現 Mapping 抽象基類
  • frozendict 的鍵和值可以是無序的
  • 僅當所有鍵和值都可雜湊時,frozendict 才可雜湊
  • frozendict 的雜湊不依賴於項的建立順序

實施

  • 新增一個基於 PyDictObject 的 PyFrozenDictObject 結構,並帶有一個額外的“Py_hash_t hash;”欄位
  • frozendict.__hash__() 使用 hash(frozenset(self.items())) 實現,並將結果快取到其私有的 hash 屬性中
  • 將 frozendict 註冊為 collections.abc.Mapping
  • frozendict 可與 PyDict_GetItem() 一起使用,但 PyDict_SetItem() 和 PyDict_DelItem() 會引發 TypeError

方案:可雜湊的字典

為了確保 frozendict 可雜湊,可以在建立 frozendict 之前檢查值

import itertools

def hashabledict(*args, **kw):
    # ensure that all values are hashable
    for key, value in itertools.chain(args, kw.items()):
        if isinstance(value, (int, str, bytes, float, frozenset, complex)):
            # avoid the compute the hash (which may be slow) for builtin
            # types known to be hashable for any value
            continue
        hash(value)
        # don't check the key: frozendict already checks the key
    return frozendict.__new__(cls, *args, **kw)

反對意見

namedtuple 可能符合 frozendict 的要求。

namedtuple 不是對映,它不實現 Mapping 抽象基類。

frozendict 可以使用描述符用 Python 實現”並且“frozendict 只需要在實踐中是常量。”

如果 frozendict 用於加固 Python(出於安全目的),則必須用 C 實現。用 C 實現的型別也更快。

PEP 351 被拒絕了。

PEP 351 嘗試凍結一個物件,因此可能會將可變物件轉換為不可變物件(使用不同的型別)。frozendict 不會轉換任何東西:如果值不可雜湊,hash(frozendict) 會引發 TypeError。凍結物件不是此 PEP 的目的。

替代方案:dictproxy

Python 有一個內建的 dictproxy 型別,由 type.__dict__ getter 描述符使用。此型別不是公開的。dictproxy 是字典的只讀檢視,但它不是隻讀對映。如果修改了字典,dictproxy 也會被修改。

可以使用 ctypes 和 Python C API 來使用 dictproxy,例如,請參閱 Ikkei Shimomura 的 透過 ctypes.pythonapi 和 type() 建立 dictproxy 物件(Python 菜譜 576540)。該菜譜包含一個測試,用於檢查 dictproxy 是否“可變”(修改連結到 dictproxy 的字典)。

然而,dictproxy 在某些情況下可能有用,當其可變屬性不是問題時,可以避免複製字典。

現有實現

白名單方法。

  • Aristotelis Mikropoulos 的 實現不可變字典(Python 菜譜 498072)。與 frozendict 類似,只是它不是真正只讀的:可以訪問其私有的內部字典。它不實現 `__hash__` 並且存在實現問題:可以再次呼叫 `__init__()` 來修改對映。
  • PyWebmail 包含一個 ImmutableDict 型別:webmail.utils.ImmutableDict。僅當鍵和值都可雜湊時,它才可雜湊。它不是真正只讀的:其內部字典是公共屬性。
  • remember 專案:remember.dicts.FrozenDict。它用於實現快取:FrozenDict 用於儲存函式回撥。FrozenDict 可能可雜湊。它有一個額外的 `supply_dict()` 類方法,用於從字典建立 FrozenDict 而無需複製字典:將字典儲存為內部字典。實現問題:可以呼叫 `__init__()` 來修改對映,並且雜湊可能因項的建立順序而異。對映不是真正只讀的:內部字典可以在 Python 中訪問。

黑名單方法:繼承自 dict 並重寫寫入方法以引發異常。它不是真正只讀的:仍然可以對這種“凍結字典”呼叫 dict 方法來修改它。

可雜湊字典:繼承自 dict 並僅新增 `__hash__` 方法。


來源:https://github.com/python/peps/blob/main/peps/pep-0416.rst

最後修改:2025-02-01 08:59:27 GMT