003.數值型別
❝本系列文章是我個人學習《python學習手冊(第五版)》的學習筆記,其中大部分內容為該書的總結和個人理解,小部分內容為相關知識點的擴充套件。
非商業用途轉載請註明作者和出處;商業用途請聯絡本人(gaoyang1019@hotmail.com)獲取許可。
❞
「這不是演習!」
好了,從本章開始,我們就要正式進入python的學習.所涉及的內容深度會有所提升,但是還到不了學習完1+1=2之後就開始微積分推導的陡峭程度. 相關的補充內容我會以知識點補充或者外鏈的方式新增進來.
數值型別的基本知識
Python中的數值型別主要包括以下三類:
**整數:**也就是我們所熟悉的int型別. 在python3之中,不再區分整數和長整數.也就是說允許整數具備無限的精度. 當然,這個精度取決於我們計算機的記憶體大小. 「浮點數:」 浮點數在標準的CPython中,採用的是C語言的雙精度浮點數. 其精度和構建python直譯器的C語言編譯器的雙精度一致.具體的精度資訊可以在 sys.float_info
中檢視,如下圖,詳細解釋請參考文件「複數:」 複數由實部和虛部構成,字面量的寫法可以寫成 a+bj
的形式或者直接通過complex(real,imag)
來構建
In [2]: import sys
# 雙精度浮點數相關資訊
In [3]: sys.float_info
Out[3]: sys.float_info(max=1.7976931348623157e+308, max_exp=1024, max_10_exp=308, min=2.2250738585072014e-308, min_exp=-1021, min_10_exp=-307, dig=15, mant_dig=53, epsilon=2.220446049250313e-16, radix=2, rounds=1)
# 虛數的表示
In [4]: cmplx = complex(1,2)
In [5]: cmplx
Out[5]: (1+2j)
In [6]: type(cmplx)
Out[6]: complex
除了以上三種型別之外,python的數字型別還包括布林型別.
字面量 | 相關的解釋 |
---|---|
1234,-24,0 | 整數型別,無大小限制 |
1.23,3.1415 | 浮點數型別 |
0o177,0x9ff,0b10011100 | python3中的十六進位制,八進位制和十進位制 |
3+4j,3.0+4.0J | 複數 |
set("spam"),{1,2,3,4} | 集合 |
Decimal('1.0'),Fraction(1,3) | 小數和分數(有理數) |
bool(X),True,False | 布林型別 |
各種進位制的表示
python的整數預設採用十進位制進行表示. 同樣,也支援二進位制,八進位制,十六進位制的表示.
**二進位制:**0b或者0B開頭表示 **八進位制:**0o或者0O開頭表示(注意第二個字元是字母o) **十六進位制:**0x或者0X開頭表示
可以使用內建函式bin(I),oct(I),hex(I)
來進行進位制轉換. 同時也支援int(str,base)
將字串轉換為對應的十進位制整數.
In [12]: a =11
In [13]: hex(a)
Out[13]: '0xb'
In [14]: oct(a)
Out[14]: '0o13'
In [15]: bin(a)
Out[15]: '0b1011'
# 將10按二進位制轉換為十進位制
In [18]: int('10',base=2)
Out[18]: 2
# 將16進位制ff轉換為十進位制
In [19]: int('ff',base=16)
Out[19]: 255
python的運算子
運算子 | 描述 |
---|---|
yield x | 生成器函式send協議 |
lambda args:expression | 匿名函式 |
x if y else z | 三元表示式 |
x or y | 邏輯或 |
x and y | 邏輯與 |
not x | 邏輯非 |
x in y, x not in y | 成員關係,用於可迭代物件和集合 |
x is y,x is not y | 物件同一性測試 |
x<y,x<=y,x>y,x>=y | 大小比較,集合的超集和子集 |
x==y,x!=y | 值的等價運算 |
x|y | 按位或,集合的並集 |
x^y | 按位異或,集合的對稱差集 |
x&y | 按位與,集合的交集 |
x<<y,x>>y | 將x左移y位,將x右移y位 |
x+y | 加法,拼接 |
x-y | 減法,集合的差集 |
x* y |
乘法,重複 |
x%y | 求餘數,格式化 |
x/y | 真除法 |
x//y | 向上去整 |
-x,+x | 取負,取正 |
~x | 按位取非 |
x**y | 冪運算 |
x[i] | 索引 |
x[i:j:k] | 分片 |
x(...) | 函式,方法,類,其他可呼叫物件的呼叫 |
x.attr | 屬性索引 |
(...) | 元組,表示式,生成器表示式 |
[....] | 列表,列表推導表示式 |
{....} | 字典,集合,集合與字典的推導 |
上表中基本把python中的運算子表示式全部列舉出來了. 而且是按照運算優先順序從低到高的順序列舉出來的.
對於混合型別的運算,永遠向著精度更高的方向進行.當然也可以通過內建函式來進行強制型別轉換
In [4]: 40+3.14
Out[4]: 43.14
In [5]: int(3.14)
Out[5]: 3
In [6]: float(5)
Out[6]: 5.0
python的數值比較
數值的比較會輸出一個布林值,比如:
In [10]: 1<2
Out[10]: True
In [11]: 2.0>3
Out[11]: False
In [13]: 2.0!=2.0
Out[13]: False
看第三項可以知道,python是支援混合型別的數值比較的.如前面所說,python在進行混合型別的數值運算的時候,會先將其轉換為精度更高的型別,然後再進行計算.
所謂鏈式比較如下例所示:
In [16]: 1<2<3
Out[16]: True
In [17]: 1==2<3
Out[17]: False
其中第一個等效於1<2 and 2<3
,第二個等效於1==2 and 2<3
數值的比較是基於數值大小進行的,對於整型的比較是沒問題的,但是對於浮點數的比較,就可能出現不可預知的錯誤. 比如以下的例子:
In [14]: 1.1+2.2 == 3.3
Out[14]: False
In [15]: 1.1+2.2
Out[15]: 3.3000000000000003
這個例子就有點讓人匪夷所思了,1.1+2.2憑什麼不等於3.3...
這是由於浮點數是有限的位元位數,導致無法精確的表示某些數值.這個問題不僅在python中存在,在其他語言中同樣存在. 不過python有分數和小數,可以很好的規避這些問題. 畢竟python適合科學計算的特性不是白來的.
python中的除法
python中有三種風格的除法和兩種除法運算子.
「X/Y」
這個是所謂的經典除法和真除法.在python2中,對於整數而言,會省略小數的部分,對於浮點數則會保留小數部分. 在python3中,無論整數還是浮點數,真除法都會保留小數部分.
In [18]: 4/2
Out[18]: 2.0
In [19]: 10/3
Out[19]: 3.3333333333333335
「X//Y」
向下取整除法,注意這個叫法,叫「向下」取整,也就是比真正結果小的那個最接近的整數.
In [20]: 10//4
Out[20]: 2
In [21]: 10//3
Out[21]: 3
向下取整除法(floor division)和截斷除法的區別:
//
操作符嚴格來說應該叫做向下取整除法,其獲取的結果是「真正結果之下」的最接近的整數.這個對於正數來說比較好理解,捨棄小數的部分.對於負數而言,就是比其結果小的最接近的負數.
In [25]: 10//4,10//-4
Out[25]: (2, -3)
In [26]: 10//9,10//-9
Out[26]: (1, -2)
通過這兩個例子就可以很好的看出來了.
那麼python中的截斷,可以通過math
模組中的trunc
方法實現
In [28]: import math
In [29]: math.floor(2.5)
Out[29]: 2
In [30]: math.floor(-2.5)
Out[30]: -3
In [31]: math.trunc(2.5)
Out[31]: 2
In [32]: math.trunc(-2.5)
Out[32]: -2
那對於所謂的截斷除法,我們可以使用一種特殊的方式.
In [33]: 5//-2
Out[33]: -3
In [34]: math.trunc(5/-2)
Out[34]: -2
按位操作
按位操作在處理網路資料包,序列程式等二進位制資料的時候十分方便,所以python中如C語言一樣,也支援位移操作.
In [1]: x=1
# 左移兩位
In [2]: x<<2
Out[2]: 4
# 按位或
In [3]: x|2
Out[3]: 3
# 按位與
In [4]: x&1
Out[4]: 1
# 按位異或
In [5]: x ^ 1
Out[5]: 0
其他的就不多說了,不難. 用到時候查下文件就完事兒了.
其他內建數值工具
數值處理相關的方法除了pow,abs這些內建方法之外,大部分的方法都在內建模組math之中. 這裡舉一些例子:
In [6]: import math
In [7]: math.pi
Out[7]: 3.141592653589793
In [8]: math.e
Out[8]: 2.718281828459045
In [9]: math.sin(90)
Out[9]: 0.8939966636005579
In [10]: math.sqrt(144)
Out[10]: 12.0
In [11]: pow(2,4)
Out[11]: 16
In [12]: abs(-42.1)
Out[12]: 42.1
In [13]: min(3,2,1)
Out[13]: 1
In [14]: max(1,3,4,9)
Out[14]: 9
# 四捨五入
In [15]: round(3.123),round(2,512),round(-3.123),round(-2.512)
Out[15]: (3, 2, -3, -3)
其他數值型別
複數
說實話,複數是個啥我都快忘了...但是python支援這玩意兒. 複數主要可以用在工程計算和科學計算中,當然作為一個數學學渣,心有餘而力不足. 所以這一塊不多說了. 簡單說一下複數的表達形式.
python中的複數是由兩個浮點陣列成,分別表示複數的實部和虛部.可以寫成 X+Yj的形式. 複數相關的處理方法主要集中在cmath模組中.
用到的時候再說吧,估計也用不到...
小數
python2.4之後引入了小數這種資料型別,正式名稱叫做Decimal. 需要注意的是python中的Decimal型別和浮點數不是一個東西. 小數很像浮點數,但是小數有固定的位數和小數點.比如,我們可以使用小數物件實現一個只有兩位小數位精度的浮點數.
根據之前的介紹我們已經瞭解了浮點數中一個詭異的現象,比如:
In [16]: 0.1+0.1+0.1-0.3
Out[16]: 5.551115123125783e-17
前文說過,這是由於浮點數儲存位數有限造成的.那麼python作為科學計算領域的老大,這麼不嚴謹的事情,肯定是不允許發生的.所以python中定義了一中新的資料型別Decimal來解決這個問題.
In [18]: Decimal('0.1')+Decimal('0.1')+Decimal('0.1')-Decimal('0.3')
Out[18]: Decimal('0.0')
這裡需要注意一點的是,上面我們是從字串建立的小數物件.如果我們直接從浮點數建立小數物件呢?
In [19]: Decimal(0.1)+Decimal(0.1)+Decimal(0.1)-Decimal(0.3)
Out[19]: Decimal('2.775557561565156540423631668E-17')
完了,饒了一圈又回來了...
這是python處理的問題.直接從浮點數建立小數物件的話,這個轉換是精確的,也就說浮點數會按照其儲存的內容完完整整的被建立為小數.(感覺這一篇寫完了是不是可以寫一篇浮點數相關的文章...)
我們可以通過設定小數數值精度,舍入模式等方法來解決這個問題.(回頭用到的時候再寫吧,我現在也有點懵逼...)
分數
分數型別在python中稱之為Fraction,實現了一個有理數物件.實質上就是顯式的保持一個分子和一個分母,從而避免浮點數的精度問題. 分數的實現不像浮點數一樣依靠底層硬體,所以,分數在效能上比浮點數要弱.
In [2]: from fractions import Fraction
# 1/3
In [3]: x=Fraction(1,3)
In [4]: y=Fraction(4,6)
In [5]: x
Out[5]: Fraction(1, 3)
In [6]: y
Out[6]: Fraction(2, 3)
In [7]: print(y)
2/3
In [8]: x+y
Out[8]: Fraction(1, 1)
集合
集合,就是數學上的那個集合.按照集合的定義,一個元素在集合中無論新增多少次,在集合中也都會表示為1次,也就說集合不能有重複的元素(初中數學好像是這麼教的...) 所以集合這個型別在涉及數值和資料庫的操作中是有著廣泛應用的.
集合有著列表和字典的一些共同特性,比如集合是可迭代的物件,可以按需增長或者縮短,可以包含多種資料型別. 另外,集合中需要注意的,集合的元素是無序的.
集合的建立比較簡單:
In [9]: x=set('abcde')
In [10]: y=set('abcfg')
In [11]: x
Out[11]: {'a', 'b', 'c', 'd', 'e'}
In [12]: y
Out[12]: {'a', 'b', 'c', 'f', 'g'}
集合支援數學上集合的那些操作:
# 差集
In [13]: x-y
Out[13]: {'d', 'e'}
# 並集
In [14]: x|y
Out[14]: {'a', 'b', 'c', 'd', 'e', 'f', 'g'}
# 交集
In [15]: x&y
Out[15]: {'a', 'b', 'c'}
# 異或(這個叫什麼集啊...沒學過呢...)
In [16]: x^y
Out[16]: {'d', 'e', 'f', 'g'}
# x是否為y的超集,y是否為x的超集
In [17]: x>y,x<y
Out[17]: (False, False)
集合也支援成員測試:
In [19]: 'a' in x
Out[19]: True
集合的修改:
In [20]: x.add('w')
In [21]: x
Out[21]: {'a', 'b', 'c', 'd', 'e', 'w'}
# 求並集
In [24]: x.update(set('awq'))
In [25]: x
Out[25]: {'a', 'b', 'c', 'd', 'e', 'q', 'w'}
In [26]: x.remove('q')
In [27]: x
Out[27]: {'a', 'b', 'c', 'd', 'e', 'w'}
集合作為一個可迭代物件,也支援len()方法和for迴圈以及列表表示式:
In [29]: for item in set('abc'):print(item*3)
bbb
ccc
aaa
「集合的另外一種建立方法」
# 可以直接使用{}來建立集合
In [30]: x={1,2,3,4}
In [31]: x
Out[31]: {1, 2, 3, 4}
In [32]: type(x)
Out[32]: set
這裡需要注意的是,對於{}
空的內容python依舊會認為其是一個字典,所以要建立空的集合還是要使用set()方法
In [34]: type({})
Out[34]: dict
作為一種可迭代物件,集合也支援推導表示式:
In [35]: {x for x in 'spam'}
Out[35]: {'a', 'm', 'p', 's'}
最後需要注意一點,python的集合有一個限制. 那就是集合中只能包含不可變的(可雜湊化的)物件型別. 像列表,字典這樣的玩意兒不能作為集合的元素.而像字串,數字常量,元組這樣的型別是可以作為集合的元素的.
「集合的優勢」
上文中已經講過,集合中的元素只能出現一次.除了實現集合的數學特性之外. 集合還可以用來過濾重複性資料,提取列表,字串以及其他可迭代型別中的差異,也可以用來進行一些順序無關的等價性測試.
# 使用集合進行重複項過濾
In [36]: L = [1,2,2,3,4,5,2,1]
In [37]: set(L)
Out[37]: {1, 2, 3, 4, 5}
In [38]: L=list(set(L))
In [39]: L
Out[39]: [1, 2, 3, 4, 5]
「差異資料的提取」
In [40]: set('while')-set('what')
Out[40]: {'e', 'i', 'l'}
In [41]: set(dir(bytes))-set(dir(bytearray))
Out[41]: {'__getnewargs__'}
「進行順序無關性的兩組資料的等價性測試」
In [45]: L1 = [1,2,3,4,5]
In [46]: L2 = [5,4,1,2,3]
In [47]: L1 == L2
Out[47]: False
In [48]: set(L1)==set(L2)
Out[48]: True
布林型別
python的布林型的定義和C語言有一點相似,本質上是int型別的子類. 有True和Flase兩個例項.其實就是整數1和0的定製版. 布林型別提高了python程式碼的可讀性. 這讓我們在設定flag的時候,更加形象. 我們可以寫while True
而不用寫while 1
In [49]: type(True)
Out[49]: bool
In [50]: True+4
Out[50]: 5
In [51]: True ==1
Out[51]: True
In [52]: True is 1
Out[52]: False
臥槽,這章終於寫完了...就這樣...