免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
你不知道的Python特性,其實可以解決很多問題!
圖靈教育 2019-04-09 15:22:39

本文會通過一些實例來介紹Python 的一些特性,每個實例都會解決具體的問題和難題。

  • 創(chuàng)建有意義的名稱和使用變量
  • 使用大整數(shù)和小整數(shù)
  • 在浮點數(shù)、小數(shù)和分數(shù)之間選擇
  • 在真除法和floor 除法之間選擇

floor 除法就是向下取整除法。向上取整除法是ceiling。

創(chuàng)建有意義的名稱和使用變量

如何確保程序易于理解呢?要編寫富有表現(xiàn)力的代碼,一個核心要素就是使用有意義的名稱。但什么是有意義的呢?在本實例中,我們將回顧一些創(chuàng)建有意義的Python名稱的通用規(guī)則。

我們還將介紹Python 的一些不同形式的賦值語句,如用同一條語句為多個變量賦值。

一、準備工作

創(chuàng)建名稱的核心問題是:被命名的是什么?

對于軟件,我們需要一個描述被命名對象的名稱。顯然,像x 這樣的名稱不是很有描述性,它似乎并不指向?qū)嶋H的事物。模糊的非描述性名稱在一些程序設(shè)計中很常見,令人十分痛苦。當使用它們時,無助于其他人理解我們的程序。描述性名稱則一目了然。

在命名時,區(qū)分解決方案域和問題域(真正想要解決的問題)也很重要。解決方案域包括Python、操作系統(tǒng)和互聯(lián)網(wǎng)的技術(shù)細節(jié)。不需要深入的解釋,任何人在閱讀代碼時都可以看到解決方案。然而,問題域可能因技術(shù)細節(jié)而變得模糊。我們的任務(wù)是使問題清晰可見,而精心挑選的名稱將對此有所幫助。

二、實戰(zhàn)演練

首先看看如何命名,然后再學(xué)習(xí)如何為對象分配名稱。

1. 明智地選擇名稱

在純技術(shù)層面上,Python 名稱必須以字母開頭。它們可以包括任意數(shù)量的字母、數(shù)字和下劃線。因為Python 3 基于Unicode,所以字母不限于拉丁字母。雖然通常使用拉丁字母A~Z,但這不是必須遵循的規(guī)定。

當創(chuàng)建一個描述性變量時,我們需要創(chuàng)建既具體又能表達程序中事物之間關(guān)系的名稱。一種廣泛使用的命名技巧就是創(chuàng)建“從特殊到一般”這種風格的長名稱。

選擇名稱的步驟如下。

(1) 名稱的最后一部分是事物的廣義概要。有時候,僅此一部分就能滿足命名的需要,靠上下文提供其余的信息。稍后將介紹一些典型的廣義概要的類別。

(2) 在應(yīng)用程序或問題域周圍使用前綴限定名稱。

(3) 如有必要,使用更精確和專用的前綴,以闡明它與其他類、模塊、包、函數(shù)和其他對象的區(qū)別。對前綴有疑問時,回想一下域名的工作原理。例如,mail.google.com 這個名稱表明了從特殊到一般的三個級別。三個級別的命名并不罕見,我們經(jīng)常采用這種命名方法。

(4) 根據(jù)在Python 中的使用方法來命名。需要命名的事物有三大類,如下所示。

  • 類:類的名稱能夠概述類中的所有對象。這些名稱通常使用大駝峰命名法(Capitalized-CamelCase)。類名的第一個字母大寫,強調(diào)它是一個類,而不是類的實例。類通常是一個通用的概念,很少用于描述有形的事物。
  • 對象:對象的名稱通常使用蛇底命名法(snake_case)。名稱全部小寫,單詞之間使用多個下劃線連接。在Python 中,一切皆是對象,包括變量、函數(shù)、模塊、包、參數(shù)、對象的屬性、類的方法等。
  • 腳本和模塊文件:這些文件是Python 看到的真正的操作系統(tǒng)資源。因此,文件名應(yīng)遵循Python對象的約定,使用字母、下劃線并以 .py 擴展名結(jié)尾。單從技術(shù)上說,你可天馬行空地設(shè)置文件名。但是,不遵循Python 規(guī)則的文件名可能難以用作模塊或包的名稱。

如何選擇名稱中廣義類別的那一部分呢?通用類別取決于討論的是事物還是事物的屬性。雖然世界上有很多事物,但我們?nèi)匀豢梢詣?chuàng)建一些有用的廣義分類,例如文檔、企業(yè)、地點、程序、產(chǎn)品、過程、人、資產(chǎn)、規(guī)則、條件、植物、動物、礦物等。

然后可以用修飾語來限定這些名稱:

FinalStatusDocument

ReceivedInventoryItemName

