Python 字典鍵 “三變一” 之謎

開頭:讀者的“玄學”字典謎題

上周,朋友發來了一段讓他抓耳撓腮的代碼:

>>> {True: 'foo', 1: 'bar', 1.0: 'baz'}  
{True: 'baz'}  

“我明明定義了布爾True、整數1、浮點數1.0三個鍵,結果字典里只剩True一個鍵,值還變成了最后一個'baz'!這是啥情況?”

這條消息讓我想起了當年自己初學 Python 時踩過的類似坑 —— 看似 “不同” 的鍵,在字典里卻被 “合并” 了。今天,咱們就用這個新例子當 “線索”,一起拆解 Python 字典的底層邏輯。

第一步:字典的“蓋樓”規則

要搞懂三個鍵為何只剩一個,得先明白字典是怎么“蓋樓”的。

簡單來說,字典的構建像搭樂高:先拼一個空架子(空字典),再按順序往架子上裝“鍵值對模塊”。上面的代碼等價于:

# 1. 拼空架子  
my_dict = {}  
# 2. 裝第一個模塊:鍵是True,值是'foo'  
my_dict[True] = 'foo'  
# 3. 裝第二個模塊:鍵是1,值是'bar'  
my_dict[1] = 'bar'  
# 4. 裝第三個模塊:鍵是1.0,值是'baz'  
my_dict[1.0] = 'baz'  

重點來了:字典的鍵是“喜新厭舊”的——如果后裝的鍵和已存在的鍵“本質相同”,就會覆蓋舊值。但問題是:True(布爾)、1(整數)、1.0(浮點數)明明是三種不同的類型,怎么就“本質相同”了?

第二步:True是“偽裝的1”

要破解“鍵相同”的謎題,得從Python的類型關系說起。

在Python的世界里,布爾(bool)是整數(int)的“親兒子”——官方文檔明確寫著:

“布爾類型是整數類型的子類型,True等價于整數1False等價于整數0。在大多數上下文中,布爾值的行為與對應的整數值一致。”

