python進階(第三章2)字典和集合

文章目錄

    • 3.8 集合論
          • nee中的元素在haystack中出現的次數,可以在任何可迭代對象上
      • 3.8.1集合字面量
      • 3.8.2 集合推導
      • 3.8.3 集合操作
    • 3.9 dict和set的背后
      • 3.9.1 一個關于效率的實驗
      • 3.9.2 字典中的散列表
        • 1.散列值和相等性
        • 2.散列表算法
          • 獲取值:
          • 添加新的元素
          • 更新現有的鍵值
      • 3.9.3 dict的實現及其導致的結果
        • 1.鍵必須是可散列的
          • 所有用戶自定義的對象默認都是可散列的,因為它們的散列值由id()值獲取,而且都是不相等的。
        • 2.字典在內存上的開銷巨大
        • 3.鍵查詢很快
        • 4.鍵的次序取決于添加順序
        • 5.往字典里添加新鍵可能會改變已有鍵的順序
      • 3.9.4 set的實現以及導致的結果

3.8 集合論

集合的本質是許多唯一對象的聚集。一次,集合可以用于去重。
集合中的元素必須是可散列的,set類型本身是不可散列的,但是frozenset可以。因此可以創建一個包含不同frozenset的set.

  • 什么叫做可散列的呢?“python里所有不可變類型都是可散列的”。
    除了保證唯一性,集合還實現了很多基礎的中綴表達式
中綴運算符含義
a&b返回它們的交集
ab
a-b返回它們的差集
nee中的元素在haystack中出現的次數,可以在任何可迭代對象上
found = len(set(nee) & set(haystack))
或者
found = len(set(nee).intersection(haystack))

除了快速的查找功能(歸功于背后的散列表),內置的set和frozenset提供了額豐富的功能和操作。

3.8.1集合字面量

{1},{1,2,3}和數學形式一模一樣

3.8.2 集合推導

例子:

>>> from unicodedata import name
>>> {chr(i) for i in range(32,256) if 'SIGN' in name(chr(i),'')}
{'×', '?', '%', '÷', '°', '?', '+', '¤', '£', '?', '?', '¢', '<', '±', 'μ', '=', '$', '§', '#', '¥', '>'}

3.8.3 集合操作

比較普遍,可以參考之前的文章

3.9 dict和set的背后

重視一下的幾個問題:

  • python里的dict和set的效率有多高?
  • 為什么它們是無序的?
  • 為什么并不是所有的python對象都可以當做dict的鍵或者set里面的元素?
  • 為什么dict的鍵和set的順序是根據它們被添加的次序而定的,以及為什么在映射對象的生命周期中,這個順序呢并不是一成不變的?
  • 為什么不應該在迭代循環dict或是set的同時往里添加元素?

3.9.1 一個關于效率的實驗

最快的是集合,最糟糕的是列表。由于列表的背后沒有散列表來支持in運算符,每次搜索都需要掃描一次完整的列表,導致所需的時間線性增長。

3.9.2 字典中的散列表

散列表其實是一個稀疏數組(總是有空白元素的數據稱為稀疏數組)。一般認為,散列表中的單元通常叫作表元(bucket)。在dict的散列表當中,每個鍵值對都占用一個表元,每個表元都有兩部分,一個是對鍵的引用,另一個是對值的引用。因為所有表元的大小一致,所有可以通過偏移量來讀取某個表元。
因為python會設法保證大概還有三分之一的表元是空的,所以在快要達到這個閥值的時候,原有的散列值會被復制到一個更大的空間里面。
如果要把一個對象放入散列表,那么首先要計算這個元素鍵的散列值。python中可以用hash()方法來做這件事情。

1.散列值和相等性

內置的hash()方法可以用于所有的內置類型對象。如果是自定義對象調用hash()的話,實際上運行的是自定義的__hash__.如果兩個對象在比較的時候是相等的,那么它們的散列值必須相等,否則就不能正常運行了。

2.散列表算法

獲取值:

