本節是第五講的第三小節,上節為大家介紹了Python語言的特點,共有8大特點(要素),幫助大家快速瞭解Python語言。本節主要為大家介紹Python語言的數字型別包括(整型、布林型、浮點型、複數型、十進位制型)。
識別符號與關鍵字(Identifiers and keywords)
有效的Python識別符號是任意長度的非空字元序列,其中包括一個“引導字元”以及0個或多個“後續字元”。Python識別符號必須符合兩條規則,並遵循某些約定。
第一條規則是關於引導字元與後續字元的。只要是Unicode編碼的字母,都可以充當引導字元,包括ASCII字母("a"、"b" ... "z", "A"、 "B"、...、"Z”)、下劃線以及大多數非英文語言的字母。後續字元可以是任意引導字元,或任意非空格字元,包括Unicode編碼中認為是數字的任意字元,比如("0"、“1”、...、 "9"),或者是加泰羅尼亞字元”•“。識別符號是大小寫敏感的,因此,TAXRATE、Taxrate、TaxRate、 taxRate與taxrate是5個不同的識別符號。
第二條規則是Python識別符號不能與Python關鍵字同名,因此,不能使用表中的這些關鍵字作為識別符號的名稱。
Python的關鍵字
and
continue
except
global
lambda
pass
while
as
def
False
if
None
raise
with
assert
del
finally
import
nonlocal
return
yield
break
elif
for
in
not
True
class
else
from
is
or
try
第一條約定是:不要使用Python預定義的識別符號名對自定義的識別符號進行命名, 要避免使用Python內建資料型別(比如int、 float、list、str與tuple)的名稱,也不要使用Python內建函式名與異常名作為識別符號名。 讀者可能會困惑如何判斷自己對識別符號的命名是否在上面需要避免的範圍之內, Python有一個內建的名為dir()的函式,該函式可以返回物件屬性列表。不帶引數呼叫該函式時,將返回Python內建屬性列表。
第二條約定是:關於下劃線(_)的使用,名的開頭和結尾都使用下劃線的情況(_) 應該避免使用,這是因為Python定義了各種特殊方法與變數,使用的就是這樣的名稱。單一的下劃線本身也可以當作一個識別符號,在不關心迭代針對的具體資料項時,有些程式設計師喜歡在for...in迴圈中使用。
for _ in (0, 1,2, 3, 4, 5):
print("Hello")
判斷是否是有效識別符號的最簡單方法是在互動式的Python直譯器或IDLE的 Python Shell中對其進行賦值操作,下面給出幾個例項:
>>> stretch-factor = 1
SyntaxError: cannot assign to operator
>>> 2miles = 2
SyntaxError: invalid syntax
>>> str = 3 # Legal but BAD
使用無效的識別符號時,會產生一個SyntaxError異常。第一個賦值操作失敗的原因在於,不是一個Unicode字母、數字或下劃線。第二個賦值操作失敗是 因為引導字元不是Unicode字母或下劃線,而數字只能充當後續字元。如果識別符號是有效的,就不會有異常產生——即便識別符號是內建的資料型別、異常或函式的名稱, 因此,第三個賦值操作可以工作,儘管並不建議這樣做。
Integral 型別(整型數)
Python提供了兩種內建的Integral型別,即int(integer)與bool整數與布林型值都是固定的,但由於Python提供了增強的賦值運算子,使得這一約束極少導致實際問題。在布林表示式中,0與False表示False,其他任意整數與true都表示true。在數字表達式中,True表示1, False表示0。這意味著,有些看起來很怪異的表示式也是有效的。 例如,我們可以使用表示式i+= True來對整型變數i進行遞增操作,當然,最自然的方法還是i+=1。
整數(int)
整數的大小隻受限於機器的記憶體大小,因此,包含幾百個數字的整數可以很容易地建立與操縱——儘管在速度上會比處理那些可以由處理器自然表示的整數要慢。
預設情況下,整數字面值(literals)採用的是十進位制,但在方便的時候也可以使用其他進位制:
>>> 14600926 # decimal
14600926
>>> 0b110111101100101011011110 # binary
14600926
>>> 0o67545336 # octal
14600926
>>> 0xDECADE # hexadecimal
14600926
二進位制數以0b引導,八進位制數以0o引導,十六進位制數則以0x引導,大寫字母也可以使用。
所有常見的數學函式與運算子都可用於整數,如表所示。有些功能由內建函式提供,比如abs()函式,abs(i)可以返回整數i的絕對值;有些功能由int運算子提供, 比如,i+j返回整數i與整數j的和。
數值型運算子與函式
x + y
將數x與數y相加
x ** y
計算x的y次幕,參見pow()函式
x - y
從x減去y
abs(x)
返回x的絕對值
x * y
將x與y相乘
divmod(x, y)
以二元組的形式返回x除以y所得的商和餘數(兩個整數)
x / y
用x除以y,總是產生一個浮點值(如果x或y是複數就產生一個複數)
pow(x, y)
計算x的y次幕,與運算子**等同
x // y
用x除以y,捨棄小數部分,使得結果總是整數,參見round()函式
pow(x, y, z)
(x**y)%z的另一種寫法
x % y
用x除以y取模(餘數)
round(x, n)
返回浮點數X四捨五入後得到的相應整數(n小數點位數)
所有二元數學運算子(+、-、/、//、%與**)都有相應的增強版賦值運算子(+=、 -=、/=、//=、%=與**=),這裡,x op=y在運算邏輯上與x = x op y是等價的。
物件的建立可以透過給變數賦字面意義上的值,比如x=17,或者將相關的資料型別作為函式進行呼叫,比如x=int(17)。有些物件(比如,型別為decimal.Decimal)只能透過資料型別建立,這是因為這些物件不能用字面意義表示。使用資料型別建立物件時,有3種用例。
第一種情況是,不使用引數呼叫資料型別函式,這種情況下,物件會被賦值為一個預設值,比如,x=int()會建立一個值為0的整數。所有內建的資料型別都可以作為函式並不帶任何引數進行呼叫。
第二種情況是,使用一個引數呼叫資料型別函式。如果給定的引數是同樣的資料型別,就將建立一個新物件,新物件是原始物件的一個淺複製(shallow copy)。如果給定的引數不是同樣的資料型別,就會嘗試進行轉換。下表展示了 int型別時的這種用法。如果給定引數支援到給定資料型別的轉換,但是轉換失敗,就會產生一個 ValueError異常,否則返回給定型別的物件。如果給定引數不知道到給定資料型別的轉換,就會產生一個TypeError異常。
第三種情況是,給定兩個或多個引數---但不是所有資料型別都支援,而對支援這一情況的資料型別,引數型別以及內涵都是變化的。對於int型別,允許給定兩個引數,其中第一個引數是一個表示整數的字串,第二個引數則是字串表示的base。 比如,int("A4", 16)會建立一個值為164的整數。
bin(i) #返回整數i的二進位制表示(字串),比如bin(1980) = '0b11110111100'
hex(i) #返回i的十六進位制表示(字串),比如hex(1980) = '0x7bc'
oct(i) #返回i的八進位制表示(字串),比如oct(1980) = '0o3674'
int(x) #將物件x轉換為整數,失敗時會產生ValueError異常,如果x的資料型別不知道到整數的轉換,就會產生TypeError異常;如果x是一個浮點數,就會擷取其整數部分
int(s, base) #將字串s轉換為整數,失敗時會產生ValueError異常。如果給定了可選的基引數,那麼應該為2 到36之間的整數
布林型(bool)
有兩個內建的布林型物件:True與False。與所有其他的Python資料型別類似,布林資料型別也可以當作函式進行呼叫 ——不指定引數時將返回False,給定的是布林型引數時,會返回該引數的一個複製, 給定的是其他型別的引數時,則會嘗試將其轉換為布林資料型別。所有內建的資料型別與標準庫提供的資料型別都可以轉換為一個布林型值,為自定義資料型別提供布林型轉換也很容易。下面給出了兩個布林型賦值操作以及兩個布林表示式:
>>> t = bool(True)
>>> f = False
>>> t and f
False
>>> t and True
True
前面已經講過,Python提供了 3個邏輯運算子:and、or與not。and與or都使用 “短路"邏輯,並返回決定其結果的運算元,not則總是返回True或False。
習慣於使用老版本Python的程式設計師有時會使用1與0,而非True與False,這種用法幾乎總是可以正常工作的,但是建議在需要布林型值的時候,新程式碼中還是使用內建的布林型物件。
浮點型別(Floating-Point Types)
Python提供了 3種浮點值:內建的float與complex型別,以及來自標準庫的 decimal.Decimal型別,這3種資料型別都是固定的。float型別存放雙精度的浮點數, 具體取值範圍則依賴於構建Python的C 編譯器,由於精度受限,對其進行相等性比較並不可靠。float型別的數值要使用小數點或使用指數表示,比如, 0.0、4.、5.7、-2.5、-2e9、8.9e-4 等。
>>> 0.0, 5.4, -2.5, 8.9e-4
(0.0, 5.4, -2.5 ,0.00089)
如果我們確實需要高精度,那麼可以使用來自decimal模組的decimal.Decimal數。 這種型別在計算時,可以達到我們指定的精度(預設情況下,到小數點後28位),並且可以準確地表示迴圈小數,比如0.1,但在處理速度上比通常的float要慢很多。由於準確性的優勢,decimal.Decimal數適合於財政計算。
Python支援混合模式的算術運算,比如使用int與float運算,生成float數;使用 float與complex運算,生成complex結果。由於decimal.Decimal是混合精度的,只能用於其他decimal.Decimal數或int,在與int混合運算時,會生成decimal.Decimal 結果。如果使用不相容的資料型別進行運算,會產生TypeError異常。
浮點數(Floating-Point Numbers)
所有數值型操作與函式都可以與float 一起使用,包括增強版的賦值運算子。float資料型別可以作為函式呼叫——不指定引數時返回0.0,指定的是float型引數時返回該引數的一個複製,指定其他任意型別的引數時都嘗試將其轉換為float。用於轉換時,可以給定一個字串引數,或者使用簡單的十進位制表示,或者使用指數表示。 在進行涉及float的計算時,可能會生成NaN (“不是一個數字”)或“無窮”。遺憾的是,這種行為並不是在所有實現中都一致,可能會由於系統底層數學庫的不同而不同。
下面給出一個簡單函式,該函式用於比較float是否相等(按機器所能提供的最大精度):
def equal_float(a, b):
return abs(a - b)<= sys.float_info.epsilon
>>>sys.float_info
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)
為了實現上述函式,需要匯入sys模組。sys.float_info物件有很多屬性,sys.float_ info.epsilon是機器可以區分出的兩個浮點數的最小區別。Python的float通常會提供至多17個數字的精度。
如果在IDLE中輸入sys.float_info,就可以顯示其所有屬性,包括機器可以表示的浮點數的最小值與最大值,輸入help(sys.float_info)會顯示關於sys.float_info物件的某些資訊。
Help on float_info object:
class float_info(builtins.tuple)
| float_info(iterable=(), /) ......
使用int()函式,可以將浮點數轉換為整數——返回其整數部分,捨棄其小數部分; 或者使用round()函式,該函式將對小數部分四捨五入;或者使用math.floor()函式,或 math.ceil()函式——該函式可以將浮點數轉換為最近鄰的整數。如果浮點數的小數部分為0, float.is_integer(x)方法將返回True,浮點數的小數表示可以使用float.as_integer_ratio()方法獲取,比如,給定浮點數x = 2.75,則呼叫 x.as_integer_ratio()將返回(11,4)(返回一對整數,其比率正好等於原浮點數並且分母為正數)。使用float()函式,可以將整數轉換為浮點數。
使用float.hex()方法,可以將浮點數以十六進位制形式表示為字串,相反的轉換可以使float.fromhex()實現。比如:
s = 14.25.hex() # str s == '0x1.c800000000000p+3'
f = float.fromhex(s) # float f == 14.25
t = f.hex() # str t == '0x1.c800000000000p+3'
>>> import math
>>> math.pi * (5 ** 2) # 78.53981633974483
>>> math.hypot(5, 12) #13.0
>>> math.modf(13.732) #(0.7319999999999993, 13.0)
math模組的函式與常量
math.ceil(x)
返回大於或等於x的最小整數,比如,math.ceil(5.4) = 6
math.floor(x)
返回小於或等於x的最小整數,比如,math.floor(5.4) = 5
math.fabs(x)
返回|x|,即浮點數x的絕對值
math.fsum(i)
對iterable i中的值進行求和(浮點數)
math.modf(x)
以float的形式返回x的小數與整數部分
math.hypot(x, y)
返回√(x²+y²)
math.pow(x, y)
返回x^y(浮點值)
複數(Complex Numbers)
複數這種資料型別是固定的,其中存放的是一對浮點數,一個表示實數部分,另 一個表示虛數部分。Literal複數在書寫上使用+或-符號將實數部分與虛數部分(其後 跟隨一個字母j)連線在一起,共同構成複數。比如下面這些例項:3.5+2j、0.5j、4+0j、 -l-3.7j等。注意,如果實數部分為0,就可以忽略。
複數的兩個部分都以屬性名的形式存在,分別為real與imag,例如:
>>>z =-89.5+2.125j
>>> z.real, z.imag
(-89.5, 2.125)
math模組中的函式不能處理複數,這是一個慎重的設計決策,可以確保在有些情況下,math模組的使用者得到的是異常,而不是得到一個複數。
要使用複數,可以先匯入cmath模組,該模組提供了 math模組中大多數三角函式 與對數函式的複數版,也包括一些複數特定的函式,比如cmath.phase()、cmath.polar() 與cmath.rect(),還包括cmath.pi、 cmath.e等常量,這些常量與math模組中對應物件包含同樣的浮點值。
十進位制數字(Decimal Numbers)
有些情況下,我們更需要的是完全的準確性,即便要付出速度降低的代價。decimal模組可以提供固定的十進位制數,其精度可以由我們自己指定。 涉及Decimals的計算要比浮點數的計算慢,但這是否需要關注要依賴於具體的應用程式。
要建立Decimal,必須先匯入decimal模組,例如:
>>> import decimal
>>> a = decimal.Decimal(9876)
>>> b = decimal.Decimal("54321.012345678987654321")
>>> a + b
Decimal('64197.01 2345678987654321')
十進位制數是使用decimal.Decimal()函式建立的,該函式可以接受一個整數或字串作為引數---但不能以浮點數作為引數,因為浮點數不夠精確,decimals則很精確。 如果使用字串作為引數,就可以使用簡單的十進位制數表示或指數表示。除提供了準確性外,decimal.Decimals的精確表述方式意味著可以可靠地進行相等性比較。
從Python 3.1開始,使用decimal.Decimal.from_float()函式將floats轉換為十進位制數成為可能,該函式以一個float型數作為引數,並返回與該float數值最為接近的 decimal.Decimal。
math模組與cmath模組不適於處理decimal.Decimals,但是math模組提供的一些函式可以作為decimal.Decimal的方法使用,比如,要計算e^x (x是一個浮點數),可以使用math.exp(x),但如果x是一個decimal.Decimal,就需要使用x.exp()。
有些情況下,浮點數與decimal.Decimals在精度上的差別會變得很明顯:
>>> 23 / 1.05
21.904761904761905
>>> print(23 / 1.05)
21.9047619048
>>> print(decimal.Decimal(23) / decimal.Decimal("1.05"))
21.90476190476190476190476190
>>> decimal.Decimal(23) / decimal.Decimal("1.05")
Decimal('21.90476190476190476190476190')
儘管使用decimal.Decimal的除法操作要比使用浮點數的精確得多,這一場景(32 位機器上)下,區別只在fifteenth decimal place才表現出來。在很多情況下,這種差別並不是很大的問題。
另一個需要注意的是上面例項中最後兩行,這裡第一次展示了列印物件時的一些幕後格式化操作。在使用decimal.Decimal(23)/decimal.Decimal("1.05")的結果作為引數呼叫print()函式時,列印的是bare number—其輸出為字串形式。如果只是簡單地輸入該表示式,就會得到一個decimal.Decimal輸出,此時的輸出是表象形式。所有 Python物件都有兩種輸出形式。字串形式在設計目標上是為了更易於閱讀,表象形式(Representational form)在設計目標上則是生成備用的輸出資訊,這種輸出資訊作為Python直譯器的輸入時會重新產生所代表的物件。