第一個示例是Document 類,我們通過添加一個前綴對其進行了略微的限定,即StatusDocument,又通過將其命名為FinalStatusDocument 來進一步限定。 第二個示例是Name 類,我們通過詳細說明它是一個ReceivedInventoryItemName 來對其進行限定。該示例需要一個4 個級別的名稱來闡明。

對象通常具有特性(property)或者屬性(attribute)。它們應(yīng)當是完整名稱的一部分,可以根據(jù)其表示的信息類型進行分解,如數(shù)量、代碼、標識符、名稱、文本、日期、時間、日期時間、圖片、視頻、聲音、圖形、值、速率、百分比、尺寸等。

命名的思路就是把狹義、詳細的描述放在最前面,把寬泛的信息放在最后:

measured_height_value

estimated_weight_value

scheduled_delivery_date

location_code

在第一個示例中,height 限定了更一般的表示術(shù)語value,而measured_height_value 做了進一步限定。通過這個名稱,可以思考一下其他與hight 相關(guān)的變體。類似的思想也適用于weight_value、delivery_date 和location_code。這些名稱都有一個或者兩個限定前綴。

需要避免的情況

切勿使用經(jīng)過編碼的前綴或后綴去描述詳細的技術(shù)信息。不要使用f_measured_height_value 這樣的名稱,其中f 可能指的是浮點數(shù)。這種命名方法通常被稱為匈牙利命名法(Hungarian Notation)。像measured_height_value 這樣的變量可以是任意數(shù)字類型,Python 會做所有必要的轉(zhuǎn)換。技術(shù)性修飾對于代碼閱讀者并沒有多大幫助,因為類型說明可能造成誤導(dǎo)甚至錯誤。

不要浪費太多的精力使名稱看起來屬于哪個類別。不要使用SpadesCardSuit、ClubsCardSuit 這樣的名稱。Python 有許多種命名空間,包括包、模塊和類,命名空間對象會把相關(guān)的名稱收集起來。如果將這些名稱添加到CardSuit 類中,就可以使用CardSuit.Spades,以類作為命名空間來區(qū)分其他相似的名稱。

2. 為對象分配名稱

Python 沒有使用靜態(tài)變量定義。當把名稱分配給對象時,就會創(chuàng)建變量。把對象看作處理過程的核心非常重要,變量有點像標識對象的標簽。使用基本賦值語句的方法如下。

(1) 創(chuàng)建對象。在許多示例中,對象以字面量的形式創(chuàng)建。我們使用355 或113 作為Python 中整數(shù)對象的字面量表示,也可以使用FireBrick 表示字符串,或使用(178,34,34)表示元組。

(2) 編寫如下類型的語句:變量 = 對象。例如:

>>> circumference_diameter_ratio = 355/113
>>> target_color_name = 'FireBrick'
>>> target_color_rgb = (178, 34, 34)

我們創(chuàng)建了一些對象并把它們賦值給了變量。第一個對象是數(shù)值計算的結(jié)果,接下來的兩個對象是簡單的字面量。對象通常由包含函數(shù)或類的表達式創(chuàng)建。

上面的基本賦值語句并不是唯一的賦值方式,還可以使用鏈式賦值的方式,將一個對象分配給多個變量,例如:

>>> target_color_name = first_color_name = 'FireBrick'

上例為同一個字符串對象創(chuàng)建了兩個名稱。可以通過檢查Python 使用的內(nèi)部ID 值來確認這兩個對象是否為同一個對象:

>>> id(target_color_name) == id(first_color_name)
True

結(jié)果表明,這兩個對象的內(nèi)部ID 值是相同的。

相等測試使用==,簡單賦值使用=。

隨后介紹數(shù)字和集合時將會說明結(jié)合運算符進行賦值的方法。例如:

>>> total_count = 0
>>> total_count += 5
>>> total_count += 6
>>> total_count
11

我們通過運算符進行了增量賦值。total_count + = 5 與total_count = total_count + 5是等價的。增量賦值的優(yōu)點在于簡化了表達式。

三、工作原理

本實例創(chuàng)建名稱的方法遵循如下模式:狹義的、更具體的限定符放在前面,更寬泛的、不太特定的類別放在最后。這種方法遵守用于域名和電子郵件地址的通用約定。

例如,域名mail.google.com 包括特定的服務(wù)、更通用的企業(yè)和最后的非常通用的域,這遵循了從窄到寬的原則。

又如,service@packtpub.com 以具體的用戶名開始,然后是更通用的企業(yè),最后是非常通用的域。甚至用戶名(PacktPub)也是一個具有兩部分的名稱,包括限定的企業(yè)名稱(Packt),以及更廣泛的行業(yè)[Pub,“Publishing”(出版)的簡寫,而不是“Public House”(酒吧)的簡寫]。

