小數據池 is和== 再談編碼

昨日回顧

上節課內容回顧
    1. 字典
        {key:value, key:value.....}
        成對的保存數據

        字典沒有索引. 不能切片, 字典的key必須是可哈希的.不可變的
        1. 增長:
            dic[新key] = 值
            dic.setdefault(key, value) 新增, 查詢
        2. 修改:
            dic[老key] = 值
            dic.update(d) 把d更新到dic中
        3. 刪除;
            pop(key)
            popitem() 隨機刪除
            del dic[key]
            clear() 清空
        4. 查詢
            for k in dic:
                k
                dic[k]

            get(key) 若是key不存在, 返回None
            dic[key] 若是key不存在, 報錯

            setdefault(key, value)
            根據key查詢出value
        5. 相關操做
            1. keys()     全部的key
            2. values()     全部的value
            3. items()      全部的key和value
            for k, v in dic.items(): # 自動解包
                k
                v
    set集合
        內部元素必須可哈希. 不可變
        內部元素不重複

        add() 添加

        frozenset() 凍結集合. 不可變的.(##通常的集合自己是可變的,可是要求其內部的元素是不可變的,而這個集合自己就是不可變的)

今日內容

今日主要內容
        1. 小數據池, id()
            小數據池針對的是: int, str, bool
            在py文件中幾乎全部的字符串都會緩存.
            id() 查看變量的內存地址
        2. is和==的區別
            is 比較的是內存地址
            == 比較的是內容
            當兩個變量指向同一個對象的時候. is是True, ==也是True

        3. 再談編碼
            回顧:
                1. ascii. 有: 數字, 字母, 特殊字符. 8bit  1byte 128  最前面是0
                2. gbk. 包含: ascii, 中文(主要), 日文, 韓文, 繁體文字. 16bit, 2byte.
                3. unicode. 包含gbk,ascii,big5... 32bit, 4byte
                4. utf-8. 可變長度的unicode.
                    1. 英文: 8bit,1byte
                    2. 歐洲文字: 16bit 2byte
                    3. 中文: 24bit 3byte
            不一樣的編碼之間不能隨意轉換. 中國人gbk和德國人utf-8罵 想要溝通必須經過英文(unicode)(媒介)

            在python3中. 默認的編碼是unicode,咱們的字符串就是unicode
            在python2中. 默認的編碼是ASCII.  Cpython是用 c 語言寫的,c語言的默認編碼是ASCII

            unicode弊端:在存儲和傳輸的時候. 是很浪費的
            在存儲和傳輸的時候不能直接使用unicode. 必需要對字符串進行編碼. 編碼成bytes類型
            bytes: 字節形式的字符串

                1. encode(編碼格式) 編碼
                2. decode(編碼格式) 解碼

            bytes是一種另類的字符串表示形式
            "哈哈哈" => \xee\xab\x13\xee\xab\x13\xee\xab\x13

一.小數據池

在說小數據池以前.咱們先看一個概念.什麼是代碼塊:html

根據提示咱們從官方文檔找到了這樣的說法:
A Python program is constructed from code blocks. A block is a piece of
Python program text that is executed as a unit. The following are blocks: a
module,a function body, and a class definition. Each command typed
interactively is a block. A script file (a file given as standard input to
the interpreter or specified as a command line argument to the interpreter)
is a code block. A script command (a command specified on the interpreter
command line with the‘-C‘ option) is a code bLock. The string argument
passed to the built-in functions evalO and execO) is a code block.
A code block is executed in an execution frame. A frame contains some
admi ni strative information (used for debugging) and determines where and
how execution continues after the code bLock's execution has compLeted.
粗略的翻譯:
python程序是由代碼塊構成的.一個代碼塊的文本做爲python程序執行的單元.
代碼塊:一個模塊,一個函數,一個類,甚至每個command命令都是一個代碼塊.一個文件也是一個代碼塊,evalO)和exec( )執行的時候也是一個代碼塊

什麼是命令行?
咱們在控制檯CMD中輸入python進入的就是python的command模式.在這裏也能夠寫
python的程序.
而根據上面的官方的解釋來看.一個command命令就是一個python代碼塊python

 

二.小數據池 is和==的區別

接下來咱們來看一下小數據池is和==的區別編程

# id()函數能夠幫咱們查看一個變量的內存地址
a = 10
b = 30
print(id(a))  # 1515545088
print(id(b))  # 1515545728


