是否將第一個串列的每個元素與第二個串列的具有相同索引的元素進行比較,還是有另一種更棘手的方法?
uj5u.com熱心網友回復:
截至我撰寫此答案時,串列比較的 CPython3 實作位于第 2752 行。
您還可以查看Python/C API 參考手冊。
我實作了一個簡單的類,當呼叫一些用于比較的魔術方法時列印一條訊息(例如__eq__,當您使用==運算子時呼叫的方法)。該類僅包含您在建構式中傳遞的值。比較Value物件時,會比較它們的值。希望這能讓您更好地了解正在發生的事情。
def show_call(func):
def wrapper(*args, **kwargs):
if kwargs:
raise NotImplemented()
print(f"{func.__qualname__}({', '.join(map(str, args))})")
return func(*args)
return wrapper
class Value:
def __init__(self, value):
self.value = value
def __repr__(self):
return f"Value({self.value})"
@show_call
def __eq__(self, other):
return self.value == other.value
@show_call
def __lt__(self, other):
return self.value < other.value
@show_call
def __gt__(self, other):
return self.value > other.value
@show_call
def __le__(self, other):
return self.value <= other.value
@show_call
def __ge__(self, other):
return self.value >= other.value
讓我們先看看當你比較兩個不同長度的串列的相等性時發生了什么。我們運行以下代碼:
ls1 = [Value(1), Value(2)]
ls2 = [Value(1), Value(2), Value(3)]
print(f"{ls1} == {ls2}")
ls1 == ls2;
這給出了以下輸出:
[Value(1), Value(2)] == [Value(1), Value(2), Value(3)]
我們可以看到沒有呼叫該__eq__方法。這是有道理的,因為兩個不同長度的串列被認為是不相等的。無需比較串列中的任何專案。在 CPython 中,這被實作為
if (Py_SIZE(vl) != Py_SIZE(wl) && (op == Py_EQ || op == Py_NE)) { /* Shortcut: if the lengths differ, the lists differ */ if (op == Py_EQ) Py_RETURN_FALSE; else Py_RETURN_TRUE; }
然后CPython源代碼說
Search for the first index where items are different
我們在相同長度的串列上運行相等測驗:
ls3 = [Value(1), Value(2)]
print(f"{ls1} == {ls3}")
ls1 == ls3;
ls4 = [Value(2), Value(2)]
print(f"{ls1} == {ls2}")
ls1 == ls4;
輸出如下:
[Value(1), Value(2)] == [Value(1), Value(2)]
Value.__eq__(Value(1), Value(1))
Value.__eq__(Value(2), Value(2))
[Value(1), Value(2)] == [Value(2), Value(2)]
Value.__eq__(Value(1), Value(2))
我們可以看到確實首先比較索引 0 處的專案,然后是后續專案。它在以下情況下停止:
- 它遇到兩個串列中的專案不相等的第一個索引;或者
- 任一串列都已用盡。
如果任一串列已用盡,我們可以回傳兩個串列長度之間的比較。
在這個階段,我們已經可以確定!=串列的等式或不等式 ( ),因為我們已經找到了第一個不同的元素。
對于小于、大于、小于或等于和大于或等于(lt、gt、le 和 ge)測驗,該程序都是相同的。第一個不同專案的索引被制作出來。如果任一串列已用盡,則比較它們的長度。唯一的區別是它與適當的魔術方法進行了最后一次比較。
以下代碼
ls5 = [Value(1), Value(3)]
print(f"{ls1} > {ls5}")
ls1 > ls5;
輸出:
[Value(1), Value(2)] > [Value(1), Value(3)]
Value.__eq__(Value(1), Value(1))
Value.__eq__(Value(2), Value(3))
Value.__gt__(Value(2), Value(3))
對于 lt、gt、le 和 ge,最后一次呼叫適當的比較函式。
此外,正如一些評論中提到的,身份測驗首先用于串列項相等性測驗。正如您在以下示例中看到的,
ls6 = [ls1[0], Value(2)]
print(f"{ls1} == {ls6}")
ls1 == ls6;
輸出:
// ls1 ids [140401841947936, 140401277199120]
// ls6 ids [140401841947936, 140401005879200]
[Value(1), Value(2)] == [Value(1), Value(2)]
Value.__eq__(Value(2), Value(2))
兩個串列中的第一項是相同的(即它們在 C 中參考相同的物件,id在 Python 中具有相同的物件)。因此,無需呼叫該__eq__函式來測驗是否相等。從源代碼注釋中,
物件相同時的快速結果。保證身份意味著平等。
有些東西已經在這里介紹了,直到我寫完我的答案才意識到。
uj5u.com熱心網友回復:
來自檔案,常見序列操作:
元組和串列通過比較相應的元素按字典順序進行比較。這意味著要比較相等,每個元素必須比較相等,并且兩個序列必須是相同的型別并且具有相同的長度。(有關詳細資訊,請參閱語言參考中的比較。)
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/485819.html
下一篇:如何在標記擴展中定義陣列的項?