賦值語句是為對象命名的唯一途徑。

四、補充內(nèi)容

我們將在所有實例中使用描述性名稱。

Tip:沒有遵循這種模式的現(xiàn)有軟件應(yīng)當保持現(xiàn)狀。一般而言,最好與遺留軟件保持一致,而不是強加新規(guī)則,即使新規(guī)則更好。

幾乎每個示例都涉及變量賦值。變量賦值是有狀態(tài)的面向?qū)ο缶幊痰暮诵摹?/p>

五、延伸閱讀

描述性命名是一個正在研討的主題,涉及兩個方面——語法和語義。Python 語法的設(shè)想起始于著名的PEP-8(Python Enhancement Proposal number 8)。PEP-8 建議使用CamelCase 和snake_case 命名風格。

此外,務(wù)必進行以下操作:

>>> import this

這有助于領(lǐng)悟Python 的設(shè)計哲學(xué)。

有關(guān)語義的信息,請參閱遺留的UDEF 和NIEM 命名和設(shè)計規(guī)則標準(http://www.opengroup.org/udefinfo/AboutTheUDEF.pdf)。有關(guān)元數(shù)據(jù)和命名的詳細信息,請參閱ISO11179(https://en.wikipedia.org/wiki/ISO/IEC_11179)。

使用大整數(shù)和小整數(shù)

許多編程語言區(qū)分整數(shù)、字節(jié)和長整數(shù),有些編程語言還存在有符號整數(shù)和無符號整數(shù)的區(qū)別。如何將這些概念與Python 聯(lián)系起來呢?

答案是“不需要”。Python 以統(tǒng)一的方式處理所有類型的整數(shù)。對于Python,從幾個字節(jié)到數(shù)百位的巨大數(shù)字,都是整數(shù)。

一、準備工作

假設(shè)我們需要計算一些非常大的數(shù)字,例如,計算一副52 張的撲克牌的排列數(shù)。52! = 52 × 51×50 × … × 2 × 1,這是一個非常大的數(shù)字??梢栽赑ython 中實現(xiàn)這個運算嗎?

二、實戰(zhàn)演練

別擔心!Python 表現(xiàn)得好像有一個通用的整數(shù)類型,涵蓋了所有整數(shù),從幾個字節(jié)到填滿所有內(nèi)存的整數(shù)。正確使用整數(shù)的步驟如下。

(1) 寫下你需要的數(shù)字,比如一些小數(shù)字:355,113。實際上,數(shù)字的大小沒有上限。

(2) 創(chuàng)建一個非常小的值——單個字節(jié),如下所示:

>>> 2
2

或者使用十六進制:

>>> 0xff
255

后面的實例中將討論只含有一個值的字節(jié)序列:

>>> b'\xfe'
b'\xfe'

嚴格說來,這不是一個整數(shù)。它有一個前綴b',這表明它是一個一字節(jié)序列(1-byte sequence)。

(3) 通過計算創(chuàng)建一個很大的數(shù)字。例如:

>>> 2 ** 2048
323...656

該數(shù)字有617 個數(shù)位,這里并沒有完全顯示。

三、工作原理

Python 內(nèi)部使用兩種數(shù)字,兩者之間的轉(zhuǎn)換是無縫且自動的。

對于較小的數(shù)字,Python 通常使用4 字節(jié)或8 字節(jié)的整數(shù)值。細節(jié)隱藏在CPython 的內(nèi)核中,并依賴于構(gòu)建Python 的C 編譯器。

對于超出sys.maxsize 的較大數(shù)字,Python 將其切換到大整數(shù)——數(shù)字(digit)序列。在這種情況下,一位數(shù)字通常意味著30 位(bit)的值。

一副52張的撲克牌有多少種排列方法?答案是52! ≈ 8 ×10^67。我們將使用math 模塊的factorial函數(shù)計算這個大整數(shù),如下所示:

>>> import math
>>> math.factorial(52)
80658175170943878571660636856403766975289505440883277824000000000000

這些巨大的數(shù)字工作得非常完美!

計算52! 的第一部分(從52 × 51 × 50 × …一直到約42)可以完全使用較小的整數(shù)來執(zhí)行。在此之后,其余的計算必須切換到大整數(shù)。我們看不到切換過程,只能看到結(jié)果。

通過下面的示例可以了解整數(shù)內(nèi)部的一些細節(jié)。

>>> import sys
>>> import math
>>> math.log(sys.maxsize, 2)
63.0
>>> sys.int_info
sys.int_info(bits_per_digit = 30, sizeof_digit = 4)

sys.maxsize 的值是小整數(shù)中的最大值。我們通過計算以2 為底的對數(shù)來說明這個數(shù)字需要多

少位。

通過計算可知,Python 使用63 位值來表示小整數(shù)。小整數(shù)的范圍是從-2^64 到2^63-1。在此范圍之外,使用大整數(shù)。

通過sys.int_info 的值可知,大整數(shù)是使用30 位的數(shù)字序列,每個數(shù)字占用4 字節(jié)。

像52! 這樣比較大的值,由8 個上述30 位的數(shù)字組成。一個數(shù)字需要30 位來表示可能有些令人困惑。以用10 個符號表示十進制(base 10)的數(shù)字為例,我們需要2**30 個不同的符號來表示這些大數(shù)字的每位數(shù)。

涉及多個大整數(shù)值的計算可能會消耗相當大的內(nèi)存空間。小數(shù)字怎么辦呢? Python 如何跟蹤大量的小數(shù)字,如1 和0?

對于常用的數(shù)字(-5 到256),Python 實際上創(chuàng)建了一個私有的對象池來優(yōu)化內(nèi)存管理。你可以在檢查整數(shù)對象的id()值時得到驗證。

>>> id(1)
4297537952
>>> id(2)
4297537984
>>> a = 1 + 1
>>> id(a)
4297537984

我們顯示了整數(shù)1 和整數(shù)2 的內(nèi)部id。當計算a 的值時,結(jié)果對象與對象池中的整數(shù)2 對象是同一個對象。

當你練習(xí)這個示例時,id()值可能跟示例不同。但是,在每次使用值2 時,將使用相同的對象。在我的筆記本電腦上,對象2 的id 等于4297537984。這種機制避免了在內(nèi)存里大量存放對象2 的副本。

這里有個小技巧,可以看出一個數(shù)字到底有多大。

>>> len(str(2 ** 2048))
617

通過一個計算得到的數(shù)字創(chuàng)建一個字符串,然后查詢字符串的長度。結(jié)果表明,這個數(shù)字有617個數(shù)位。

四、補充知識

Python 提供了一組豐富的算術(shù)運算符:+、- 、*、/、//、%和**。/和//用于除法,**將執(zhí)行冪運算。

對于位處理,還有其他一些運算符,比如&、^、|、<<和>>。這些運算符在整數(shù)的內(nèi)部二進制表示上逐位操作。它們分別計算二進制與、二進制異或二進制或、左移右移

雖然這些運算符也同樣適用于大整數(shù),但是逐位操作對于大整數(shù)來說并沒有實際意義。一些二進制文件和網(wǎng)絡(luò)協(xié)議會要查看數(shù)據(jù)的單個字節(jié)中的位。

可以通過bin()函數(shù)查看應(yīng)用這些運算符的運行結(jié)果。示例如下:

>>> xor = 0b0011 ^ 0b0101
>>> bin(xor)
'0b110'

先使用0b0011 和0b0101 作為兩個位串。這有助于準確說明數(shù)字的二進制表示。然后將異或(^)運算符應(yīng)用于這兩個位序列。最后使用bin()函數(shù)查看位串形式的結(jié)果。可以通過結(jié)果仔細觀察各個位,了解操作符的實際功能。

可以把一個字節(jié)分解為若干部分。假設(shè)我們要將最左邊的2 個位與其他6 個位分開,其中一種方法是使用位操作(bit-fiddling)表達式,例如:

>>> composite_byte = 0b01101100
>>> bottom_6_mask = 0b00111111
>>> bin(composite_byte >> 6)
'0b1'
>>> bin(composite_byte & bottom_6_mask)
'0b101100'

這里先定義了一個composite_byte,其中最高有效的2 位為01,最低有效的6 位為101100。再使用>>移位運算符將composite_byte 的值右移6 個位置,去除最低有效位并保留2 個最高有效位。然后使用&運算符和掩碼來進行操作。掩碼中值為1 的位,在結(jié)果中保留對應(yīng)位置的值;掩碼中值為0 的位,結(jié)果中對應(yīng)位置的值被設(shè)置為0。

五、延伸閱讀

關(guān)于整數(shù)操作的詳細信息,請參閱https://www.python.org/dev/peps/pep-0237/。

在浮點數(shù)、小數(shù)和分數(shù)之間選擇

Python 提供了多種處理有理數(shù)和無理數(shù)近似值的方法。3 種基本選擇如下:

? 浮點數(shù)

? 小數(shù)

? 分數(shù)

有這么多種選擇,那么怎樣選擇才合適呢?

一、準備工作

確定我們的核心數(shù)學(xué)期望值很重要。如果不確定已擁有的數(shù)據(jù)類型或者想要得到的結(jié)果,真的不應(yīng)該開始編碼。我們需要退一步,用鉛筆和紙來演算一下。

除了整數(shù),在數(shù)學(xué)中涉及的數(shù)字還有3 種。

(1) 貨幣:如美元、美分或歐元。貨幣通常具有固定的小數(shù)位數(shù)。另外還有很多舍入規(guī)則,例如,可以用這些規(guī)則確定 $2.95 的7.25% 是多少美分。

貨幣的最小單位一般為0.01 元

(2) 有理數(shù)或分數(shù):使用美制單位的英尺和英寸,或在烹飪中使用杯和盎司進行測量時,經(jīng)常需要使用分數(shù)。把一個8 人量的食譜縮減為5 人量時,要用5/8 作為縮放因子進行分數(shù)運算。如何將這種方法應(yīng)用到2/3 杯米,并得到適用于廚房量具的測量值呢?

(3) 無理數(shù):包括所有其他類型的計算。必須注意,數(shù)字計算機只能逼近這些無理數(shù),而我們偶爾會看到近似值的一些奇怪現(xiàn)象。浮點近似值運算非???,但有時會出現(xiàn)截斷問題。

當計算涉及前兩種數(shù)字時,應(yīng)當避免使用浮點數(shù)。

二、實戰(zhàn)演練

本實例將分別討論這3 種數(shù)字。首先討論貨幣值計算。然后討論有理數(shù)計算,以及無理數(shù)或浮點數(shù)計算。最后討論這些類型之間的顯式轉(zhuǎn)換。

1. 貨幣值計算

在處理貨幣值時,應(yīng)當堅持使用decimal 模塊。如果使用Python 內(nèi)置的浮點數(shù),將會遇到數(shù)字的舍入和截斷問題。

(1) 為了處理貨幣值,首先從decimal 模塊導(dǎo)入Decimal 類。

>>> from decimal import Decimal

(2) 從字符串或整數(shù)創(chuàng)建Decimal 對象。

>>> from decimal import Decimal
>>> tax_rate = Decimal('7.25')/ Decimal(100)
>>> purchase_amount = Decimal('2.95')
>>> tax_rate * purchase_amount
Decimal('0.213875')

tax_rate 由兩個Decimal 對象構(gòu)建,其中一個基于字符串,另一個基于整數(shù)。我們可以直接使用Decimal('0.0725'),而不顯式地執(zhí)行除法。

結(jié)果稍微大于$0.21,因為我們計算出了小數(shù)位的全部數(shù)字。

(3) 如果通過浮點數(shù)創(chuàng)建Decimal 對象,那么將得到異常的浮點近似值。應(yīng)當避免混用 Decimal和float。為了舍入到最近的便士(penny),創(chuàng)建一個penny 對象。

>>> penny = Decimal('0.01')

(4) 使用penny 對象量化數(shù)據(jù)。

>>> total_amount = purchase_amount + tax_rate * purchase_amount
>>> total_amount.quantize(penny)
Decimal('3.16')

上述示例演示了如何使用默認的ROUND_HALF_EVEN 舍入規(guī)則。

舍入規(guī)則有很多種,Decimal 模塊提供了所有舍入規(guī)則。例如:

>>> import decimal
>>> total_amount.quantize(penny, decimal.ROUND_UP)
Decimal('3.17')

本示例顯示了使用另一種不同的舍入規(guī)則的結(jié)果。

2. 分數(shù)計算

當計算中含有精確分數(shù)值時,可以使用fractions 模塊。該模塊提供了便于使用的有理數(shù)。處理分數(shù)的流程如下。

(1) 從fractions 模塊導(dǎo)入Fraction 類。

>>> from fractions import Fraction

(2) 由字符串、整數(shù)或整數(shù)對創(chuàng)建Fraction 對象。如果由浮點數(shù)創(chuàng)建Fraction 對象,可能會遇到浮點近似值的異?,F(xiàn)象。當分母是2 的冪時,一切正常。

>>> from fractions import Fraction
>>> sugar_cups = Fraction('2.5')
>>> scale_factor = Fraction(5/8)
>>> sugar_cups * scale_factor
Fraction(25, 16)

我們從字符串2.5 創(chuàng)建了第一個分數(shù),從浮點計算5/8 創(chuàng)建了第二個分數(shù)。因為分母是2 的冪,所以計算結(jié)果非常準確。

25/16——結(jié)果是一個看起來很復(fù)雜的分數(shù),那么它的最簡分數(shù)是多少呢?

>>> Fraction(24, 16)
Fraction(3, 2)

結(jié)果表明,我們使用大約一杯半的米就可以完成5 人量的食譜。

3. 浮點近似值

Python 的內(nèi)置浮點(float)類型能夠表示各種各樣的值。對于是否使用浮點值,選擇的關(guān)鍵在于浮點值通常涉及近似值。在某些情況下,特別是在做涉及2 的冪的除法時,結(jié)果是一個精確的分數(shù)。

在其他情況下,浮點值和分數(shù)值之間可能存在細小的差異,這反映了浮點數(shù)的實現(xiàn)與無理數(shù)的數(shù)學(xué)理想之間的差異。

(1) 要使用浮點數(shù),經(jīng)常需要舍入值來使它們看起來合理。所有浮點計算的結(jié)果都是近似值。

>>>(19/155) * (155/19)
0.9999999999999999

(2) 上面的值在數(shù)學(xué)上應(yīng)該為1。由于float 使用的是近似值,所以結(jié)果并不精確。雖然這個結(jié)果與1 相差不多,但仍然錯了。當進行適當?shù)纳崛霑r,這個值會更有意義。

