小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

你不知道的Python特性,其實(shí)可以解決很多問(wèn)題!

 靜幻堂 2019-04-10
圖靈教育 2019-04-09 15:22:39
你不知道的Python特性,其實(shí)可以解決很多問(wèn)題!

本文會(huì)通過(guò)一些實(shí)例來(lái)介紹Python 的一些特性,每個(gè)實(shí)例都會(huì)解決具體的問(wèn)題和難題。

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

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

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

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

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

一、準(zhǔn)備工作

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

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

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

二、實(shí)戰(zhàn)演練

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

1. 明智地選擇名稱

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

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

選擇名稱的步驟如下。

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

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

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

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

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

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

然后可以用修飾語(yǔ)來(lái)限定這些名稱:

FinalStatusDocument

ReceivedInventoryItemName

第一個(gè)示例是Document 類,我們通過(guò)添加一個(gè)前綴對(duì)其進(jìn)行了略微的限定,即StatusDocument,又通過(guò)將其命名為FinalStatusDocument 來(lái)進(jìn)一步限定。 第二個(gè)示例是Name 類,我們通過(guò)詳細(xì)說(shuō)明它是一個(gè)ReceivedInventoryItemName 來(lái)對(duì)其進(jìn)行限定。該示例需要一個(gè)4 個(gè)級(jí)別的名稱來(lái)闡明。

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

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

measured_height_value

estimated_weight_value

scheduled_delivery_date

location_code

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

需要避免的情況

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

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

2. 為對(duì)象分配名稱

Python 沒(méi)有使用靜態(tài)變量定義。當(dāng)把名稱分配給對(duì)象時(shí),就會(huì)創(chuàng)建變量。把對(duì)象看作處理過(guò)程的核心非常重要,變量有點(diǎn)像標(biāo)識(shí)對(duì)象的標(biāo)簽。使用基本賦值語(yǔ)句的方法如下。

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

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

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

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

上面的基本賦值語(yǔ)句并不是唯一的賦值方式,還可以使用鏈?zhǔn)劫x值的方式,將一個(gè)對(duì)象分配給多個(gè)變量,例如:

>>> target_color_name = first_color_name = 'FireBrick'

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

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

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

相等測(cè)試使用==,簡(jiǎn)單賦值使用=。

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

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

我們通過(guò)運(yùn)算符進(jìn)行了增量賦值。total_count + = 5 與total_count = total_count + 5是等價(jià)的。增量賦值的優(yōu)點(diǎn)在于簡(jiǎn)化了表達(dá)式。

三、工作原理

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

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

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

賦值語(yǔ)句是為對(duì)象命名的唯一途徑。

四、補(bǔ)充內(nèi)容

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

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

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

五、延伸閱讀

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

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

>>> import this

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

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

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

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

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

一、準(zhǔn)備工作

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

二、實(shí)戰(zhàn)演練

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

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

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

>>> 2
2

或者使用十六進(jìn)制:

>>> 0xff
255

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

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

嚴(yán)格說(shuō)來(lái),這不是一個(gè)整數(shù)。它有一個(gè)前綴b',這表明它是一個(gè)一字節(jié)序列(1-byte sequence)。

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

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

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

三、工作原理

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

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

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

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

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

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

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

通過(guò)下面的示例可以了解整數(shù)內(nèi)部的一些細(xì)節(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ù)中的最大值。我們通過(guò)計(jì)算以2 為底的對(duì)數(shù)來(lái)說(shuō)明這個(gè)數(shù)字需要多

少位。

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

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

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

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

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

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

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

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

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

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

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

四、補(bǔ)充知識(shí)

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

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

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

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

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

先使用0b0011 和0b0101 作為兩個(gè)位串。這有助于準(zhǔn)確說(shuō)明數(shù)字的二進(jìn)制表示。然后將異或(^)運(yùn)算符應(yīng)用于這兩個(gè)位序列。最后使用bin()函數(shù)查看位串形式的結(jié)果??梢酝ㄟ^(guò)結(jié)果仔細(xì)觀察各個(gè)位,了解操作符的實(shí)際功能。

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

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

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

五、延伸閱讀

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

在浮點(diǎn)數(shù)、小數(shù)和分?jǐn)?shù)之間選擇

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

? 浮點(diǎn)數(shù)

? 小數(shù)

? 分?jǐn)?shù)

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

一、準(zhǔn)備工作

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

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

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

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

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

(3) 無(wú)理數(shù):包括所有其他類型的計(jì)算。必須注意,數(shù)字計(jì)算機(jī)只能逼近這些無(wú)理數(shù),而我們偶爾會(huì)看到近似值的一些奇怪現(xiàn)象。浮點(diǎn)近似值運(yùn)算非???,但有時(shí)會(huì)出現(xiàn)截?cái)鄦?wèn)題。

當(dāng)計(jì)算涉及前兩種數(shù)字時(shí),應(yīng)當(dāng)避免使用浮點(diǎn)數(shù)。

二、實(shí)戰(zhàn)演練

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

1. 貨幣值計(jì)算

在處理貨幣值時(shí),應(yīng)當(dāng)堅(jiān)持使用decimal 模塊。如果使用Python 內(nèi)置的浮點(diǎn)數(shù),將會(huì)遇到數(shù)字的舍入和截?cái)鄦?wèn)題。

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

