官术网_书友最值得收藏!

2.3 基本計算

2.3.1 變量

在程序中,我們需要保存一些值或者狀態之后再使用,這種情況就需要用一個變量來存儲它,這個概念跟數學中的“變量”非常類似,比如下面一段代碼:

在36行按〈Enter〉鍵后并不會出現新的一行,而是光標在最左端閃動等待用戶輸入,我們輸入任意內容,比如Type something here,按〈Enter〉鍵后才會出現新的一行,這時候a中就存儲了我們輸入的內容。顯然,根據輸入內容的不同,a的值也是不同的,所以說a是一個變量。

要注意的是,在編程語言中單個等號“=”一般不表示“相等”的語義,而是表示“賦值”的語義,即把等號右邊的值賦給等號左邊的變量,后面講解運算符的時候會有更加詳細的解釋。

在Python中聲明一個變量是非常簡單的事情,如果變量的名字之前沒有被聲明過的話,只要直接賦值就可以聲明新變量了,比如:

考慮下面這段代碼:

注意到了嗎?a的類型是在不斷變化的,這也是Python的特點之一——動態類型,即變量的類型可以隨著賦值而改變,這樣很符合直覺,同時也易于程序的編寫。

變量的名稱叫作標識符,而開發者可以近乎自由地為變量取名。之所以說是“近乎”自由,是因為Python的變量命名還是有一些基本規則的。

● 標識符必須由字母、數字、下劃線構成。

● 標識符不能以數字、開頭。

● 標識符不能是Python關鍵字。

什么是關鍵字呢?關鍵字也叫保留字,是編程語言預留給一些特定功能的專有名字。Python具體的關鍵字列表如下:

這些關鍵字的具體功能會在后續章節覆蓋到,比如馬上就會遇到True、False、and、or、not這幾個關鍵字。

2.3.2 算術運算符

運算符用于執行運算,運算的對象叫操作數。比如對于“+”運算符,在表達式1+2中,操作數就是1和2。運算符根據操作數的數量不同有一元運算符、二元運算符和三元運算符。在Python中,根據功能還可分為算術運算符、比較運算符、賦值運算符、邏輯運算符、位運算符、成員運算符、身份運算符。其中算術運算符、比較運算符、賦值運算符、邏輯運算符和位運算符比較基礎也比較常用。而剩下兩種,成員運算符和身份運算符,則需要一些前置知識才方便理解,將在后面的章節認識它們。

Python除了支持之前提到的四則運算,它還支持取余、乘方、取整除這三種運算。這些運算都是二元運算符,也就是說它們需要接受兩個操作數,然后返回一個運算結果。

為了方便舉例,我們定義兩個變量,alice=9bob=4,具體的運算規則如表2-1所示。

表2-1 算術運算符

值得注意的是,通過duck typing其實可以讓上述運算符支持任意兩個對象之間的運算,這是Python中很重要的一種特性,我們會在面向對象編程中提到它,這里簡單理解為算術運算符只用于數字類型運算就可以了。

特殊的,+和-還是兩個一元運算符,例如-alice可以獲得alice的相反數。

1.比較運算符和邏輯運算符

比較運算符,顧名思義,是將兩個表達式的返回值進行比較,返回一個布爾型變量。它也是二元運算符,因為需要兩個操作數才能產生比較。

邏輯運算符,是布爾代數中最基本的三個操作,也就是與、或、非,比如:

要注意的是,這些表達式最后輸出的值只有兩種—— TrueFalse,這跟之前介紹的布爾型變量取值只有兩種是完全吻合的。其實與其理解為兩種取值,不如理解為兩種邏輯狀態,即一個命題總有一個值,真或者假。

所有的比較運算符運算規則如表2-2所示。

表2-2 比較運算符

注意這里正如之前提到的,單個等號的語義為“賦值”,而兩個等號放一起的語義才是“相等”。

但是如果我們想同時判斷多個條件,那么這時候就需要邏輯運算符了,比如:

通過邏輯運算符,我們可以連接任意個表達式進行邏輯運算,然后得出一個布爾類型的值。

邏輯運算符的只有and,or和not,具體的運算規則如表2-3所示。

表2-3 邏輯運算符

2.賦值運算符