這意味著:

  • True == 1 → 是真的(True
  • 1 == 1.0 → 也是真的(浮點數1.0的數值等于整數1
  • 所以True == 1 == 1.0 → 全等于!

用代碼驗證:

>>> True == 1  
True  
>>> 1 == 1.0  
True  
>>> True == 1 == 1.0  
True  

原來,在字典的“視角”里,這三個鍵根本就是“同一個人”!所以當依次插入True: 'foo'1: 'bar'1.0: 'baz'時,后兩次插入都是在“修改同一個鍵的值”,最終只保留最后一次的'baz'

第三步:哈希值——字典的“身份證號”

但這里還有個疑問:就算三個鍵“數值相等”,字典怎么確定它們是“同一個鍵”?難道只看==嗎?

這就要說到字典的底層“黑科技”——哈希表(Hash Table)。字典能快速查找鍵值對,全靠哈希值:每個鍵會先通過__hash__方法生成一個哈希值(類似“身份證號”),字典根據這個號碼把鍵“扔”到對應的“抽屜”里;查找時,也先算哈希值,再去對應的抽屜里找。

關鍵規則是:只有當兩個鍵的哈希值相同,且==返回True時,字典才會認為它們是同一個鍵

驗證這三個鍵的哈希值:

>>> hash(True)  
1  
>>> hash(1)  
1  
>>> hash(1.0)  
1  

三個鍵的哈希值都是1==又全返回True,字典自然把它們當同一個鍵。所以后插入的1: 'bar'1.0: 'baz',本質上都是在修改True對應的值。

第四步:為什么鍵是True而不是11.0

最后一個疑問:三個鍵數值相等、哈希相同,為什么最終字典的鍵是True,而不是后插入的11.0

這涉及字典的“鍵保留規則”:當多個鍵被視為相同時,字典會保留第一個插入的鍵對象。比如:

>>> temp = {1.0: 'test'}  
>>> temp[True] = 'update'  
>>> temp  
{1.0: 'update'}  

這里先插入1.0,后插入True(與1.0相等),字典會保留第一個鍵1.0,并更新它的值。回到原問題,原字典第一個插入的鍵是True,所以最終鍵是True,值被后續插入的'bar''baz'覆蓋。

結論:三個“不同”鍵的終極真相

現在,我們可以徹底解開這個“變臉字典”的謎題了:

  1. 類型關系是根源:Python中boolint的子類,True等價于11又等價于1.0(數值相等)。
  2. 哈希值是身份證:三個鍵的哈希值都是1,字典通過“哈希值相同+==為True”判定它們是同一個鍵。
  3. 先到先得保鍵形:字典保留第一個插入的鍵對象(True),后續插入只更新值,不修改鍵。

所以,最終結果{True: 'baz'}的本質是:三個鍵被字典視為同一對象,后插入的值覆蓋了前值,而鍵保留了第一個插入的True

寫在最后:這行代碼教會我的事

這個看似“玄學”的字典表達式,其實藏著Python最核心的設計邏輯:

  • 布爾類型的“隱藏身份”(int子類)
  • 字典的哈希表底層邏輯(哈希值+相等性雙重校驗)
  • 鍵值對的插入順序對結果的影響

下次遇到類似“反直覺”的代碼時,別急著懷疑語言bug——打開Python解釋器,用==hash()驗證一下,你會發現Python的底層邏輯遠比想象中嚴謹。

畢竟,Python的“奇怪”,往往藏著最精妙的設計。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/82923.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/82923.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/82923.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

如何選擇 RabbitMQ、Redis 隊列等消息中間件?—— 深度解析與實戰評估

如何選擇 RabbitMQ、Redis 隊列等消息中間件?—— 深度解析與實戰評估 1. 引言 在現代分布式系統架構中,消息隊列(Message Queue,MQ) 作為解耦服務、異步處理和高效通信的關鍵組件,被廣泛應用于高并發、微服務和數據流處理場景。選擇合適的消息中間件不僅能提高系統的穩…

特征工程四:數據特征提取TfidfVectorizer的使用

TfidfVectorizer 深度解析 TfidfVectorizer 是 scikit-learn 中用于文本特征提取的核心工具,它將原始文本轉換為 TF-IDF 特征矩陣,是自然語言處理(NLP)和文本挖掘的基礎組件。 一、核心原理 1. TF-IDF 計算 TF (Term Frequency):詞頻&…

c/c++爬蟲總結

GitHub 開源 C/C 網頁爬蟲探究:協議、實現與測試 網頁爬蟲,作為一種自動化獲取網絡信息的強大工具,在搜索引擎、數據挖掘、市場分析等領域扮演著至關重要的角色。對于希望深入理解網絡工作原理和數據提取技術的 C/C 開發者,尤其是…

PostgreSQL 的表連接方法

PostgreSQL 的表連接方法 PostgreSQL 提供了多種高效的連接算法,每種方法適用于不同的查詢場景。以下是 PostgreSQL 支持的四種主要表連接方法及其特點: 1 Nested Loop Join(嵌套循環連接) 工作原理 對外表的每一行&#xff0…

【Qt】qss語法詳解

QSS (Qt Style Sheets) 語法格式詳解 QSS 是 Qt 的樣式表語言,類似于 CSS,用于自定義 Qt 應用程序的外觀。以下是 QSS 的完整語法格式說明: 基本語法結構 selector {property: value;property: value;... }1. 選擇器 (Selectors) 基本選擇…

Azure資源創建與部署指南

本文將指導您如何在Azure平臺上創建和配置必要的資源,以部署基于OpenAI的應用程序。 資源組創建 資源組是管理和組織Azure資源的邏輯容器。 在Azure門戶頂端的查詢框中輸入"Resource groups"(英文環境)或"資源組"(中文環境)在搜索結果中點擊"資…

Java后端快速生成驗證碼

Hutool是一個小而全的Java工具類庫,它提供了很多實用的工具類,包括但不限于日期處理、加密解密、文件操作、反射操作、HTTP客戶端等。 核心工具類:CaptchaUtil,CaptchaUtil 是 Hutool 提供的一個工具類,用于創建各種類…

sql 備份表a數據到表b

備份表a數據到表b mysql CREATE TABLE sys_dict_240702 LIKE sys_dict;INSERT INTO sys_dict_240702 SELECT * FROM sys_dict;mssql select * into t_Dict_240702 from t_Dict

2.4GHz無線通信芯片選型指南:集成SOC與低功耗方案解析

今天給大家分享幾款2.4GHz無線通信芯片方案: 一、集成SOC芯片方案 XL2407P(芯嶺技術) 集成射頻收發機和微控制器(如九齊NY8A054E) 支持一對多組網和自動重傳 發射功率8dBm,接收靈敏度-96.5dBm&#xff08…

Tomcat與純 Java Socket 實現遠程通信的區別

Servlet 容器??(如 Tomcat) 是一個管理 Servlet 生命周期的運行環境,主要功能包括: ??協議解析??:自動處理 HTTP 請求/響應的底層協議(如報文頭解析、狀態碼生成); ??線程…

[超級簡單]講解如何用PHP實現LINE Pay API!

在 PHP 中實現 LINE Pay API 之前我應該??做哪些準備?如何在 PHP 中實現 LINE Pay API? 目錄 [前提] 環境使用 PHP 實現 LINE Pay API 的準備工作使用 PHP 實現 LINE Pay API概括 [前提] 環境 這次我們將使用SandBox環境(測試環境&a…

centos7.x下,使用寶塔進行主從復制的原理和實踐

操作原理: 一、主庫配置 1.修改 MySQL 配置文件 # 編輯主庫配置文件(路徑根據實際系統可能不同) vim /etc/my.cnf # 添加以下配置 [mysqld] server-id 1 # 唯一 ID,主庫設置為 1 log-bin mysql-bin …

從零實現基于Transformer的英譯漢任務

1. model.py(用的是上一篇文章的代碼:從0搭建Transformer-CSDN博客) import torch import torch.nn as nn import mathclass PositionalEncoding(nn.Module):def __init__ (self, d_model, dropout, max_len5000):super(PositionalEncoding,…

c#建筑行業財務流水賬系統軟件可上傳記賬憑證財務管理系統簽核功能

# financial_建筑行業 建筑行業財務流水賬系統軟件可上傳記賬憑證財務管理系統簽核功能 # 開發背景 軟件是給岳陽客戶定制開發一款建筑行業流水賬財務軟件。提供工程簽證單、施工日志、人員出勤表等信息記錄。 # 財務管理系統功能描述 1.可以自行設置記賬科目,做憑…

MySQL 8.0 OCP 1Z0-908 題目解析(2)

題目005 Choose two. Which two actions can obtain information about deadlocks? □ A) Run the SHOW ENGINE INNODB MUTEX command from the mysql client. □ B) Enable the innodb_status_output_locks global parameter. □ C) Enable the innodb_print_all_deadlock…

XA協議和Tcc

基于 XA 協議的兩階段提交 (2PC)。這是一種分布式事務協議,旨在保證在多個參與者(通常是不同的數據庫或資源管理器)共同參與的事務中,所有參與者要么都提交事務,要么都回滾事務,從而維護數據的一致性。 你…

數據分析-圖2-圖像對象設置參數與子圖

from matplotlib import pyplot as mp mp.figure(A figure,facecolorgray) mp.plot([0,1],[1,2]) mp.figure(B figure,facecolorlightgray) mp.plot([1,2],[2,1]) #如果figure中標題已創建,則不會新建窗口, #而是將舊窗口設置為當前窗口 mp.figure(A fig…

跳轉語句:break、continue、goto -《Go語言實戰指南》

在控制流程中,我們有時需要跳出當前循環或跳過當前步驟,甚至直接跳轉到指定位置。Go 提供了三種基本跳轉語句: ? break:跳出當前 for、switch 或 select。? continue:跳過本輪循環,進入下一輪。? goto&a…

Linux中find命令用法核心要點提煉

大家好,歡迎來到程序視點!我是你們的老朋友.小二! 以下是針對Linux中find命令用法的核心要點提煉: 基礎語法結構 find [路徑] [選項] [操作]路徑:查找目錄(.表當前目錄,/表根目錄)…

MQTT協議詳解:物聯網通信的輕量級解決方案

MQTT協議詳解:物聯網通信的輕量級解決方案 引言 在物聯網(IoT)快速發展的今天,設備間高效可靠的通信變得至關重要。MQTT(Message Queuing Telemetry Transport)作為一種輕量級的發布/訂閱協議,已成為物聯網通信的首選解決方案。本文將深入探…