lst = ['周杰倫', "麻花藤"]
print(id(lst))  # 166167624
print(lst)
lst = []  # 建立了一個新列表
lst.append("胡辣湯")
print(id(lst))  # 166167624
print(lst)

lst1 = [1,2,3] # 兩個對象 內存地址是不同的
lst2 = [1,2,3]
print(id(lst1)) # 166167624
print(id(lst2)) # 166122376

s1 = "abc" # 內存中是沒有"abc", 建立一個新的  0.0001
s2 = "abc" # 內存中是已經有了"abc", 直接把abc拿來用   0.0000001
print(id(s1), id(s2)) # 31096032 31096032

# 使用頻率最高的數據類型: 字符串,爲了可以快速的建立字符串.
# 節省內存. 把相同的規律的字符串進行緩存,當下次建立的時候就不在建立了
# 把字符串的緩存-> 小數據池 -> String iterning -> 常量池 -> 字符串緩存

# 在建立字符串以前. 先去小數據池對比. 是否已經存在了該字符串.若是存在了.
# 就不建立新的了. 直接拿原來存在的數據, 省略掉反覆重複建立字符串的過程. 節約內存


# 什麼數據會被緩存
# 數字, 字符串, 布爾值 =>  都是不可變的數據類型
# 1. 數字
a = 1000
b = 1000
print(id(a), id(b))  # 165830000 165830000

# 2. 字符串. 若是單純的寫字符串. 幾乎都會被緩存
s1 = "a昨天上廁所沒關門. 紅衝進去了. 麪筋歌出來了. 有故事a昨天上廁所沒關門. 紅衝進去了. 麪筋歌出來了. 有故事a昨天上廁所沒關門. 紅衝進去了. 麪筋歌出來了. 有故事"
s2 = "a昨天上廁所沒關門. 紅衝進去了. 麪筋歌出來了. 有故事a昨天上廁所沒關門. 紅衝進去了. 麪筋歌出來了. 有故事a昨天上廁所沒關門. 紅衝進去了. 麪筋歌出來了. 有故事"

print(id(s1), id(s2)) # 31222064 31222064

# 若是在py文件中寫的字符串. 幾乎都是緩存的
# 在黑窗口裏的寫的幾乎都不會緩存
# 不一樣的解釋器. 緩存的機制也不同
#
# 優勢: 能夠幫咱們快速的建立對象.節省內存.
# 缺點: 緩存若是過大. 響應速度會比較慢
# 不要糾結.

# == 和 is 區別:
#
# == 比較的是數據, 外貌
# is 比較的是內存地址, 比較身份證號

lst1 = [1,2,3]
lst2 = [1,2,3]
# 列表沒有小數據池
print(id(lst1), id(lst2)) #  166167560 166126408
print(lst1 == lst2) # True
print(lst1 is lst2) # False

s1 = "我叫周潤發"
s2 = "我叫周潤發"
print(s1 == s2)
print(s1 is s2) # 小數據池

tu1 = ("週一", "週二")
tu2 = ("週一", "週二")
print(tu1 is tu2) # 地址不相等 False
print(tu1 == tu2) # 內容相等 True

# == 比較的是內容
# is 比較內存地址
View Code

 

id()

經過id()咱們能夠查看到一個變量表示的值在內存中的地址.緩存

s = 'alex'
print(id(s))  # 4326667072

is和==

==判斷左右兩端的值是否相等.是否是一致.
is判斷左右兩端內容的內存地址是否一致. 若是返回True,那能夠肯定這兩個變量使用的是同一個對象
網絡

咱們能夠這樣認爲. 若是內存地址相同,那麼值必定是相等的. 若是值相等, 則不必定是同一 個對象.app


小數據池,一種數據緩存機制,也被稱爲駐留機制.各大編程語言中都有相似的末西.在網上搜索常量池,小數據池指的都是同一個內容.

小數據池只針対:整數,字符串,布尓値.其餘的數據類型不存在駐留機制編程語言

#對於整數,Python官方文檔中這麼說:
The current implementation keeps an array of integer objects for all integers between -5 and 256, 
when you create an int in that range you actually just get back a reference to the existing object.
So it should be possible to change the value of 1. I suspect the behaviour of Python in this case is undefined. #對於字符串: Incomputer science, string interning is a method of storing only onecopy of each distinct string value,
which must be immutable. Interning strings makes some stringprocessing tasks more time- or space-efficient
at the cost of requiring moretime when the string is created or interned. The distinct values are stored ina string intern pool. –引⾃維基百科