二元運算符中最常用的就是賦值運算符“=”,它的意思是把等號右邊表達式的值賦值給左邊的變量,當然要注意這么做的前提是賦值運算符的左值必須是可以修改的變量。如果我們賦值給了不可修改的量,就會產生如下的錯誤:

對一個字面量或者關鍵詞進行賦值操作,這顯然是沒有意義并且不合理的,所以它報錯的類型是SyntaxError,意思是語法錯誤。這里是我們第一次接觸到了Python的異常機制,后面的章節會更加詳細地介紹,因為這是寫出一個強魯棒性程序的關鍵。

3.復合賦值運算符

很多時候操作數本身就是賦值對象,比如i=i+1。由于這樣的語句會經常出現,所以為了方便和簡潔,就有了算術運算符和賦值運算符相結合的復合賦值運算符。它們相當于將一個變量本身作為左側的操作數,然后將相關的運算結果賦給本身。

算術運算符對應的復合賦值運算符,如表2-4所示。

表2-4 復合賦值運算符

(續)

我們來動手試一試復合賦值運算符,代碼如下:

可以看到復合賦值運算符的確簡化了代碼,同時也增強了可讀性。

4.位運算符

所有的數值類型在計算機中都是二進制存儲的,比如對于一個整數30而言,在計算機內的存儲形式可能就是0011110,而位運算就是以二進制位為操作數的運算。

所有的位運算符如表2-5所示。

表2-5 位運算符

位運算比較抽象,下面舉例說明。

(1)移位運算

先看按位左移和右移,代碼如下:

a是一個十進制表示為211,二進制表示為11010011的整數,我們對它進行左移1位,得到了422。不難發現,這就是乘以2。從二進制的角度來看,就是在這個數最后加了個0,但是從位運算的角度看,實際的操作是所有的比特位全都向左移動了一位,而新增的最后一位用0補上。這里要注意的是,移位運算符的右操作數是移動的位數。

我們用一個表來精細對比下前后的二進制表示,其中表的第一行是二進制表示的位數,低位在右邊,高位在左邊,如表2-6所示。

表2-6 按位左移

對于左移而言,所有的二進制位會向左移動數位,空出來的位用0補齊。如果丟棄的位中沒有1,也就是說沒有溢出的話,等價于原來的數乘以2。

類似地,右移就是丟棄最后幾位,剩下的位向右移動,空出來的位使用0補齊。從十進制的角度來看,這就是整除以2,如表2-7所示。

表2-7 按位右移

(2)與運算

先看一個例子:

這里給出與運算的運算規則,在離散數學中這也叫真值表,如表2-8所示。

表2-8 與運算真值表

對于與運算的規則其實非常好理解,只要參與運算的兩個二進制位中任意一位為0那么結果就是0,是不是覺得和之前講的邏輯運算符and有點像?實際上從邏輯運算的角度來看,二者就是等價的。

直接看可能與運算有些難理解,我們用一個表格來說明,如表2-9所示。

表2-9 與運算

從低位到高位一位一位地分析剛才這個例子。

● 第0位,1 &0=0

● 第1位,1 &0=0

● 第2位,0 &0=0

● 第3位,0 &0=0

● 第4位,1 &1=1

● 第5位,0 &1=0

● 第6位,1 &0=0

● 第7位,1 &0=0

所以就得到了結果00010000。與運算有一個常見的應用就是掩碼,比如我們想獲得某個整數二進制表示中的前三位,那么就可以把這個整數和7相與,因為7的二進制表示是0b00000111,這樣一來結果中除了前三位以外所有的二進制位都是0,而結果中前三位和原來前三位是一樣的,也就是說利用與運算可以獲得一個整數二進制表示中的任何一位,這就是“掩碼”的作用。

(3)或運算

仍然是先看一個例子:

這里給出或運算的規則,如表2-10所示。

表2-10 或運算真值表

對于或運算來說,參與運算的兩個二進制位只要有一個為1結果就為1,這跟之前講過的or運算符是一致的。

我們再用表格分析上述或運算,如表2-11所示。

表2-11 或運算

從低位到高位一位一位地分析這個例子。

● 第0位,1|0=1

● 第1位,1|0=1

