2010-03-02 38 views
8

Có khả năng tạo ra bất kỳ đối tượng python nào sẽ không thể sắp xếp được không? Vì vậy, đó sẽ là một ngoại lệ khi cố gắng sắp xếp một danh sách các đối tượng đó? Tôi đã tạo một lớp rất đơn giản, không xác định bất kỳ phương thức so sánh nào, nhưng vẫn có thể so sánh các thể hiện của lớp này và do đó có thể sắp xếp. Có lẽ, lớp của tôi thừa kế các phương pháp so sánh từ đâu đó. Nhưng tôi không muốn hành vi này.Có cách nào để tạo một đối tượng python sẽ không thể sắp xếp được không?

Trả lời

7

Bạn có thể xác định phương thức __cmp__ trên lớp và luôn nêu ngoại lệ khi được gọi. Điều đó có thể làm các trick.

Ngoài sự tò mò, tại sao?

+0

Cám ơn câu trả lời nhanh! Tôi đã tìm thấy công thức về cách nhanh nhất để xóa các mục trùng lặp khỏi chuỗi - http://code.activestate.com/recipes/52560/. Kiểm tra bình luận này trong mã số: "Nếu không thể, các phần tử trình tự sẽ được hưởng tổng số yêu cầu, và nếu danh sách (s) .sort() không tăng TypeError, thì giả định rằng chúng được hưởng tổng số thứ tự. unique() sẽ thường hoạt động trong thời gian O (N * log2 (N)). " Tôi không thể tạo thành phần không được hưởng tổng số thứ tự. Vì vậy, nó là một lỗi của tác giả công thức, hay anh ta thực sự biết điều gì đó, mà tôi không biết? – Graf

+0

Tại sao không chỉ sử dụng 'set()' để lấy danh sách – er, 'set' – của các phần tử duy nhất? Tại sao bạn sử dụng công thức đó? Nếu bạn đang sử dụng công thức đó và bạn làm cho các đối tượng của bạn luôn có ngoại lệ khi chúng được sắp xếp, điều đó sẽ sử dụng cách thứ ba và tồi tệ nhất để xác định các mục duy nhất. –

+0

Vâng, hiểu rằng, tôi chỉ muốn biết, nếu tác giả của công thức nấu ăn là làm một cái gì đó từ không có gì, hoặc nếu anh ta chỉ cố gắng xử lý tất cả các tình huống có thể. Vì vậy, tôi muốn biết, trong trường hợp nào giải pháp thứ hai thất bại (sử dụng sắp xếp) không thành công? Giải pháp đầu tiên không thành công khi các đối tượng không có khả năng băm (danh sách sắp xếp của danh sách), nhưng có vẻ như không có trường hợp nào khi giải pháp thứ hai thất bại. Nhân tiện, giải pháp của bạn (sử dụng set() để lấy danh sách-er) cũng không thành công trong trường hợp không có danh sách băm. >>> a = [[1,1], [1,2], [1,1]] >>> a = danh sách (đặt (a)) LoạiError: loại không thể loại bỏ: 'list' – Graf

0

Tại sao bạn không viết một lớp có chứa đối tượng danh sách và cung cấp các phương thức để truy cập dữ liệu bên trong? Bằng cách đó, bạn sẽ ẩn danh sách một cách hiệu quả và do đó ngăn chúng phân loại nó.

1

Như Will McCutchen đã đề cập, bạn có thể xác định phương pháp __cmp__ làm tăng ngoại lệ để ngăn phân loại vườn. Một cái gì đó như thế này:

class Foo(object): 
    def __cmp__(self, other): 
     raise Exception() 

a = [Foo(), Foo(), Foo()] 
a.sort() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 3, in __cmp__ 
Exception 

Tuy nhiên, bạn thực sự không thể ngăn nhà phát triển phân loại danh sách đối tượng của mình. Sử dụng đối số key hoặc cmp với list.sort() hoặc với chức năng độc lập được tích hợp sẵn sorted(), bất kỳ ai cũng có thể phá vỡ phương pháp __cmp__ bằng cách sử dụng hàm so sánh tùy chỉnh hoặc khóa sắp xếp.

# continuing from above 
>>> a = [Foo(), Foo(), Foo()] 
>>> a 
[<__main__.Foo object at 0x1004a3350>, <__main__.Foo object at 0x1004a3390>, 
<__main__.Foo object at 0x1004a33d0>] 

>>> a.sort(key=id, reverse=True) 
>>> # or a.sort(cmp=lambda a, b: cmp(id(b), id(a))) 
>>> # or sorted(a, key=id) 
>>> # etc... 
[<__main__.Foo object at 0x1004a33d0>, <__main__.Foo object at 0x1004a3390>, 
<__main__.Foo object at 0x1004a3350>] 

Như những người khác sẽ chỉ ra, tôi không chắc chắn có nhiều giá trị trong việc cố gắng ngăn người khác phân loại đối tượng. Nếu điều này không chỉ là một sự ngứa ngáy kỳ lạ mà bạn đang cố gắng làm xước, trường hợp sử dụng cho điều này là gì?

+0

Bạn đã nhanh hơn một phút. Hầu như chính xác cùng một mã ví dụ;) –

1

Phân loại danh sách mặc định sử dụng chức năng được xây dựng trong cmp() trên các phần tử của nó. Hàm cmp() kiểm tra xem đối số của nó (2 phần tử trong danh sách của bạn) có phương thức __cmp__() hay không. Nếu có, phương pháp này được sử dụng để so sánh. Nếu không, như trong trường hợp của bạn, các ID đối số đối số (giá trị trả về của hàm dựng sẵn id()) được sử dụng để so sánh.

Để cho việc phân loại thất bại, bạn có thể xác định một phương pháp so sánh mà ném ra một ngoại lệ:

>>> class X(object): 
... def __cmp__(self, other): 
...  raise StandardError # or whatever Exception you need 
... 
>>> l = [X(), X(), X()] 
>>> l.sort() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 2, in __cmp__ 
StandardError 
+0

Đó là câu trả lời hay và rõ ràng! Nhưng có bất kỳ đối tượng có một id chức năng được xây dựng trong()? – Graf

+0

ID đối tượng được đặt bên trong bằng Python, không phải bởi phương thức của đối tượng. Thông thường, ví dụ: trong Python dựa trên C, nó chỉ đơn giản là địa chỉ bộ nhớ của đối tượng (xem thêm http://docs.python.org/library/functions.html#id). –

0

Sets không có tổng cộng đặt hàng

>>> s=set((1,2,3)) 
>>> t=set("abc") 
>>> s<t 
False 
>>> t<s 
False 
>>> 

Nhưng không phải ngoại lệ là khi bạn nâng cao cố gắng sắp xếp chúng

>>> sorted([s,t]) 
[set([1, 2, 3]), set(['a', 'c', 'b'])] 
1

Đối với những gì nó đáng giá, trong Python 3, mặc định sẽ là giá trị mới ems không thể so sánh (và do đó không thể sắp xếp). Trong Python 2, bạn phải tạo một phương thức __cmp__ hoặc __lt__ một cách rõ ràng, như những người khác đã nói.

0

Thuật toán sắp xếp python sử dụng phương thức đặc biệt __lt__. Giữ trong tâm trí rằng việc sử dụng các cmpkey đối số của hàm phân loại và phương pháp, người ta cho rằng lớp học của bạn định nghĩa một phương pháp:

def __lt__(self, other): 
    raise NotImplementedError 
Các vấn đề liên quan