在python中對-5到256之間的整數會被駐留在內存中,將必定規則的字符串緩存.在使用的時候,內存中只會建立一個該數據的對象,保存在小數據池中.當使用的時候直接從小數據池中獲取對象的內存引用,而不須要建立一個新的數據,這樣會節省更多的內存區域.

優勢:可以提升一些字符串,整數的處理速度.省略掉建立對象的過程.
缺點:在'池'中建立或者插入新的內容會花費更多的時間.ide

 

#對於數字: 
-5~256是會被加到小數據池中的,每次使用都是同一個對象.

#對於字符串: 
1.若是字符串的長度是0或者1,都會默認進行緩存 (也要是在同一個代碼塊中)
2.字符串長度大於1,可是字符串中只包含字母,數字,下劃線時纔會緩存
3.用乘法獲得的字符串
①.乘數爲1,僅包含數字,字母,下劃線時會被緩存.若是包含其餘字符,而長度<=1也會被駐存.
②.乘數大於1,僅包含數字,字母,下劃線這個時候會被緩存.但字符串長度不能大於20
4.指定駐留.咱們能夠經過sys模塊中的intern()函數來指定要駐留的內容.

 

OK.到目前爲止.咱們已經瞭解了python的小數據池的一些基本狀況了.可是!!還有最後一個問題.小數據池和最開始的代碼塊有什麼關係呢?

一樣的一段代碼在命令行窗口和在py文件中.出現的效果是徹底不同的.函數

a = 1000
b = 1000
print(a is b)
注意. 在py文件中,獲得的結果是True, 可是在command(命令行)中就是False了.

在代碼塊內的緩存機制是不同的.在執行同一個代碼塊的初始化對象的命令時,會檢查是否其值是否已經存在,若是存在,會將其重用.換句話說:執行同一個代碼塊時,遇到初始化對象的命令時,他會將初始化的這個變量與值存儲在一個字典中,在遇到新的變量時,會先在字典中查詢記錄,若是有一樣的記錄那麼它會重複使用這個字典中的以前的這個值.因此在你給出的例子中,文件執行時(同一個代碼塊)會把a, b兩個變量指向同一個對象.若是是不一樣的代碼塊,他就會看這個兩個變量是不是知足小數據池的數據,若是是知足小數據池的數據則會指向同一個地址.因此: a, b的賦值語句分別被看成兩個代碼塊執行,可是他們不知足小數據池的數據因此會獲得兩個不一樣的對象,於是is判斷返回False.ui

三.編碼補充

s = "我今天很是的困" # 21個utf-8
bs = s.encode("gbk") # 把字符串轉化成utf-8格式bytes
# bytes不是給人看的. 給機器用的
# 14個字節   gbk
# b'\xce\xd2\xbd\xf1\xcc\xec\xb7\xc7\xb3\xa3\xb5\xc4\xc0\xa7'
# 21個字節   utf-8
# b'\xe6\x88\x91\xe4\xbb\x8a\xe5\xa4\xa9\xe9\x9d\x9e\xe5\xb8\xb8\xe7\x9a\x84\xe5\x9b\xb0'
print(bs)

# utf-8和gbk是不能直接轉換的, 必須使用unicode來轉換
bs = b'\xe6\x88\x91\xe4\xbb\x8a\xe5\xa4\xa9\xe9\x9d\x9e\xe5\xb8\xb8\xe7\x9a\x84\xe5\x9b\xb0'
# 把字節轉化回字符串
s = bs.decode("utf-8")
print(s)



b'\xe6\x88\x91\xe4\xbb\x8a\xe5\xa4\xa9\xe9\x9d\x9e\xe5\xb8\xb8\xe7\x9a\x84\xe5\x9b\xb0'
# 把這個bytes轉化成gbk的bytes
bs = b'\xe6\x88\x91\xe4\xbb\x8a\xe5\xa4\xa9\xe9\x9d\x9e\xe5\xb8\xb8\xe7\x9a\x84\xe5\x9b\xb0'
# 解碼
s = bs.decode("utf-8")
print(s)

# 編碼
bss = s.encode("gbk")
print(bss)


# 關於bytes, 非ascii中的內容. 展現的時候都是\x.. 若是是ascii中的內容. 原樣輸出
name = "alex昨天吃多了"
bs = name.encode("gbk") # b'alex\xd7\xf2\xcc\xec\xb3\xd4\xb6\xe0\xc1\xcb'
print(bs)