>>> answer =(19/155) * (155/19)
>>> round(answer, 3)
1.0

(3) 認識誤差項。在本例中,我們知道確切的答案,所以可以將計算結(jié)果與已知的正確答案進行比較。下面的示例給出的通用誤差項適用于所有浮點數(shù)。

>>> 1-answer
1.1102230246251565e-16

對于大多數(shù)浮點誤差,典型值約為10^16。Python 有一些聰明的規(guī)則,有時通過自動舍入隱藏這個錯誤。但是,對于本示例,錯誤并沒有隱藏。

這是一個非常重要的推論。

Tip:不要比較浮點值是否完全相等。

在浮點數(shù)之間使用精確的==測試時,如果近似值相差一個位,代碼就會出現(xiàn)問題。

4. 數(shù)字的類型轉(zhuǎn)換

可以使用float()函數(shù)從其他類型的值創(chuàng)建一個float 值。例如:

>>> float(total_amount)
3.163875
>>> float(sugar_cups * scale_factor)
1.5625

在第一個示例中,我們將Decimal 值轉(zhuǎn)換為float 值。在第二個示例中,我們將Fraction 值轉(zhuǎn)換為float 值。

正如剛剛看到的,我們永遠不想將float 轉(zhuǎn)換為Decimal 或Fraction:

