Sets thử nghiệm cho bình đẳng, và cho đến khi có phiên bản Python mới, thứ tự mà họ làm điều này có thể khác nhau dựa trên biểu mẫu, bạn trao các giá trị cho tập hợp đang được xây dựng, như tôi sẽ hiển thị bên dưới.
Kể từ 0 == x
là đúng và0 == y
là đúng, nhưng x == y
là sai, hành vi ở đây thực sự là không xác định, như các thiết lập giả định rằng x == y
phải đúng nếu hai bài kiểm tra đầu tiên là đúng quá.
Nếu bạn đảo ngược danh sách truyền cho set()
, sau đó bạn sẽ có được kết quả tương tự như sử dụng một chữ, vì thứ tự của sự bình đẳng kiểm tra những thay đổi:
>>> set([y, x, 0])
set([0j, Decimal('0')])
và tương tự cho đảo ngược nghĩa đen:
>>> {y, x, 0}
set([0])
Điều đang xảy ra là thiết lập chữ tải các giá trị vào ngăn xếp và sau đó giá trị ngăn xếp được thêm vào đối tượng bộ mới theo thứ tự ngược lại.
Miễn là 0
được tải trước tiên, hai đối tượng kia sau đó được thử nghiệm với 0
đã có trong bộ này. Khoảnh khắc một trong hai đối tượng khác được nạp đầu tiên, kiểm tra bình đẳng không và bạn nhận được hai đối tượng nói thêm:
>>> {y, 0, x}
set([Decimal('0'), 0j])
>>> {x, 0, y}
set([0j, Decimal('0')])
Điều đó đặt literals thêm các yếu tố ngược lại là một món quà lỗi trong tất cả các phiên bản của Python có hỗ trợ cú pháp , cho đến tận Python 2.7.12 và 3.5.2. Gần đây nó đã được sửa, xem issue 26020 (một phần của 2.7.13, 3.5.3 và 3.6, chưa có bản nào được phát hành). Nếu bạn nhìn vào 2.7.12, bạn có thể thấy rằng BUILD_SET
in ceval.c
đọc ngăn xếp từ trên xuống dưới:
# oparg is the number of elements to take from the stack to add
for (; --oparg >= 0;) {
w = POP();
if (err == 0)
err = PySet_Add(x, w);
Py_DECREF(w);
}
trong khi bytecode thêm yếu tố để ngăn xếp theo thứ tự ngược (đẩy 0
trên stack đầu tiên):
>>> from dis import dis
>>> dis(compile('{0, x, y}', '', 'eval'))
2 0 LOAD_CONST 1 (0)
3 LOAD_GLOBAL 0 (x)
6 LOAD_GLOBAL 1 (y)
9 BUILD_SET 3
12 RETURN_VALUE
Khắc phục là đọc các phần tử từ ngăn xếp theo thứ tự ngược lại; các Python 2.7.13 version sử dụng PEEK()
thay vì POP()
(và một STACKADJ()
để loại bỏ các yếu tố từ ngăn xếp sau):
for (i = oparg; i > 0; i--) {
w = PEEK(i);
if (err == 0)
err = PySet_Add(x, w);
Py_DECREF(w);
}
STACKADJ(-oparg);
Vấn đề kiểm tra bình đẳng có nguyên nhân gốc rễ giống như câu hỏi khác; lớp Decimal()
có một số vấn đề bình đẳng với complex
ở đây, được sửa trong Python 3.2 (bằng cách thực hiện Decimal()
support comparisons to complex
and a few other numeric types it didn't support before).
liên quan: [Dict/Set Parsing thứ tự nhất quán] (https://stackoverflow.com/q/34623846/4279) – jfs