為了獲取my_dict[search_key]背后的值,python首先會調用hash(search_key)來計算search_key的散列值,把這個值最低的幾位數字當做偏移量,在散列表里查找表元(具體取幾位,得看當前散列值的大小)。若找到的表元是空的,則拋出KeyError異常。若不是空的,則表元里會有found_key:found_value。這時候python會檢驗search_key == found_key是否為真,如果它們相等的話,就會返回found_value.
如果search_key和found_key不匹配的話,就稱為散列沖突。發生這種情況是因為,散列表所做的其實是把隨機的元素映射到只有幾位的數字上,而散列表本身的索引又只依賴這個數字的一部分。為了解決散列沖入,算法會在散列值中另外取幾位,然后用特殊方法處理一下,把新得到的數字再當作索引來尋找表元。這次找到若表元若是空的,則同樣會拋出KeyError。若非空,或者鍵匹配,則返回這個值;或者又發現散列沖突,則重復以上步驟。如下圖:
在這里插入圖片描述

添加新的元素

在發現空表元的時候會放入一個新的元素

更新現有的鍵值

在找到相應的表元,原表中的值對象會被替換成新值
另外在插入新值時候,python可能會按照散列表的擁擠程度來決定是否要重新分配內存為它擴容。如果增加了散列表的大小,那散列值所占的位數和用作索引的位數都會隨之增加,這樣做是為了減少發生散列沖突的概率。

3.9.3 dict的實現及其導致的結果

1.鍵必須是可散列的

一個散列的對象必須包含下面要求:

  • (1)支持hash()函數,并且通過__hash__()所得到的散列值是不可變的
  • (2)支持通過__eq__()方法來檢測相等性
  • (3)若a == b 為真,則hash(a)== hash(b) 也為真
所有用戶自定義的對象默認都是可散列的,因為它們的散列值由id()值獲取,而且都是不相等的。

如果你實現了一個類的__eq__方法,并且希望它是可散列的,那么它一定要有個恰當的__hash__方法.

2.字典在內存上的開銷巨大

因為字典使用了散列表,而散列表又必須是稀疏的,這導致了它在空間上的效率底下。
在用戶自定義的類型中,__slot__屬性可以改變實例屬性的存儲方式,由dict變成tuple.
在類中定義__slots__屬性的目的是告訴解釋器:“這個類中所有實力屬性都在這兒了”

class Point():__slots__ = ("x", "y")def __init__(self, x, y):self.x = xself.y = ydef __str__(self):return "X={}-Y={}".format(self.x,self.y)

3.鍵查詢很快

dict是典型的空間換時間:字典類型有著巨大的內存開銷,但是它們提供了無視數據大小的快速訪問—只要字典被裝在內存里。

4.鍵的次序取決于添加順序

當往dict里添加新建而又發生散列沖突的時候,新鍵可能會被安排到另一個位置。

DIAL_CODES本身按照人口排序的,國家人口前10的國家

>>> DIAL_CODES=[
... (86,'China'),
...  (91,'India'),
...  (1,'United States'),
... (62,'Indonesia'),
... (55,'Brazil'),
... (92,'Pakistan'),
...  (880,'Bangladesh'),
...  (234,'Nigeria'),
...  (7,'Russia'),
...  (81,'Japan'),]
>>> d1= dict(DIAL_CODES)
>>> d1.keys()
dict_keys([86, 91, 1, 62, 55, 92, 880, 234, 7, 81])
>>> d2 = dict(sorted(DIAL_CODES))   # 按照國家的電話區號排序
>>> d2.keys()
dict_keys([1, 7, 55, 62, 81, 86, 91, 92, 234, 880])
>>> d3 = dict(sorted(DIAL_CODES, key=lambda x:x[1]))  按照國家英文名拼寫排序
>>> d3.keys()
dict_keys([880, 55, 86, 91, 62, 81, 234, 92, 7, 1])
>>> d1 == d2 and d2 == d3
True

5.往字典里添加新鍵可能會改變已有鍵的順序

無論何時往字典里添加新的鍵,python解釋器都可能做出為字典擴容的決定。擴容導致的結果就是新建一個更大的散列表,并把字典里已經有的元素添加到新表里。這個過程可能呢會發生新的散列沖突,導致新散列表中的鍵的次序變化。要注意的是,上面提到的這些變化是否會發生以及如何發生,都依賴于字典背后的具體實現。
由此可知,不要對字典同時進行迭代和修改。如果想要掃描并修改一個字典,最好分成兩步來進行:首先對字典迭代,以得出需要添加的內容,把這些內容放到一個新的字典里,迭代結束以后,再對原有字典進行更新。