>>> Fraction(19/155)
Fraction(8832866365939553, 72057594037927936)
>>> Decimal(19/155)
Decimal('0.12258064516129031640279123394066118635237216949462890625')

在第一個示例中,我們在整數(shù)之間進行計算,創(chuàng)建了一個具有已知截斷問題的float 值。當我們從截斷的float 值創(chuàng)建一個Fraction 時,得到的是一些暴露了截斷問題的數(shù)字。

類似地,第二個示例從float 創(chuàng)建了 Decimal 值。

三、工作原理

對于數(shù)字類型,Python 提供了多種運算符:+、-、*、/、//、%和**。這些運算符用于加法、減法、乘法、真除法、截斷除法、取模和冪運算。

Python 擅長各種數(shù)字類型之間的轉(zhuǎn)換。我們可以混合使用整數(shù)(int)和浮點數(shù)(float),整數(shù)將被轉(zhuǎn)換為浮點數(shù),以提供最準確的答案。類似地,還可以混合使用整數(shù)(int)和分數(shù)(Fraction),結(jié)果將是分數(shù)(Fractions)。我們也可以混合使用整數(shù)(int)和小數(shù)( Decimal)。但是,不能隨便混合使用小數(shù)( Decimal)與浮點數(shù)(float),或小數(shù)( Decimal)與分數(shù)(Fraction),在這樣操作之前,需要進行顯式轉(zhuǎn)換。

