最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python 存儲字符串時節(jié)省空間的方法

 更新時間:2019年04月23日 09:19:01   作者:小小后端  
這篇文章主要介紹了Python 存儲字符串時節(jié)省空間的方法,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下

從 Python 3 開始,str 類型代表著 Unicode 字符串。取決于編碼的類型,一個 Unicode 字符可能會占 4 個字節(jié),這個有些時候有點浪費內存。

出于內存占用以及性能方面的考慮,Python 內部采用下面 3 種方式來存儲 Unicode 字符:

  • 一個字符占一個字節(jié)(Latin-1 編碼)
  • 一個字符占二個字節(jié)(UCS-2 編碼)
  • 一個字符占四個字節(jié)(UCS-4 編碼)

使用 Python 進行開發(fā)的時候,我們會覺得字符串的處理都很類似,很多時候根本不需要注意這些差別。可是,當碰到大量的字符處理的時候,這些細節(jié)就要特別注意了。

我們可以做一些小實驗來體會下上面三種方式的差別。方法 sys.getsizeof 用來獲取一個對象所占用的字節(jié),這里我們會用到。

>>> import sys
>>> string = 'hello'
>>> sys.getsizeof(string)
54
>>> # 1-byte encoding
... sys.getsizeof(string + '!') - sys.getsizeof(string)
1
>>> # 2-byte encoding
... string2 = '你'
>>> sys.getsizeof(string2 + '好') - sys.getsizeof(string2)
2
>>> sys.getsizeof(string2)
76
>>> # 4-byte encoding
... string3 = ':snake:'
>>> sys.getsizeof(string3 + ':computer:') - sys.getsizeof(string3)
4
>>> sys.getsizeof(string3)
80

如上所示,當字符串的內容不同時,所采用的編碼也會不同。需要注意的是,Python 中每個字符串都會另外占用 49-80 字節(jié)的空間,用于存儲額外的一些信息,比如哈希、字符串長度、字符串字節(jié)數和字符串標識。這么一來,一個空字符串會占用 49 個字節(jié),也就好理解了。

我們可以通過 cbytes 直接獲取一個對象的編碼類型:

import ctypes
class PyUnicodeObject(ctypes.Structure):
 # internal fields of the string object
 _fields_ = [("ob_refcnt", ctypes.c_long),
    ("ob_type", ctypes.c_void_p),
    ("length", ctypes.c_ssize_t),
    ("hash", ctypes.c_ssize_t),
    ("interned", ctypes.c_uint, 2),
    ("kind", ctypes.c_uint, 3),
    ("compact", ctypes.c_uint, 1),
    ("ascii", ctypes.c_uint, 1),
    ("ready", ctypes.c_uint, 1),
    # ...
    # ...
    ]
def get_string_kind(string):
 return PyUnicodeObject.from_address(id(string)).kind

然后測試

>>> get_string_kind('Hello')
1
>>> get_string_kind('你好')
2
>>> get_string_kind(':snake:')
4

如果一個字符串中的所有字符都能用 ASCII 表示,那么 Python 會使用 Latin-1 編碼。簡單說下,Latin-1 用于表示前 256 個 Unicode 字符。它能支持很多拉丁語言,比如英語、瑞典語、意大利語等。不過,如果是漢語、日語、西伯爾語等非拉丁語言,Latin-1 編碼就行不通了。因為這些語言的文字的碼位值(編碼值)超過了 1 個字節(jié)的范圍(0-255)。

>>> ord('a')
97
>>> ord('你')
20320
>>> ord('!')
33

大部分語言文字使用 2 個字節(jié)(UCS-2)來編碼就已經足夠了。4 個字節(jié)(UCS-4)的編碼在保存特殊符號、emoji 表情或者少見的語言文字的時候會用到。

設想有一個 10GB 的 ASCII 文本文件,我們準備將其讀到內存里面去。如果你插入一個 emoji 表情到文件中,文件占用空間將會達到 4 倍。如果你處理 NLP 問題較多的話,這種差別你應該能經常體會到。

Python 內部為什么不直接使用 UTF-8 編碼

最常見的 Unicode 編碼是 UTF-8,但是 Python 內部并沒有使用它。

UTF-8 編碼字符的時候,取決于字符的內容,占的空間在 1-4 個字節(jié)內發(fā)生變化。這是一種特別省空間的存儲方式,但正因為這種變長的存儲方式,導致字符串不能通過下標直接進行隨機讀取,只能遍歷進行查找。比如,如果采用的是 UTF-8 編碼的話,Python 獲取 string[5] 只能一個一個字符的進行掃描,直至找到目標字符。如果是定長編碼的話也就沒有問題了,要用一個下標定位一個字符,只需要用下標乘以指定長度(1、2 或者 4)就能確定。

字符串駐留

Python 中的空字符串和 ASCII 字符都會使用到字符串駐留(string interning)技術。怎么理解?你就把這些字符(串)看作是單例的就行。也就是說,兩個相同內容的字符串如果使用了駐留的技術,那么內存里面其實就只開辟了一個空間。

>>> a = 'hello'
>>> b = 'world'
>>> a[4],b[1]
('o', 'o')
>>> id(a[4]), id(b[1]), a[4] is b[1]
(4567926352, 4567926352, True)
>>> id('')
4545673904
>>> id('')
4545673904

正如你看到的那樣,a 中的字符 o 和 b 中的字符 o 有著同樣的內存地址。Python 中的字符串是不可修改的,所以提前為某些字符分配好位置便于后面使用也是可行的。

使用到字符串駐留的除了 ASCII 字符、空竄之外,字符長度不超過 20 的串也使用到了同樣的技術,前提是這些串的內容在編譯的時候就能確定。

