2010-10-27 33 views
5

Tôi có đoạn code sau đây tôi đang cố gắng để hiểu:Hiểu __call__ và list.sort (key)

>>> class DistanceFrom(object): 
     def __init__(self, origin): 
      self.origin = origin 
     def __call__(self, x): 
      return abs(x - self.origin) 

>>> nums = [1, 37, 42, 101, 13, 9, -20] 
>>> nums.sort(key=DistanceFrom(10)) 
>>> nums 
[9, 13, 1, 37, -20, 42, 101] 

bất cứ ai có thể giải thích cách làm việc này? Theo như tôi đã hiểu, __call__ là những gì được gọi khi object() được gọi - gọi đối tượng là một hàm.

Điều tôi không hiểu là cách nums.sort(key=DistanceFrom(10)). Cái này hoạt động ra sao? Bất cứ ai có thể vui lòng giải thích dòng này?

Cảm ơn!

Trả lời

7

Ở đây tôi đã xác định một hàm DistanceFrom() mà có thể được sử dụng theo cách tương tự như lớp học của bạn, nhưng có thể dễ dàng hơn để làm theo

>>> def DistanceFrom(origin): 
...  def f(x): 
...   retval = abs(x - origin) 
...   print "f(%s) = %s"%(x, retval) 
...   return retval 
...  return f 
... 
>>> nums = [1, 37, 42, 101, 13, 9, -20] 
>>> nums.sort(key=DistanceFrom(10)) 
f(1) = 9 
f(37) = 27 
f(42) = 32 
f(101) = 91 
f(13) = 3 
f(9) = 1 
f(-20) = 30 
>>> nums 
[9, 13, 1, 37, -20, 42, 101] 

vì vậy, bạn thấy rằng các đối tượng được trả về bởi DistanceFromgọi một lần cho từng hạng mục công nums và sau đó nums được trả về được sắp xếp phù hợp với các giá trị trả

+0

Cảm ơn bạn! Đây là hoàn hảo. – user225312

+0

@Alfred, bạn được chào đón nhiều nhất –

4

Nó sắp xếp danh sách nums tại chỗ bằng cách sử dụng đối tượng hàm keyDistanceFrom(10). Nó cần phải được gọi bởi vì key cần phải được gọi. Kết quả đầu ra được sắp xếp theo "từ xa" của chúng từ 10, đó là 9 là giá trị gần nhất với 10, 101 là giá trị xa nhất.

Sau khi đối tượng được khởi tạo và thông qua như là một tham số key với phương pháp sort, trên mỗi lần lặp, nó sẽ được gọi với giá trị hiện tại (đó là x là gì) và trở về giá trị sẽ được sử dụng để xác định vị trí x 's trong danh sách kết quả.

+0

Cách này được thực thi? Ý tôi là, DistanceFrom (10) đặt self.origin = 10. Sau đó? – user225312

+0

@Alfred: xem chỉnh sửa của tôi – SilentGhost

+0

"__ init __" là một hàm tạo được gọi trong khi tạo khóa Đối tượng – OlimilOops

8

__call__ trong python cho phép một lớp được chạy như thể đó là một hàm. Bạn có thể thử cách này theo cách thủ công:

>>> dis = DistanceFrom(10) 
>>> print dis(10), dis(5), dis(0) 
0 5 10 
>>> 

Loại sắp xếp là gọi hàm đó cho mọi mục trong danh sách của bạn và sử dụng giá trị trả về làm khóa sắp xếp. Trong ví dụ này, bạn sẽ nhận được một danh sách trở lại với các mục gần nhất với 10 đầu tiên, và một trong những xa hơn nữa về phía cuối.

+0

Aah. Điều này là tốt. – user225312

+0

@user: Câu trả lời của bạn là hoàn hảo, nhưng tôi chấp nhận câu trả lời của gnibbler vì nó sẽ có lợi cho người mới bắt đầu trong trường hợp họ tìm kiếm nó. – user225312

1

Khi bạn gọi điều gì đó có nghĩa là bạn đang mong đợi nó trả về một giá trị. Khi bạn tạo một lớp học có phương thức __call__ được định nghĩa, bạn sẽ ra lệnh rằng một thể hiện của lớp đó có thể hoạt động như một hàm.

Đối với mục đích của câu hỏi này, điều này:

class DistanceFrom(object): 
     def __init__(self, origin): 
      self.origin = origin 
     def __call__(self, x): 
      return abs(x - self.origin) 

là có chức năng tương đương với:

def distance_from(origin, other): 
    return abs(other - origin) 

Đối với key lập luận để sắp xếp, đây là lời giải thích của bạn trực tiếp từ tài liệu Python:

phím chỉ định một hàm của một đối số được sử dụng để trích xuất khóa so sánh từ mỗi phần tử danh sách: key=str.lower.Giá trị mặc định là None (so sánh các yếu tố trực tiếp)

1

Các tài liệu Python khá tốt bất cứ khi nào tôi thấy tôi không hiểu các nguyên tắc cơ bản. Tôi đặt chúng với google.

The key parameter là chức năng sắp xếp sẽ gọi trên các phần tử của danh sách. Tôi đã tìm tài liệu này bằng cách googling sort site:http://docs.python.org/ và sau đó tìm kiếm key=.

__call__ là một hàm bạn có thể thêm vào đối tượng để làm cho đối tượng đó có thể gọi được như thể đó là một hàm. Tôi đã tìm thấy tài liệu này bằng cách googling __call__ site:http://docs.python.org/ và sau đó nhấp vào liên kết tới tài liệu cho __call__.

+0

Tôi hiểu chúng là gì, câu hỏi của tôi là cụ thể cho ví dụ này. – user225312