>>> from decimal import Decimal

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

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

結(jié)果稍微大于$0.21,因?yàn)槲覀冇?jì)算出了小數(shù)位的全部數(shù)字。

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

>>> penny = Decimal('0.01')

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

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

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

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

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

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

2. 分?jǐn)?shù)計(jì)算

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

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

>>> from fractions import Fraction

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

>>> 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)建了第一個(gè)分?jǐn)?shù),從浮點(diǎn)計(jì)算5/8 創(chuàng)建了第二個(gè)分?jǐn)?shù)。因?yàn)榉帜甘? 的冪,所以計(jì)算結(jié)果非常準(zhǔn)確。

25/16——結(jié)果是一個(gè)看起來(lái)很復(fù)雜的分?jǐn)?shù),那么它的最簡(jiǎn)分?jǐn)?shù)是多少呢?

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

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

3. 浮點(diǎn)近似值

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

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

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

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

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

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

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

>>> 1-answer
1.1102230246251565e-16

對(duì)于大多數(shù)浮點(diǎn)誤差,典型值約為10^16。Python 有一些聰明的規(guī)則,有時(shí)通過(guò)自動(dòng)舍入隱藏這個(gè)錯(cuò)誤。但是,對(duì)于本示例,錯(cuò)誤并沒(méi)有隱藏。

這是一個(gè)非常重要的推論。

Tip:不要比較浮點(diǎn)值是否完全相等。

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

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

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

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

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

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

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

在第一個(gè)示例中,我們?cè)谡麛?shù)之間進(jìn)行計(jì)算,創(chuàng)建了一個(gè)具有已知截?cái)鄦?wèn)題的float 值。當(dāng)我們從截?cái)嗟膄loat 值創(chuàng)建一個(gè)Fraction 時(shí),得到的是一些暴露了截?cái)鄦?wèn)題的數(shù)字。

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

三、工作原理

對(duì)于數(shù)字類型,Python 提供了多種運(yùn)算符:+、-、*、/、//、%和**。這些運(yùn)算符用于加法、減法、乘法、真除法、截?cái)喑ā⑷∧:蛢邕\(yùn)算。

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

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

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

>>> 8.066e + 67
8.066e + 67

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

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

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

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

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

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

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

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

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

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

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

為什么要使用浮點(diǎn)數(shù)?原因有兩個(gè)

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

此外,浮點(diǎn)值運(yùn)算非常快。

四、補(bǔ)充知識(shí)

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

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

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

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

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

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

為了更好地支持復(fù)數(shù),Python 內(nèi)置了cmath 包。例如,cmath.sqrt()函數(shù)將返回一個(gè)復(fù)數(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ù)時(shí),離不開(kāi)cmath 包。

五、延伸閱讀

請(qǐng)參閱https://en./wiki/IEEE_floating_point。

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

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

一、準(zhǔn)備工作

除法運(yùn)算有幾種常見(jiàn)的使用場(chǎng)景。

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

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

二、實(shí)戰(zhàn)演練

我們將分別討論這三種情況。首先討論截?cái)嗟膄loor 除法,然后討論真正的浮點(diǎn)除法,最后討論分?jǐn)?shù)的除法。

1. floor 除法

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

(1) 將秒數(shù)除以3600 得到小時(shí)數(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í)計(jì)算商和余數(shù)。

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

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

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

2. 真除法

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

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

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

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

3. 有理分?jǐn)?shù)計(jì)算

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

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

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

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

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

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

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

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

三、工作原理

Python 3 有兩個(gè)除法運(yùn)算符。

  • 真除法運(yùn)算符/總是試圖產(chǎn)生一個(gè)浮點(diǎn)數(shù)結(jié)果,即使這兩個(gè)操作數(shù)是整數(shù)。從這個(gè)角度來(lái)看,真除法運(yùn)算符是一個(gè)不尋常的運(yùn)算符。其他所有運(yùn)算符都試圖保留數(shù)據(jù)的類型。當(dāng)應(yīng)用于整數(shù)時(shí),真除法運(yùn)算會(huì)產(chǎn)生浮點(diǎn)數(shù)結(jié)果。
  • 截?cái)喑ㄟ\(yùn)算符//總是試圖產(chǎn)生截?cái)嗟慕Y(jié)果。對(duì)于兩個(gè)整數(shù)操作數(shù),結(jié)果是截?cái)嗌?。?duì)于兩個(gè)浮點(diǎn)數(shù)操作數(shù),結(jié)果是一個(gè)截?cái)嗟母↑c(diǎn)數(shù)結(jié)果。
>>> 7358.0 // 3600.0
2.0

默認(rèn)情況下,Python 2 只有一個(gè)除法運(yùn)算符。對(duì)于仍在使用Python 2 的程序員來(lái)說(shuō),可以通過(guò)以下方法使用這些新運(yùn)算符:

>>> from __future__ import division

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

五、延伸閱讀

請(qǐng)參閱https://www./dev/peps/pep-0238/。

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

你不知道的Python特性,其實(shí)可以解決很多問(wèn)題!

解決實(shí)際場(chǎng)景中的具體問(wèn)題,全面了解Python語(yǔ)言特性

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

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

本書采用基于實(shí)例的方法編寫,每個(gè)實(shí)例都會(huì)解決具體的問(wèn)題和難題。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多