這包括:

  • 方法名、類型
  • 變量名
  • 參數名
  • 常量(代碼中定義的字符串)
  • 字典的鍵
  • 屬性名

當你在交互式命令行中編寫代碼的時候,語句同樣也會先被編譯成字節(jié)碼。所以說,交互式命令行中的短字符串也會被駐留。

>>> a = 'teststring'
>>> b = 'teststring'
>>> id(a), id(b), a is b
(4569487216, 4569487216, True)
>>> a = 'test'*5
>>> b = 'test'*5
>>> len(a), id(a), id(b), a is b
(20, 4569499232, 4569499232, True)
>>> a = 'test'*6
>>> b = 'test'*6
>>> len(a), id(a), id(b), a is b
(24, 4569479328, 4569479168, False)

因為必須是常量字符串會使用到駐留,所以下面的例子不能達到駐留的效果:

>>> open('test.txt','w').write('hello')
5
>>> open('test.txt','r').read()
'hello'
>>> a = open('test.txt','r').read()
>>> b = open('test.txt','r').read()
>>> id(a), id(b), a is b
(4384934576, 4384934688, False)
>>> len(a), id(a), id(b), a is b
(5, 4384934576, 4384934688, False)

字符串駐留技術,減少了大量的重復字符串的內存分配。Python 底層通過字典實現的這種技術,這些暫存的字符串作為字典的鍵。如果想要知道某個字符串是否已經駐留,使用字典的查找操作就能確定。

Python 的 unicode 對象的實現( https://github.com/python/cpython/blob/master/Objects/unicodeobject.c )大約有 16,000 行 C 代碼,其中有很多小優(yōu)化在本文中未提及。如果你想更多的了解 Python 中的 Unicode,推薦你去看一下字符串相關的 PEPs( https://www.python.org/dev/peps/ ),同時查看下 unicode 對象的源碼。

總結

以上所述是小編給大家介紹的Python 存儲字符串時節(jié)省空間的方法,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網站的支持!
如果你覺得本文對你有幫助,歡迎轉載,煩請注明出處,謝謝!

相關文章

  • python數組中的?k-diff?數對例題解析

    python數組中的?k-diff?數對例題解析

    這篇文章主要介紹了python數組中的?k-diff?數對例題解析,文章根據題目內容對其進行分析以此展開主題內容,感興趣的小伙伴可以參考一下下面文章詳情
    2022-06-06
  • pandas去除重復值的實戰(zhàn)

    pandas去除重復值的實戰(zhàn)

    本文主要介紹了pandas去除重復值的實戰(zhàn),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • Python批量重命名同一文件夾下文件的方法

    Python批量重命名同一文件夾下文件的方法

    這篇文章主要介紹了Python批量重命名同一文件夾下文件的方法,涉及Python使用os模塊操作文件的相關技巧,需要的朋友可以參考下
    2015-05-05
  • Django實現的自定義訪問日志模塊示例

    Django實現的自定義訪問日志模塊示例

    這篇文章主要介紹了Django實現的自定義訪問日志模塊,結合具體實例形式分析了Django針對日志的相關操作技巧,需要的朋友可以參考下
    2017-06-06
  • Python字典,函數,全局變量代碼解析

    Python字典,函數,全局變量代碼解析

    這篇文章主要介紹了Python字典,函數,全局變量代碼解析,具有一定借鑒價值,需要的朋友可以參考下。
    2017-12-12
  • Python繪制的愛心樹與表白代碼(完整代碼)

    Python繪制的愛心樹與表白代碼(完整代碼)

    這篇文章主要介紹了Python繪制的愛心樹與表白代碼,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-04-04
  • Python爬蟲基本庫request的基本使用

    Python爬蟲基本庫request的基本使用

    這篇文章主要介紹了Python爬蟲基本庫request的基本使用,urllib庫使用繁瑣,比如處理網頁驗證和Cookies時,需要編寫Opener和Handler來處理。為了更加方便的實現這些操作,就有了更為強大的requests庫,需要的朋友可以參考下
    2023-07-07
  • 使用k8s部署Django項目的方法步驟

    使用k8s部署Django項目的方法步驟

    這篇文章主要介紹了使用k8s部署Django項目的方法步驟,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-01-01
  • Python中yield關鍵字及與return的區(qū)別詳解

    Python中yield關鍵字及與return的區(qū)別詳解

    這篇文章主要介紹了Python中yield關鍵字及與return的區(qū)別詳解,帶有 yield 的函數在 Python 中被稱之為 generator生成器,比如列表所有數據都在內存中,如果有海量數據的話將會非常耗內存,想要得到龐大的數據,又想讓它占用空間少,那就用生成器,需要的朋友可以參考下
    2023-08-08
  • 詳解python中flask_caching庫的用法

    詳解python中flask_caching庫的用法

    這篇文章主要介紹了詳解python中flask_caching庫的用法,可以在一定的時間內直接返回結果而不是每次都需要計算或者從數據庫中查找。flask_caching插件就是提供這種功能的神器,需要的朋友可以參考下
    2023-05-05

最新評論

布拖县| 锦屏县| 剑河县| 龙山县| 德钦县| 外汇| 启东市| 柘城县| 桐梓县| 新兴县| 蛟河市| 吴桥县| 改则县| 周口市| 陈巴尔虎旗| 闸北区| 三河市| 长汀县| 合山市| 临猗县| 玛多县| 蚌埠市| 淅川县| 营山县| 府谷县| 昌黎县| 象山县| 保山市| 贵德县| SHOW| 舟曲县| 黎城县| 民勤县| 方正县| 高尔夫| 武冈市| 万源市| 莱西市| 华安县| 抚远县| 凤冈县|