必須注意的是,float 值是真正的近似值。雖然Python 語法允許將數(shù)字寫為小數(shù)值,但它們在Python 內(nèi)部并不是按小數(shù)處理的。

我們可以使用普通的十進制數(shù)值在Python 中編寫如下值:

>>> 8.066e + 67
8.066e + 67

在內(nèi)部使用的實際值將包含上述十進制值的一個二進制近似值。

該示例(8.066e + 67)中的內(nèi)部值為:

>>> 6737037547376141/2 ** 53 * 2 ** 226
8.066e + 67

分子是一個大數(shù)字,6737037547376141;分母總是2^53。由于分母是固定的,因而所得到的分數(shù)只能有53 位有意義的數(shù)據(jù)。由于53 位之外的位不可用,因此值可能會被截斷。這導(dǎo)致了我們的理想化抽象和實際數(shù)字之間的微小差異。指數(shù)(2^226)需要將分數(shù)縮放到適當?shù)姆秶?/p>

在數(shù)學(xué)上,即6737037547376141 * 2^226/2^53。

可以使用math.frexp()查看數(shù)字的內(nèi)部細節(jié):

>>> import math
>>> math.frexp(8.066E + 67)
(0.7479614202861186, 226)

結(jié)果的兩個部分分別稱為尾數(shù)(mantissa)和指數(shù)(exponent)。如果將尾數(shù)乘以2^53,那么將得到一個整數(shù),這個整數(shù)是二進制分數(shù)的分子。

