數字日期和時間
數字的四舍五入
問題:
你想對浮點數執行指定精度的舍入運算。
解決方法:
對於簡單的舍入運算,使用內置的round(value, ndigits) 函數即可。比如:
1 #保留小數點後1位數,因為比1.25小,所以四舍五入,取小的 2 r1 = round(1.23, 1) 3 print(r1) 4 5 #保留小數點後1位數,因為比1.25大,所以四舍五入,所以取大的 6 r2 = round(1.27, 1) 7 print(r2) 8 9 #保留小數點後1位數,因為比-1.25小,所以四舍五入,所以取小的 10 r3 = round(-1.27, 1) 11print(r3) 12 13 #保留小數點後3位數,因為比1.253大,所以四舍五入,所以取大的 14 r4 = round(1.25361, 3) 15 print(r4)
以上代碼執行的結果為:
1.2 1.3 -1.3 1.254
執行精確的浮點數運算
問題:
你需要對浮點數執行精確的計算操作,並且不希望有任何小誤差的出現。
解決方案:
浮點數的一個普遍問題是它們並不能精確的表示十進制數。並且,即使是最簡單的數學運算也會產生小的誤差,比如:
1 a = 4.2 2 b = 2.1 3 c = a + b 4 5 if c == 6.3: 6 print(‘True‘) 7 else: 8 print(‘False‘) 9 print(c) 10 11 #解決方案,如果你想更加精確(並能容忍一定的性能損耗),你可以使用decimal 模塊 12 print(‘*‘*30) 13 from decimal import Decimal 14 a = Decimal(‘4.2‘) 15 b = Decimal(‘2.1‘) 16 c = a + b 17 print(c)
以上代碼運行的結果為:
False
6.300000000000001
******************************
6.3
即便如此,你卻不能完全忽略誤差。數學家花了大量時間去研究各類算法,有些處理誤差會比其他方法更好。你也得註意下減法刪除已經大數和小數的加分運算所帶來的影響。比如:
1 nums = [1.23e+18, 1, -1.23e+18] 2 #返回的結果是0.0,是錯誤的結果 3 print(‘錯誤的結果為:‘, sum(nums)) 4 5 #解決上面的問題辦法 6 import math 7 print(‘正確的結果為:‘, math.fsum(nums))
以上代碼運行的結果為:
錯誤的結果為: 0.0
正確的結果為: 1.0
總結:
總的來說, decimal 模塊主要用在涉及到金融的領域。在這類程序中,哪怕是一點小小的誤差在計算過程中蔓延都是不允許的。因此, decimal 模塊為解決這類問題提供了方法。當Python 和數據庫打交道的時候也通常會遇到Decimal 對象,並且,通常也是在處理金融數據的時。
數字的格式化輸出
問題:
你需要將數字格式化後輸出,並控制數字的位數、對齊、千位分隔符和其他的細節。
解決方案:
格式化輸出單個數字的時候,可以使用內置的format() 函數,比如:
1 x = 1234.56789 2 print(format(x, ‘0.2f‘)) 3 4 #右對齊10個字符並保留小數點後一位 5 print("右對齊十個字符:", format(x, ‘>10.1f‘)) 6 7 #左對齊10個字符並保留小數點後一位 8 print("左對齊十個字符:", format(x, ‘<10.1f‘) + ‘!‘) 9 10 #居中對齊 11 print("居中對齊十個字符:", format(x, ‘^10.1f‘)) 12 13 #分離器,分離千萬 14 print("分離的格式:", format(x, ‘,‘)) 15 16 print(format(x, ‘0,.1f‘))
以上代碼運行的結果為:
1234.57 右對齊十個字符: 1234.6 左對齊十個字符: 1234.6 ! 居中對齊十個字符: 1234.6 分離的格式: 1,234.56789 1,234.6
二八十六進制整數
問題:
你需要轉換或者輸出使用二進制,八進制或十六進制表示的整數。
解決方案:
為了將整數轉換為二進制、八進制或十六進制的文本串,可以分別使用bin() ,oct() 或hex() 函數:
1 x = 1234 2 3 #二進制格式的 4 print(bin(x)) 5 6 #八進制格式的 7 print(oct(x)) 8 9 #十六進制格式的 10 print(hex(x)) 11 12 #如果你不想輸出0b , 0o 或者0x 的前綴的話,可以使用format() 函數 13 print(format(x, ‘b‘)) 14 print(format(x, ‘o‘)) 15 print(format(x, ‘x‘))
以上代碼運行的結果為:
0b10011010010 0o2322 0x4d2 10011010010 2322 4d2
字節到大整數的打包與解包
問題:
你有一個字節字符串並想將它解壓成一個整數。或者,你需要將一個大整數轉換為一個字節字符串。
解決方案:
假設你的程序需要處理一個擁有128 位長的16 個元素的字節字符串。比如:
1 data = b‘\x00\x124V\x00x\x90\xab\x00\xcd\xef\x01\x00#\x004‘ 2 3 print(‘data的長度為:‘, len(data)) 4 5 r1 = int.from_bytes(data, ‘little‘) 6 print(r1) 7 8 r2 = int.from_bytes(data, ‘big‘) 9 print(r2) 10 11 #為了將一個大整數轉換為一個字節字符串,使用int.to bytes() 方法,並像下面這樣指定字節數和字節順序 12 x = 94522842520747284487117727783387188 13 r3 = x.to_bytes(16, ‘big‘) 14 print(r3) 15 16 r4 = x.to_bytes(16, ‘little‘) 17 print(r4)
以上代碼運行的結果為:
data的長度為: 16 69120565665751139577663547927094891008 94522842520747284487117727783387188 b‘\x00\x124V\x00x\x90\xab\x00\xcd\xef\x01\x00#\x004‘ b‘4\x00#\x00\x01\xef\xcd\x00\xab\x90x\x00V4\x12\x00‘
分數運算
問題:
你進入時間機器,突然發現你正在做小學家庭作業,並涉及到分數計算問題。或者你可能需要寫代碼去計算在你的木工工廠中的測量值。
解決方案:
fractions 模塊可以被用來執行包含分數的數學運算。比如:
1 from fractions import Fraction 2 3 #除法 等同於5/4 7/16 4 a = Fraction(5, 4) 5 b = Fraction(7, 16) 6 7 r1 = a * b 8 print(a + b) 9 print(a * b) 10 11 #被除數 12 r = a * b 13 print(r.numerator) 14 15 #除數 16 print(r.denominator) 17 18 #結果 19 print(float(r))
以上代碼運行的結果為:
27/16 35/64 35 64 0.546875
大型數組運算
問題:
你需要在大數據集(比如數組或網格) 上面執行計算
解決方案:
涉及到數組的重量級運算操作,可以使用NumPy 庫。NumPy 的一個主要特征是它會給Python 提供一個數組對象,相比標準的Python 列表而已更適合用來做數學運算。下面是一個簡單的小例子,向你展示標準列表對象和NumPy 數組對象之間的差別:
1 x = [1, 2 ,3 , 4, 5] 2 y = [6, 7, 8, 9, 10] 3 4 #x列表的乘以2的效果 5 print("x*2:", x * 2) 6 7 #做列表拼接 8 print(‘x+y:‘, x + y) 9 10 import numpy as np 11 # print("數組".center(40, "*")) 12 print(‘{:*^40}‘.format(‘數組‘)) 13 14 ax = np.array([1, 2, 3, 4]) 15 ay = np.array([5, 6, 7, 8]) 16 17 #數組的每個元素都乘以2 18 print(‘ax*2 :‘, ax * 2) 19 print(‘ax+10:‘, ax + 10) 20 print(‘ax+ay:‘, ax + ay) 21 print(‘ax*ay:‘, ax * ay)
以上代碼運行的結果為:
x*2: [1, 2, 3, 4, 5, 1, 2, 3, 4, 5] x+y: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] *******************數組******************* ax*2 : [2 4 6 8] ax+10: [11 12 13 14] ax+ay: [ 6 8 10 12] ax*ay: [ 5 12 21 32]
總結:
正如所見,兩種方案中數組的基本數學運算結果並不相同。特別的, NumPy 中的標量運算(比如ax * 2 或ax + 10 ) 會作用在每一個元素上。另外,當兩個操作數都是數組的時候執行元素對等位置計算,並最終生成一個新的數組。
矩陣與線性代數運算
問題:
你需要執行矩陣和線性代數運算,比如矩陣乘法、尋找行列式、求解線性方程組等等。
解決方案:
NumPy 庫有一個矩陣對象可以用來解決這個問題。
1 import numpy as np 2 3 m = np.matrix([[1, -2, 3], [0, 4, 5], [7, 8, 9]]) 4 5 print(m.T) 6 print(‘‘.center(40, ‘*‘)) 7 8 print(m.I) 9 print(‘‘.center(40, ‘-‘)) 10 11 v = np.matrix([[2], [3], [4]]) 12 print(v) 13 14 print(‘‘.center(40, ‘~‘)) 15 print(m * v)
以上代碼運行的結果為:
[[ 1 0 7] [-2 4 8] [ 3 5 9]] **************************************** [[ 0.02531646 -0.26582278 0.13924051] [-0.22151899 0.07594937 0.03164557] [ 0.17721519 0.13924051 -0.02531646]] ---------------------------------------- [[2] [3] [4]] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [[ 8] [32] [74]]
隨機選擇
問題:
你想從一個序列中隨機抽取若幹元素,或者想生成幾個隨機數。
解決方案:
random 模塊有大量的函數用來產生隨機數和隨機選擇元素。比如,要想從一個序列中隨機的抽取一個元素,可以使用random.choice() :
1 import random 2 3 values = list(range(10)) 4 5 #從values中提取單個元素 6 print(‘提取單個元素‘.center(15, ‘*‘)) 7 print(random.choice(values)) 8 print(random.choice(values)) 9 print(random.choice(values)) 10 print(random.choice(values)) 11 12 #從values中提取N個不同的元素 13 print(‘提取N個元素‘.center(15, ‘*‘)) 14 print(random.sample(values, 3)) 15 print(random.sample(values, 3)) 16 print(random.sample(values, 3)) 17 18 print(‘打亂values的元素順序‘.center(15, ‘*‘)) 19 print(‘打亂之前的values:‘, values) 20 random.shuffle(values) 21 print("打亂以後的values:", values)
以上代碼運行的結果為:
*****提取單個元素**** 1 2 7 0 *****提取N個元素**** [3, 5, 0] [4, 8, 2] [4, 9, 3] *打亂values的元素順序* 打亂之前的values: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 打亂以後的values: [1, 8, 7, 2, 9, 5, 3, 4, 0, 6]
基本的日期與時間轉換
問題:
你需要執行簡單的時間轉換,比如天到秒,小時到分鐘等的轉換。
解決方案:
為了執行不同時間單位的轉換和計算,請使用datetime 模塊。比如,為了表示一個時間段,可以創建一個timedelta 實例,就像下面這樣:
1 from datetime import timedelta, datetime 2 3 a = timedelta(days=2, hours=6) 4 b = timedelta(hours=4.5) 5 c = a + b 6 7 print(‘biubiu天~:‘, c.days) 8 9 print(‘biubiu秒~:‘, c.seconds) 10 11 print(‘小時:‘, c.seconds / 3600) 12 13 print(‘總共經過多少小時:‘, c.total_seconds() / 3600) 14 15 a1 = datetime(2017, 8, 3) 16 #在當前時間上加10天 17 print(a1 + timedelta(days=10)) 18 19 b1 = datetime(2017, 12, 21) 20 c1 = b1 - a1 21 #兩個時間點相差多少天 22 print(c1) 23 24 print(c1.days) 25 26 print(‘當前時間‘.center(30, ‘*‘)) 27 now = datetime.today() 28 print(now) 29 30 print(‘當前時間往後推8個小時‘.center(26,"*")) 31 print(now + timedelta(hours=8)) 32 33 print(‘當前時間往後推30分鐘‘.center(27, ‘*‘)) 34 print(now + timedelta(minutes=30))
以上代碼運行的結果為:
biubiu天~: 2 biubiu秒~: 37800 小時: 10.5 總共經過多少小時: 58.5 2017-08-13 00:00:00 140 days, 0:00:00 140 *************當前時間************* 2017-08-03 14:42:28.002825 *******當前時間往後推8個小時******** 2017-08-03 22:42:28.002825 ********當前時間往後推30分鐘******** 2017-08-03 15:12:28.002825
計算最後一個周五的日期
問題:
你需要查找星期中某一天最後出現的日期,比如星期五。
解決方案:
Python 的datetime 模塊中有工具函數和類可以幫助你執行這樣的計算。下面是對類似這樣的問題的一個通用解決方案:
1 from datetime import datetime, timedelta 2 3 weekdays = [‘Monday‘, ‘Tuesday‘, ‘Wednesday‘, ‘Thursday‘, 4 ‘Friday‘, ‘Saturday‘, ‘Sunday‘] 5 6 def get_previous_byday(dayname, start_date=None): 7 if start_date is None: 8 start_date = datetime.today() 9 day_num = start_date.weekday() 10 day_num_target = weekdays.index(dayname) 11 days_ago = (7 + day_num - day_num_target) % 7 12 if days_ago == 0: 13 days_ago = 7 14 target_date = start_date - timedelta(days=days_ago) 15 return target_date 16 17 18 print(get_previous_byday(‘Monday‘)) 19 print(get_previous_byday(‘Tuesday‘)) 20 print(get_previous_byday(‘Friday‘)) 21 get_previous_byday(‘Sunday‘, datetime(2017, 12, 21))
以上代碼運行的結果為:
2017-07-31 14:58:38.092831 2017-08-01 14:58:38.092945 2017-07-28 14:58:38.092975 2017-12-24 00:00:00
上面的算法原理是這樣的:先將開始日期和目標日期映射到星期數組的位置上(星期一索引為0),然後通過模運算計算出目標日期要經過多少天才能到達開始日期。然後用開始日期減去那個時間差即得到結果日期
計算當前月份的日期範圍
問題:
你的代碼需要在當前月份中循環每一天,想找到一個計算這個日期範圍的高效方法
解決方案:
在這樣的日期上循環並需要事先構造一個包含所有日期的列表。你可以先計算出開始日期和結束日期,然後在你步進的時候使用datetime.timedelta 對象遞增這個日期變量即可
1 from datetime import datetime, date , timedelta 2 import calendar 3 4 def get_month_range(start_date=None): 5 if start_date is None: 6 start_date = date.today().replace(day=1) 7 _, days_in_month = calendar.monthrange(start_date.year, start_date.month) 8 end_date = start_date + timedelta(days=days_in_month) 9 return (start_date, end_date) 10 11 a_day = timedelta(days=1) 12 first_day, last_day = get_month_range() 13 14 while first_day < last_day: 15 print(first_day) 16 first_day += a_day
以上代碼運行的結果為:
017-08-01
2017-08-02
2017-08-03
2017-08-04
2017-08-05
2017-08-06
2017-08-07
2017-08-08
................
結合時區的日期操作
問題:
你有一個安排在2012 年12 月21 日早上9:30 的電話會議,地點在芝加哥。而你的朋友在印度的班加羅爾,那麽他應該在當地時間幾點參加這個會議呢?
解決方案:
對幾乎所有涉及到時區的問題,你都應該使用pytz 模塊。這個包提供了Olson 時區數據庫,它是時區信息的事實上的標準,在很多語言和操作系統裏面都可以找到
1 from datetime import datetime 2 from pytz import timezone, utc 3 4 #初始化時間 5 d = datetime(2017, 8, 3, 11, 20, 38) 6 print("本地時間:", d) 7 8 #轉換成芝加哥時間 9 central = timezone("US/Central") 10 loc_d = central.localize(d) 11 print("芝加哥的時間:", loc_d) 12 13 #班加羅爾的時間 pytz.utc是utc時間,asctimezone中可以替換成這個 14 bang_d = loc_d.astimezone(timezone(‘Asia/Kolkata‘)) 15 #bang_d = loc_d.astimezone(utc) 16 print("班加羅爾的時間:", bang_d)
以上代碼運行的結果為:
本地時間: 2017-08-03 11:20:38 芝加哥的時間: 2017-08-03 11:20:38-05:00 班加羅爾的時間: 2017-08-03 21:50:38+05:30
數字日期和時間