bss = name.encode("utf-8") # b'alex\xe6\x98\xa8\xe5\xa4\xa9\xe5\x90\x83\xe5\xa4\x9a\xe4\xba\x86'
print(bss)
View Code

 

1. python2中默認使用的是ASCII碼,因此不支持中文.若是須要在Python2中更改編碼須要在文件的開始編寫:

# -*- encoding:utf-8 -*-

 

2. python3中: 內存中使用的是unicode碼.

#編碼回顧:
1. ASCII: 最先的編碼.裏面有英文大寫字母,小寫字母,數字,一些特殊字符. 沒有中文,8個01代碼, 8個bit, 1個byte
2. GBK:中文國標碼,裏面包含了ASCII編碼和中文經常使用編碼.16個bit, 2個byte
3. UNICODE: 萬國碼,裏面包含了全世界全部國家文字的編碼.32個bit, 4個byte,包含了ASCII
4. UTF-8:可變長度的萬國碼.是unicode的一種實現.最小字符佔8位
    1.英文:      8bit    1byte
    2.歐洲文字:16bit   2byte
    3.中文:      24bit   3byte
綜上,除了ASCII碼之外,其餘信息不能直接轉換.要經過Unicode轉換

在python3的內存中,在程序運行階段使用的是unicode編碼.由於unicode是萬國碼,什麼內容均可以進行顯示.那麼在數據傳輸和存儲的時候因爲unicode比較浪費空間和資源.須要把unicode轉存成UTF-8或者GBK進行存儲.怎麼轉換呢.在python中能夠把文字信息進行編碼,編碼以後的內容就能夠進行傳輸了,編碼以後的數據是bytes類型的數據.其實啊,仍是原來的數據只是通過編碼以後表現形式發生了改變而已.
bytes的表現形式:

1.英文b'alex'  英文的表現形式和字符串沒什麼兩樣
2.中文b"\xe4\xb8\xad' 這是一個漢字的UTF-8的bytes表現形式

  

字符串在傳輸時轉化成bytes=> encode(字符集)來完成

s = "alex"
print(s.encode("utf-8")) #將字符串編碼成UTF-8 
print(s.encode("GBK")) #將字符串編碼成GBK
#結果:
b'alex'
b'alex'


s = ""
print(s.encode("UTF-8")) #中文編碼成UTF-8 
print(s.encode("GBK")) # 中文編碼成GBK
#結果: 
b'\xe4\xb8\xad' 
b'\xd6\xd0'

記住:英文編碼以後的結果和源字符串一致.中文編碼以後的結果根據編碼的不一樣,編碼結果也不一樣.咱們能看到,一箇中文的UTF-8編碼是3個字節,一個GBK的中文編碼是2個字節.
編碼以後的類型就是bytes類型.在網絡傳輸和存儲的時候咱們python是保存和存儲的bytes類型.那麼在對方接收的時候,也是接收的bytes類型的數據.
咱們可使用decode0來進行解碼操做.把bytes類型的數據還原回咱們熟悉的字符串:

s = "我叫李嘉誠"
print(s.encode("utf-8")) # b'\xe6\x88\x91\xe5\x8f\xab\xe6\x9d\x8e\xe5\x98\x89\xe8\xaf\x9a'
print(b'\xe6\x88\x91\xe5\x8f\xab\xe6\x9d\x8e\xe5\x98\x89\xe8\xaf\x9a'.decod e("utf-8")) # 解碼

編碼和解碼的時候都須要制定編碼格式.

s = "我是文字"
bs = s.encode("GBK") # 咱們這樣能夠獲取到GBK的文字 

# 把GBK轉換成UTF-8
# 首先要把GBK轉換成unicode. 也就是須要解碼
s = bs.decode("GBK") # 解碼成unicode
# 而後須要進⾏從新編碼成UTF-8
bss = s.encode("UTF-8") # 從新編碼
print(bss)

 

Python2和Python3的比較:

- 字符串和字節不一樣
    py2:   name=u"alex"(用unicode進行編碼)                   name='alex'(utf-8/gbk/ascii)   
                unicode(就是py3中的str類型)                     str(就是py3中的bytes類型) 
    py3: name='alex'(用unicode進行編碼)                      name=b'alex'(utf-8/gbk/ascii)
str bytes

 




今日做業

今日做業及默寫

相關文章
相關標籤/搜索