● 第2位,0|0=0

● 第3位,0|0=0

● 第4位,1|1=1

● 第5位,0|1=1

● 第6位,1|0=1

● 第7位,1|0=1

所以就得到了結果11110011。或運算可以用來快速把二進制中某些位置1,比如我們想把某個數的前三位置1,只要跟7或運算即可,因為7的二進制表示是0b00000111,可以確保前三位運算的結果一定是1,而其他位和原來一致。

5.按位取反

按位取反是一個一元運算符,因為它只有一個操作數,它的用法如下:

按位取反的運算規則,如表2-12所示。

表2-12 按位取反真值表

也就是每一位如果是0就變成1,如果是1就變成0。按照這個運算規則,運算的結果應該如表2-13所示。

表2-13 按位取反

但是上面的例子中按位取反后的二進制表示有點奇怪,它竟然有一個負號,而且也跟上面表格中的結果不太一樣,問題出在哪了呢?

我們回想一下,計算機內所有數據都是以二進制存儲的,負號也是一樣,為了處理數據方便,計算機采用了一種叫作“補碼”的方法來存儲負數,具體的做法是二進制表示的最高位為符號位,0表示正數,1表示負數,對于一個用補碼表示的二進制整數wn-1wn-2...w1,它的實際數值為

這看起來非常抽象,為了方便敘述回到上面這個例子,對于211來說,因為Python輸出二進制的時候省略了符號位,只用正負號表示,所以它的二進制表示其實應該是011010011,按照上述給的公式計算的話就是27+26+24+21+20=221,接著按照取反的運算規則會得到100101100,同樣按照公式計算的話有-28+25+23+22=-212,結果和例子中是一樣的。

所以就本例而言,取反得到的負數在計算機內的存儲形式的確是100101100。但是由于Python輸出二進制的時候沒有符號位,只有正負號,也就是說如果原樣輸出0b100101100,最高位1其實不是符號位,實際表示的是正數0100101100(這里最高位0表示正數),這是不合理的,所以Python輸出的是-0b11010100,因為0b11010100表示的整數是011010100,即212。

6.異或運算

仍然是先看一個例子:

異或的具體規則如表2-14所示。

表2-14 異或運算真值表

異或的運算規則是參與運算的兩個二進制位相異(不同)則為1,相同則為0。

再用表格分析上述異或運算,如表2-15所示。

表2-15 異或運算

從低位到高位一位一位地分析:

● 第0位,1 ^0=1

● 第1位,1 ^0=1

● 第2位,0 ^0=0

● 第3位,0 ^0=0

● 第4位,1 ^1=0

● 第5位,0 ^1=1

● 第6位,1 ^0=1

● 第7位,1 ^0=1

所以就得到了結果0b11100011。

7.復合賦值運算符

位運算也有相應的復合賦值運算符,如表2-16所示。

表2-16 位運算對應的復合賦值運算符

2.3.3 運算符優先級

Python中不同的運算符具有不同的優先級,高優先級的運算符會優先于低優先級的運算符計算,比如乘號的優先級應該比加號高,冪運算的優先級應該比乘法高,看一個簡單的例子:

但是Python的運算符遠不止加減乘除幾個,表2-17中按照優先級從高到低列出了常用的運算符。其中的is表示內存地址的一致,is not表示內存地址的不一致,in表示某個元素在列表中,not in表示某個元素不在列表中。

表2-17 運算符優先級

如果需要改變優先級,可以通過圓括號( )來提升優先級。( )優先于一切運算符號,程序會優先運算最內層的( )的表達式。

主站蜘蛛池模板: 滨海县| 奈曼旗| 兴义市| 海城市| 扶绥县| 柳州市| 澄江县| 三江| 老河口市| 南通市| 陕西省| 桐庐县| 开封市| 富阳市| 彭泽县| 湖北省| 吉安县| 嵊州市| 滨州市| 砚山县| 昂仁县| 道孚县| 惠水县| 封开县| 霍山县| 巴林右旗| 屯留县| 成安县| 昌图县| 基隆市| 绿春县| 芜湖市| 祁东县| 巴林右旗| 营山县| 宁安市| 花莲县| 建昌县| 皮山县| 灯塔市| 寿宁县|