3.9.4 set的實現以及導致的結果

set和frozenset的實現也依賴散列表,但在它們的散列表里存放的只有元素的引用(就像在字典中只有存放鍵而沒有響應的值)
特點總結:

  • 結合里的元素必須是散列的
  • 結合很消耗內存
  • 可以很高效的判斷元素是否存在與某個集合
  • 元素的次序取決于被添加到集合里的次序
  • 往集合里面添加元素,可能會改變集合里已有元素的次序。

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

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

相關文章

Android下實現GPS定位服務

1.申請Google API Key&#xff0c;參考前面文章 2.實現GPS的功能需要使用模擬器進行經緯度的模擬設置&#xff0c;請參考前一篇文章進行設置 3.創建一個Build Target為Google APIs的項目 4.修改Androidmanifest文件&#xff1a; view plain<uses-library android:name"…

python 鏈表 【測試題】

文章目錄注意&#xff1a;實例講解1 .鏈表基本功能2. 根據值刪除鏈表中的節點信息答案&#xff1a;3.反轉一個單鏈表信息答案4.合并兩個有序鏈表信息答案5.刪除排序鏈表中的重復元素信息答案6.移除鏈表元素信息7.環形鏈表信息進階思路答案注意&#xff1a; 這里的head是只存儲…

WebService應用一例,帶有安全驗證

1、創建WEB項目&#xff0c;添加WEB服務WebService1.asmx&#xff0c;代碼如下&#xff1a; 1 using System;2 using System.Collections.Generic;3 using System.Linq;4 using System.Web;5 using System.Web.Services;6 7 namespace WebService8 {9 /// <summary> …

linux集成開發環境

Linux操作系統的種種集成開發環境隨著Linux的逐漸興起&#xff0c;已經有為數眾多的程序在上面馳騁了&#xff0c;許多開發環境(Development Environment)也應運而生。好的開發環境一定是集成了編輯、編譯和調試等多項功能并且易于使用。本文介紹了一些在Linux上流行的開發環境…

mysql技術內幕《讀書筆記》

文章目錄1. mysql 體系結構和存儲引擎1.5 連接mysql1.5.11. mysql 體系結構和存儲引擎 1.5 連接mysql 連接mysql操作是一個連接進程和mysql數據庫實例進行通信。 本質是進程通信&#xff0c;常用的進程通信方式有管道&#xff0c;命名管道&#xff0c;命名字&#xff0c;TCP/…

DEDECMS全版本gotopage變量XSS ROOTKIT 0DAY

影響版本&#xff1a; DEDECMS全版本 漏洞描敘&#xff1a; DEDECMS后臺登陸模板中的gotopage變量未效驗傳入數據&#xff0c;導致XSS漏洞。 \dede\templets\login.htm 65行左右 <input type"hidden" name"gotopage" value"<?php if(!empty($g…

Android開源庫loopj的android-async-http的 JsonHttpResponseHandler 存在死循環GC_CONCURRENT

我現在用的是 AndroidAsyncHttp 1.4.4 版本&#xff0c;之前遇到一個很奇怪的問題&#xff0c; 當使用 JsonHttpResponseHandler 解析請求的頁面出現服務器錯誤或其他情況返回的內容不是 JSON 字符串時不會調用自己復寫實現的 onSuccess 或者 onFailure 方法&#xff0c;將會出…

python【進階】4.文本和字節序列

文章目錄1. 字符、碼位和字節表述4.1字符問題2. bytes、bytearray 和 memoryview 等二進制序列的獨特特性3. 全部 Unicode 和陳舊字符集的編解碼器4.避免和處理編碼錯誤5.處理文本文件的最佳實踐6.默認編碼的陷阱和標準 I/O 的問題7.規范化 Unicode 文本,進行安全的比較8.規范化…

C#序列化和反序列化

序列化和反序列化我們可能經常會聽到&#xff0c;其實通俗一點的解釋&#xff0c;序列化就是把一個對象保存到一個文件或數據庫字段中去&#xff0c;反序列化就是在適當的時候把這個文件再轉化成原來的對象使用。我想最主要的作用有&#xff1a; 1、在進程下次啟動時讀取上次保…