前面提到的誤差項與該值非常地匹配:10^16 ≈ 2^53。

與內(nèi)置的float 不同,F(xiàn)raction 是兩個整數(shù)值的精確比率。正如前邊所示,Python 中的整數(shù)可能非常大。我們可以創(chuàng)建包含具有大量數(shù)位的整數(shù)的比率,并且不受固定分母的限制。

類似地,Decimal 值基于非常大的整數(shù)值和用于確定小數(shù)點位置的縮放因子。這些數(shù)字可以是巨大的,不會有特殊的表示問題。

為什么要使用浮點數(shù)?原因有兩個

并不是所有可計算的數(shù)字都可以表示為分數(shù)。這就是數(shù)學(xué)家引入(或者可能是發(fā)現(xiàn))無理數(shù)的原因。內(nèi)置的float 類型與無理數(shù)的數(shù)學(xué)抽象非常接近。例如,像√2 這樣的值就不能表示為分數(shù)。

此外,浮點值運算非???。

四、補充知識

Python 的math 模塊包含許多用于處理浮點值的專用函數(shù)。該模塊包括了常用的函數(shù),如平方根、對數(shù)和各種三角函數(shù),還包括其他一些函數(shù),如伽瑪函數(shù)、階乘函數(shù)和高斯誤差函數(shù)。

math 模塊也包含了一些可以精確計算浮點數(shù)的函數(shù)。例如,math.fsum()函數(shù)將比內(nèi)置sum()函數(shù)更加周密地計算浮點和。math.fsum()函數(shù)很少出現(xiàn)近似值問題。

還可以使用math.isclose()函數(shù)比較兩個浮點值是否接近相等:

>>> (19/155)*(155/19) == 1.0
False
>>> math.isclose((19/155)*(155/19), 1)
True

該函數(shù)提供了一種正確比較浮點數(shù)的方法。

Python 還提供了復(fù)數(shù)數(shù)據(jù)類型。復(fù)數(shù)由實部和虛部組成。在Python 中,3.14 + 2.78j 代表復(fù)數(shù) 3.14 + 2.78√-1。Python可以在浮點數(shù)和復(fù)數(shù)之間進行輕松的轉(zhuǎn)換。Python提供了一組常用的復(fù)數(shù)運算符。

為了更好地支持復(fù)數(shù),Python 內(nèi)置了cmath 包。例如,cmath.sqrt()函數(shù)將返回一個復(fù)數(shù)值,而不是在求負數(shù)的平方根時拋出異常。示例如下:

