題目
判斷浮點數的運行結果是否相等:
a = 0.1
b = 0.2
c = 0.3
assert a + b == c
題目解析:
這是由於底層 CPU 和運算標准通過自己的浮點單位去執行算術時的特征決定的。看似有窮的小數, 在計算機的二進制表示里卻是無窮的。
所以在進行高進度浮點運算的時候一定要注意,尤其是自動化測試過程中需要進行斷言非常容易出錯。
題目答案:
斷言失敗,拋出 AssertionError 錯誤。
解決方案:
使用 Decimal 模塊:
from decimal import Decimal
a = 0.1
b = 0.2
c = 0.3
assert Decimal(str(a)) + Decimal(str(b)) == Decimal(str(c))
Decimal() 可以維持浮點數的精度,在金融領域和測試領域等精度要求高的行業有非常大的作用。 但是一定要注意: Decimal() 傳的參數一定要是字符串類型,如果是數據類型會再次丟掉精度。
Decimal(0.1) + Decimal(0.2) == Decimal(0.3) # False
Decimal('0.1') + Decimal('0.2') == Decimal('0.3') # True
二、列表的扁平化和降維
題目
有一個二維列表,降成普通的一維的。比如說檸檬班都會有學員分組,我們想通過分組信息去獲取所有的學員名稱。
groups = [['huahua', 'xiaojian'], ['musen', 'yuze'], ['keyou']]
# 得到結果 ['huahua', 'xiaojian', 'musen', 'yuze', 'keyou']
方法一
最簡單的方式可以通過 for 循環的方式一一提取:
names = []
for group in groups:
for name in group:
names.append(name)
print(names)
方法二
但是在面試的時候可能會加一些限制,比如讓你用一行代碼實現,這個時候就需要對 python 基礎有進一步的理解了,比如說使用 sum 函數:
names = sum(groups, [])
非常簡單就實現了同樣的功能。 sum 函數為什么可以做到呢?先看一個簡單的例子:
a = sum([1,2,3])
得到的結果是 6, 也就是說, sum 函數會把一個列表里面的每個元素相加。但是 sum 函數還可以有第二個參數:開始值,默認為 0 , 所以上述過程其實可以寫成:
a = sum([1,2,3], 0)
# 0 + 1 + 2 + 3
依據同樣的道理,可以對列表進行降維操作:
a = sum([['yuze'], ['is'], ['a']], []) # [] + ['yuze'] + ['is'] + ['a'] # 列表拼接
方法三
通過列表推導式也可以方便的解決:
a = [e for group in groups for e in group]
三、多重繼承
class A:
def run(self):
print("a is running")
class B:
def run(self):
print("b is running")
class C(A, B):
pass
# 會打印什么???
C().run()
多重繼承經常用來出面試題。在這個考題中,C 類的父類 A 和 B 都實現了 run 方法,那在 C 的對象里到底是優先調用哪一個呢?
答案是: a running
菱形問題
class A:
def run(self):
print("a running")
class B(A):
pass
class C(A):
def run(self):
print("C running")
class D(B, C):
pass
# 會打印什么???
D().run()
他們的繼承關系圖可以簡化如下,這個問題又稱為菱形問題或者鑽石問題:
答案是: c running
如果我們不讓 C 類繼承 A 呢?
class A: def run(self): print("a running") class B(A): pass class C: def run(self): print("C running") class D(B, C): pass # 會打印什么??? D().run()
他們的繼承關系圖可以簡化如下,可以簡稱為 v 型問題:
答案會變成 a running
題目解析
具體原因是 python 的繼承會遵循特定的順序,優先級排在前面的,子類會優先使用。怎么快速查看這種繼承順序呢?通過D.__mro__
去查看
比如在 菱形問題上,d 的順序是這樣的:
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
D 排在最前面,如果 D 定義了 run 方法,就會被優先使用,然后是 B, 然后是C, 然后是 A, 最后是 object 基類。
而在 V 行問題上,d 的順序又變成了這樣:
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.C'>, <class 'object'>)
A 和 C 互換了順序。造成 2 個題目的答案不一致。