2014-10-22 15 views
17

Tôi đã đoạn mã sau, mà là làm cho tôi gãi đầu của tôi -Tại sao đối tượng của tôi bị xóa khỏi danh sách khi __eq__ không được gọi?

class Element: 
    def __init__(self, name): 
     self.name = name 

    def __repr__(self): 
     return self.name 

def eq(self, other): 
    print('comparing {} to {} ({})'.format(self.name, 
     other.name, 
     self.name == other.name)) 

    return self.name == other.name 

Element.__eq__ = eq 
elements = [ 
    Element('a'), 
    Element('b'), 
    Element('c'), 
    Element('d')  
] 

print('before {}'.format(elements)) 
elements.remove(elements[3]) 
print('after {}'.format(elements)) 

nào mang lại kết quả như sau -

before [a, b, c, d] 
comparing a to d (False) 
comparing b to d (False) 
comparing c to d (False) 
after [a, b, c] 

Tại sao không eq() xuất ra comparing d to d (True)?

Lý do tôi khỉ vá __eq__ thay vì chỉ đơn giản là thực hiện nó trong lớp Element của tôi là vì tôi đang thử nghiệm cách khỉ vá làm việc trước khi tôi thực hiện nó với một trong những thư viện Tôi đang sử dụng.

Trả lời

16

Yếu tố thứ tư là đối tượng chính xác giống với đối tượng mà mã đang chuyển (elements[3]).

Nói một cách khác,

>>> elements[3] is elements[3] 
True 
>>> elements[3] == elements[3] 
True 

Vì vậy, không cần phải kiểm tra sự bình đẳng vì họ (?) Là giống hệt nhau (cùng) một.

Kiểm tra bình đẳng sẽ xảy ra nếu chúng không giống nhau. Ví dụ, __eq__ sẽ được gọi nếu mã đi một đối tượng khác với giá trị tương tự:

elements.remove(Element('d')) 
+0

Cảm ơn bạn. Câu trả lời rất rõ ràng. –

9

list.remove() phương pháp kiểm tra đầu tiên của Python cho dù các đối tượng cả hai đều giống hệt nhau khác rơi trở lại với các phương pháp so sánh thường xuyên như __eq__ trong trường hợp này. Vì vậy, trong trường hợp này là cả hai đối tượng giống hệt nhau, nó được loại bỏ khỏi danh sách.

listremove(PyListObject *self, PyObject *v) 
{ 
    Py_ssize_t i; 

    for (i = 0; i < Py_SIZE(self); i++) { 
     int cmp = PyObject_RichCompareBool(self->ob_item[i], v, Py_EQ); 
     ... 

Đây PyObject_RichCompareBool(PyObject *o1, PyObject *o2, int opid) đang được sử dụng để so sánh, và từ tài liệu của nó:

Nếu o1o2 là cùng một đối tượng, PyObject_RichCompareBool() sẽ luôn luôn trả 1 cho Py_EQ0 cho Py_NE.

+0

Cảm ơn bạn đã đăng một đoạn mã nguồn thực thi thực tế của Python. Tôi thực sự nên tìm hiểu để xem xét câu trả lời của tôi. –

Các vấn đề liên quan