>>> math.sqrt(-2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: math domain error
>>> cmath.sqrt(-2)
1.4142135623730951j

在操作復(fù)數(shù)時,離不開cmath 包。

五、延伸閱讀

請參閱https://en.wikipedia.org/wiki/IEEE_floating_point。

在真除法和floor 除法之間選擇

Python 提供了兩種除法運算符。本實例將介紹這兩種運算符以及它們適用的情景,還將介紹Python 除法規(guī)則以及如何對整數(shù)值進行除法運算。

一、準備工作

除法運算有幾種常見的使用場景。

  • div-mod 對:我們需要兩部分值——商和余數(shù)。當對數(shù)值進行數(shù)制轉(zhuǎn)換時,或者把秒數(shù)轉(zhuǎn)換為小時、分鐘和秒時,會執(zhí)行div-mod 除法。我們不想要確切的小時數(shù),只是想要一個截斷的小時數(shù),余數(shù)轉(zhuǎn)換為分鐘和秒。
  • 真實(true)值:典型的浮點值——商的良好近似值。例如,如果計算一些測量數(shù)據(jù)的平均值,那么我們通常希望結(jié)果是浮點值,即使輸入值都是整數(shù)。
  • 合理的分數(shù)值:當我們使用英尺、英寸和杯等美國單位時,常常需要這種值。為此,應(yīng)當使用Fraction 類。當使用Fraction 對象時,總是得到確切的答案。

我們首先需要確定適用哪種情況,然后就知道該使用哪種除法運算符了。

二、實戰(zhàn)演練

我們將分別討論這三種情況。首先討論截斷的floor 除法,然后討論真正的浮點除法,最后討論分數(shù)的除法。

1. floor 除法

在做div-mod 類計算時,可以使用floor 除法運算符(//)和取模運算符(%)?;蛘咭部梢允褂胐ivmod()函數(shù)。

(1) 將秒數(shù)除以3600 得到小時數(shù),模數(shù)或余數(shù)可以分別轉(zhuǎn)換為分鐘數(shù)和秒數(shù)。

>>> total_seconds = 7385
>>> hours = total_seconds//3600
>>> remaining_seconds = total_seconds % 3600

(2) 將步驟(1)剩余的秒數(shù)除以60 得到分鐘數(shù),余數(shù)是小于60 的秒數(shù)。

>>> minutes = remaining_seconds//60
>>> seconds = remaining_seconds % 60
>>> hours, minutes, seconds
(2, 3, 5)

使用divmod()函數(shù)的示例如下。

(1) 同時計算商和余數(shù)。

>>> total_seconds = 7385
>>> hours, remaining_seconds = divmod(total_seconds, 3600)

(2) 再次計算商和余數(shù)。

>>> minutes, seconds = divmod(remaining_seconds, 60)
>>> hours, minutes, seconds
(2, 3, 5)

2. 真除法

真值除法計算的結(jié)果是浮點近似值。例如,7386 秒是多少小時?使用真除法運算符進行除法運算:

>>> total_seconds = 7385
>>> hours = total_seconds / 3600
>>> round(hours, 4)
2.0514

我們提供了兩個整數(shù)值,但得到了一個精確的浮點數(shù)結(jié)果。與以前使用浮點值的實例相一致,我們?nèi)≌私Y(jié)果,以避免出現(xiàn)微小的誤差值。

這種真除法是Python 3 的特性。

3. 有理分數(shù)計算

可以用Fraction 對象和整數(shù)做除法。這將使結(jié)果是一個數(shù)學(xué)上精確的有理數(shù)。

(1) 創(chuàng)建至少一個Fraction 值。

>>> from fractions import Fraction
>>> total_seconds = Fraction(7385)

(2) 在計算中使用Fraction 值,任何整數(shù)都將被提升到分數(shù)。

>>> hours = total_seconds / 3600
>>> hours
Fraction(1477, 720)

(3) 如有必要,將確切分數(shù)轉(zhuǎn)換為浮點近似值。

>>> round(float(hours),4)
2.0514

我們首先為總秒數(shù)創(chuàng)建了一個Fraction 對象。在對分數(shù)做算術(shù)運算時,Python 會把所有整數(shù)都轉(zhuǎn)換為分數(shù),這種轉(zhuǎn)換意味著數(shù)學(xué)運算是盡可能精確地完成的。

三、工作原理

Python 3 有兩個除法運算符。

  • 真除法運算符/總是試圖產(chǎn)生一個浮點數(shù)結(jié)果,即使這兩個操作數(shù)是整數(shù)。從這個角度來看,真除法運算符是一個不尋常的運算符。其他所有運算符都試圖保留數(shù)據(jù)的類型。當應(yīng)用于整數(shù)時,真除法運算會產(chǎn)生浮點數(shù)結(jié)果。
  • 截斷除法運算符//總是試圖產(chǎn)生截斷的結(jié)果。對于兩個整數(shù)操作數(shù),結(jié)果是截斷商。對于兩個浮點數(shù)操作數(shù),結(jié)果是一個截斷的浮點數(shù)結(jié)果。
>>> 7358.0 // 3600.0
2.0

默認情況下,Python 2 只有一個除法運算符。對于仍在使用Python 2 的程序員來說,可以通過以下方法使用這些新運算符:

>>> from __future__ import division

這個導(dǎo)入將會引入Python 3 的除法規(guī)則。

五、延伸閱讀

請參閱https://www.python.org/dev/peps/pep-0238/。

——本文節(jié)選自《Python經(jīng)典實例》

解決實際場景中的具體問題,全面了解Python語言特性

本書是Python經(jīng)典實例解析,采用基于實例的方法編寫,每個實例都會解決具體的問題和難題。主要內(nèi)容有:數(shù)字、字符串和元組,語句與語法,函數(shù)定義,列表、集、字典,用戶輸入和輸出等內(nèi)置數(shù)據(jù)結(jié)構(gòu),類和對象,函數(shù)式和反應(yīng)式編程,Web服務(wù),等等。

Python 是全球的開發(fā)人員、工程師、數(shù)據(jù)科學(xué)家和編程愛好者的首選語言。它是杰出的腳本語言,可以為你的應(yīng)用程序注入動力,提供出色的速度、安全性和可擴展性。本書會通過一些簡單的實例剖析Python,你可以在特定的情境中深入了解其具體的語言特性。明確的情境有助于理解語言或標準庫的特性。

本書采用基于實例的方法編寫,每個實例都會解決具體的問題和難題。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
淺談Python內(nèi)置對象類型——數(shù)字篇(附py2和py3的區(qū)別之一)
python中/和//有什么不同?
Python中分數(shù)的相關(guān)使用教程
Python基礎(chǔ)知識點:類型和運算
Python中的 // 與 / 的區(qū)別
Python基礎(chǔ)知識④:數(shù)字類型、數(shù)字運算
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服