2010-04-07 2 views
10

Tôi đang cố gắng tạo một đối tượng tùy chỉnh hoạt động đúng trong các hoạt động đã đặt.Hành vi của đối tượng trong các hoạt động đã đặt

Tôi thường làm việc đó, nhưng tôi muốn đảm bảo rằng tôi hoàn toàn hiểu được các tác động. Đặc biệt, tôi quan tâm đến hành vi khi có dữ liệu bổ sung trong đối tượng không được bao gồm trong các phương thức bằng/băm. Dường như trong hoạt động 'giao lộ', nó trả về tập các đối tượng đang được so sánh, trong đó các hoạt động 'union' trả về tập các đối tượng đang được so sánh.

Để minh họa:

class MyObject: 
    def __init__(self,value,meta): 
     self.value = value 
     self.meta = meta 
    def __eq__(self,other): 
     return self.value == other.value 
    def __hash__(self): 
     return hash(self.value) 

a = MyObject('1','left') 
b = MyObject('1','right') 
c = MyObject('2','left') 
d = MyObject('2','right') 
e = MyObject('3','left') 
print a == b # True 
print a == C# False 

for i in set([a,c,e]).intersection(set([b,d])): 
    print "%s %s" % (i.value,i.meta) 
#returns: 
#1 right 
#2 right 

for i in set([a,c,e]).union(set([b,d])): 
    print "%s %s" % (i.value,i.meta) 
#returns: 
#1 left 
#3 left 
#2 left 

là hành vi này ghi nhận ở đâu đó và xác định? Nếu vậy, nguyên tắc điều chỉnh là gì?

Trả lời

4

Không, nó không xác định. Vấn đề là bạn đã phá vỡ bằng 'và bất biến của hash, rằng hai đối tượng là tương đương khi chúng bằng nhau. Sửa đối tượng của bạn, không cố gắng thông minh và lạm dụng cách triển khai của bộ công cụ. Nếu giá trị meta là một phần của danh tính MyObject, nó phải được bao gồm trong eq và băm.

Bạn không thể dựa vào giao lộ của bộ theo bất kỳ thứ tự nào, vì vậy không có cách nào để dễ dàng thực hiện những gì bạn muốn. Những gì bạn sẽ chỉ làm là lấy giao lộ bằng giá trị mà thôi, sau đó xem qua tất cả các đối tượng của bạn để có một cái cũ hơn để thay thế nó bằng, cho mỗi cái. Không có cách nào tốt đẹp để làm điều đó theo thuật toán.

đoàn không phải là quá tệ:

##fix the eq and hash to work correctly 
class MyObject: 
    def __init__(self,value,meta): 
     self.value = value 
     self.meta = meta 
    def __eq__(self,other): 
     return self.value, self.meta == other.value, other.meta 
    def __hash__(self): 
     return hash((self.value, self.meta)) 
    def __repr__(self): 
     return "%s %s" % (self.value,self.meta) 

a = MyObject('1','left') 
b = MyObject('1','right') 
c = MyObject('2','left') 
d = MyObject('2','right') 
e = MyObject('3','left') 

union = set([a,c,e]).union(set([b,d])) 
print union 
#set([2 left, 2 right, 1 left, 3 left, 1 right]) 

##sort the objects, so that older objs come before the newer equivalents 
sl = sorted(union, key= lambda x: (x.value, x.meta)) 
print sl 
#[1 left, 1 right, 2 left, 2 right, 3 left] 
import itertools 
##group the objects by value, groupby needs the objs to be in order to do this 
filtered = itertools.groupby(sl, lambda x: x.value) 
##make a list of the oldest (first in group) 
oldest = [ next(group) for key, group in filtered] 
print oldest 
#[1 left, 2 left, 3 left] 
+0

Nhìn vào tài liệu cho phương pháp __hash__, dường như không thể có dữ liệu trong đối tượng không được băm. Tôi có thể nghĩ về nhiều ví dụ mà 2 đối tượng tương đương sẽ có một số dạng siêu dữ liệu (dấu thời gian hoặc tên tệp, có lẽ) khác nhau. Từ tài liệu cho __hash__: Thuộc tính bắt buộc duy nhất là các đối tượng so sánh bằng nhau có cùng giá trị băm; nó được khuyến khích bằng cách nào đó trộn lẫn với nhau (ví dụ: sử dụng độc quyền hoặc) giá trị băm cho các thành phần của đối tượng cũng đóng vai trò so sánh các đối tượng. –

+1

Tôi bị nhầm lẫn bởi bình luận của bạn, dường như bạn đồng ý với tôi. Nếu một đối tượng có siêu dữ liệu (chẳng hạn như dấu thời gian hoặc tên tệp) bị bỏ qua bởi eq và băm, thì chúng không đủ quan trọng để được giữ, hoặc đối tượng được so sánh sẽ làm. Nếu chúng đủ quan trọng để phân biệt hai đối tượng, chúng sẽ được bao gồm trong hàm băm và eq. Bạn đang hỏi gì vào thời điểm này? – hlfrk414

+0

Tôi không đồng ý với bạn;). Chỉ cần cố gắng hiểu các tính năng này có thể được sử dụng như thế nào. Trong trường hợp này, tôi có các đối tượng được tạo ra bởi một tác nhân giám sát. Cố gắng tương quan các điều kiện cảnh báo định kỳ, có các dấu thời gian khác nhau. Muốn giữ các vật cũ hơn, nhưng tất nhiên tôi có thể thực hiện nó theo nhiều cách khác, bởi vì tôi nghi ngờ bạn là chính xác. –

1

thứ tự không xuất hiện để có vấn đề:

>>> [ (u.value, u.meta) for u in set([b,d]).intersection(set([a,c,e])) ] 
[('1', 'right'), ('2', 'right')] 

>>> [ (u.value, u.meta) for u in set([a,c,e]).intersection(set([b,d])) ] 
[('1', 'right'), ('2', 'right')] 

Tuy nhiên, nếu bạn làm điều này:

>>> f = MyObject('3', 'right') 

Và thêm f để bộ "đúng":

>>> [ (u.value, u.meta) for u in set([a,c,e]).intersection(set([b,d,f])) ] 
[('1', 'right'), ('3', 'right'), ('2', 'right')] 

>>> [ (u.value, u.meta) for u in set([b,d,f]).intersection(set([a,c,e])) ] 
[('1', 'left'), ('3', 'left'), ('2', 'left')] 

Vì vậy, bạn có thể thấy rằng hành vi phụ thuộc vào kích thước của các bộ (hiệu ứng tương tự sẽ xảy ra nếu bạn union). Nó có thể phụ thuộc vào các yếu tố khác. Tôi nghĩ rằng bạn đang tìm kiếm thông qua nguồn python nếu bạn muốn biết tại sao.

0

Giả sử đối tượng của bạn có hai loại thuộc tính khác nhau: khóa thuộc tính và dữ liệu thuộc tính. Trong ví dụ của bạn, MyObject.value là thuộc tính khóa.

Lưu tất cả các đối tượng của bạn dưới dạng từ khóa, được khóa bằng các thuộc tính khóa, đảm bảo rằng chỉ ưa thích của bạn (ví dụ: dấu thời gian cũ nhất) được nhập trong từ điển. Thực hiện các hoạt động đã cài đặt của bạn bằng cùng một khóa như được sử dụng trong từ điển và truy xuất các đối tượng thực tế từ từ điển:

result= [dict1[k] for k in set_operation_result]