python【進階】5.一等函數(注銷)

在 Python 中,函數是一等對象。編程語言理論家把“一等對象”定義為滿足下述條件的程 序實體: 在運行時創建能賦值給變量或數據結構中的元素能作為參數傳給函數能作為函數的返回結果 在 Python 中,所有函數都是一等對象。 5.1 把函數視作對象 >>> def d(n): ... …

進程狀態轉換(了解)

進程三個基本狀態&#xff1a;就緒、阻塞、運行 這個比較簡單&#xff0c;進程創建后進入就緒狀態、然后若CPU空閑或能打斷CPU正在執行的進程&#xff08;優先級低的&#xff09;&#xff0c;那么就緒狀態轉換成運行態&#xff0c;運行時&#xff0c;進程需要用到其他資源&…

rebuild online意外終止導致ora-8104錯誤的實驗

rebuild online意外終止導致ora-8104錯誤的實驗 SQL> !oerr ora 810408104, 00000, "this index object %s is being online built or rebuilt"// *Cause: the index is being created or rebuild or waited for recovering // from the online (re)build // *Act…

關于range方法,如果你覺得python很簡單就錯了

前言&#xff1a;在系統學習迭代器之前&#xff0c;我一直以為 range() 方法也是用于生成迭代器的&#xff0c;現在卻突然發現&#xff0c;它生成的只是可迭代對象&#xff0c;而并不是迭代器&#xff01; 1、range() 是什么&#xff1f; 對于 range() 函數&#xff0c;有幾個注…

centos下crontab的使用

1.作用使用crontab命令可以修改crontab配置文件&#xff0c;然后該配置由cron公用程序在適當的時間執行&#xff0c;該命令使用權限是所有用戶。2.格式crontab [-u user] {-l | -r | -e}3.crontab命令選項: -u指定一個用戶, -l列出某個用戶的任務計劃, -r刪除某個用戶的任務, -…

關于python3中的包operator(支持函數式編程的包)

文章目錄1.functools2.operator.itemgetter3.operator.attrgetter雖然 Guido 明確表明,Python 的目標不是變成函數式編程語言,但是得益于 operator 和 functools 等包的支持,函數式編程風格也可以信手拈來。接下來的兩節分別介紹這兩 個包。 1.functools 示例1 使用 reduce 函…

collections 中的namedtuple

文章目錄namedtuple 基本用法namedtuple特性_make(iterable)_asdict()_replace(**kwargs)_fields_fields_defaults參考&#xff1a;namedtuple 基本用法 Tuple還有一個兄弟&#xff0c;叫namedtuple。雖然都是tuple&#xff0c;但是功能更為強大。對于namedtuple&#xff0c;你…

abap 中modify 的使用

1、modify table itab from wa Transporting f1 f2 ... 表示表itab中符合工作區wa 中關鍵字的一條數據的 f1 f2字段會被wa中對應的字段值更新。 modify用于更新和新增數據&#xff0c;當表中沒有數據時就新增&#xff0c;有就修改。 2、在使用binary search 時一定要先排序&am…

python[進階] 6.使用一等函數實現設計模式

文章目錄6.1.1 經典的“策略”模式6.1.2 使用函數實現“策略”模式6.1.3 選擇最佳策略&#xff1a;簡單的6.1.4 找出模塊中的全部6.2 “命令”模式6.1.1 經典的“策略”模式 為抽象基類&#xff08;Abstract Base Class&#xff0c;ABC&#xff09;&#xff0c;這么做是為了使…

2014阿里巴巴校園招聘筆試題 - 中南站

轉載于:https://www.cnblogs.com/gotodsp/articles/3530329.html

python中一些特殊方法的作用

我們先暫且稱呼為特殊方法。 單下劃線開頭&#xff08;_foo&#xff09;雙下劃線開頭的&#xff08;__foo&#xff09;雙下劃線開頭和結尾的&#xff08; __foo__&#xff09;代表不能直接訪問的類屬性&#xff0c;需通過類提供的接口進行訪問&#xff0c;不能用“from xxx im…