2017-08-14 17 views
39

reversed 's loại là "loại":Tại sao được đảo ngược và sắp xếp các loại khác nhau trong Python?

>>> type(reversed) 
<class 'type'> 

sorted' s loại là "chức năng được xây dựng trong hoặc phương pháp":

>>> type(sorted) 
<class 'builtin_function_or_method'> 

Tuy nhiên, họ có vẻ giống nhau trong tự nhiên. Loại trừ sự khác biệt rõ ràng về chức năng (chuỗi đảo ngược so với sắp xếp), lý do cho sự khác biệt này trong việc triển khai là gì?

+1

Chúng khác nhau vì chúng làm những việc khác nhau. Kết quả cuối cùng có thể được xem là tương tự, nhưng cách để có được kết quả cuối cùng là rất khác nhau. –

+1

Đầu cơ không có dấu gạch ngang: 'đảo ngược' là một kiểu vì nó trả về một biến lặp thực hiện phương thức [' __length_hint__'] (https://docs.python.org/3/reference/datamodel.html#object.__length_hint__). Vì phương thức này phải được định nghĩa trong một lớp, nên nó có ý nghĩa đối với 'đảo ngược' chính nó là lớp đó. (Vấn đề với lý thuyết này là '__length_hint__' chỉ tồn tại kể từ python 3.4) –

+2

Hãy để tôi hỏi câu hỏi ngược lại: tại sao bạn mong đợi chúng giống nhau? – jpmc26

Trả lời

50

Sự khác biệt là reversed là một trình lặp (nó cũng là đánh giá lười biếng) và sorted là một hàm hoạt động "háo hức".

Tất cả built-in lặp (ít nhất là trong python-3.x) như map, zip, filter, reversed, ... được thực hiện như lớp. Trong khi các trình cài sẵn hoạt động háo hức là chức năng, ví dụ: min, max, any, allsorted.

>>> a = [1,2,3,4] 
>>> r = reversed(a) 
<list_reverseiterator at 0x2187afa0240> 

Bạn thực sự cần phải "tiêu thụ" các iterator để có được các giá trị (ví dụ list):

>>> list(r) 
[4, 3, 2, 1] 

Mặt khác này "tiêu thụ" một phần là không cần thiết cho chức năng như sorted:

>>> s = sorted(a) 
[1, 2, 3, 4] 

tôi n các ý kiến ​​nó được hỏi lý do tại sao chúng được thực hiện như là các lớp thay vì chức năng. Điều đó không thực sự dễ dàng để trả lời nhưng tôi sẽ cố hết sức:

Sử dụng các hoạt động đánh giá lười biếng có một lợi ích to lớn: Chúng rất hiệu quả khi bị xâu chuỗi.Họ không cần tạo danh sách trung gian trừ khi chúng được "yêu cầu" rõ ràng. Đó là lý do tại sao map, zipfilter được thay đổi từ các hàm hoạt động háo hức (python-2.x) thành các lớp hoạt động lười biếng (python-3.x).

Nói chung có hai cách bằng Python để tạo vòng lặp:

  • lớp return self trong phương pháp __iter__ họ chức năng máy phát điện
  • - chức năng có chứa một yield

Tuy nhiên (ít nhất CPython) thực hiện tất cả các built-in của họ (và một số mô-đun thư viện tiêu chuẩn) trong C. Nó rất dễ dàng để tạo các lớp lặp trong C nhưng tôi đã không tìm thấy bất kỳ cách nào hợp lý để tạo ra máy phát funct các ion dựa trên Python-C-API. Vì vậy, lý do tại sao các trình vòng lặp này được thực hiện như các lớp (trong CPython) có thể chỉ là tiện lợi hoặc thiếu các lựa chọn thay thế (nhanh hoặc có thể thực hiện).

Có một lý do khác để sử dụng lớp thay vì máy phát: Bạn có thể triển khai các phương pháp đặc biệt cho lớp học nhưng bạn không thể triển khai chúng trên các chức năng của trình tạo. Điều đó nghe có vẻ không ấn tượng nhưng nó có lợi thế nhất định. Ví dụ: hầu hết các trình lặp có thể là pickled (ít nhất là trên Python-3.x) bằng cách sử dụng các phương thức __reduce____setstate__. Điều đó có nghĩa là bạn có thể lưu trữ chúng trên đĩa và cho phép sao chép chúng. Kể từ Python-3.4 một số vòng lặp cũng thực hiện __length_hint__ mà làm cho tiêu thụ các iterators với list (và tương tự) nhanh hơn nhiều.


Lưu ý rằng reversed dễ dàng có thể được thực hiện như nhà máy chức năng (như iter) nhưng không giống như iter, mà có thể trở lại hai độc đáo lớp, reversed chỉ có thể trở lại một độc đáo lớp.

Để minh họa cho các lớp có thể (và duy nhất), bạn phải xem xét một lớp học mà không có __iter__ và không __reversed__ phương pháp nhưng iterable và ngược iterable (bằng cách thực hiện __getitem____len__):

class A(object): 
    def __init__(self, vals): 
     self.vals = vals 

    def __len__(self): 
     return len(self.vals) 

    def __getitem__(self, idx): 
     return self.vals[idx] 

Và trong khi nó làm cho tinh thần để thêm một lớp trừu tượng (một chức năng nhà máy) trong trường hợp iter - bởi vì lớp trở là tùy thuộc vào số lượng các đối số đầu vào:

>>> iter(A([1,2,3])) 
<iterator at 0x2187afaed68> 
>>> iter(min, 0) # actually this is a useless example, just here to see what it returns 
<callable_iterator at 0x1333879bdd8> 

Lý do đó không áp dụng cho reversed:

>>> reversed(A([1,2,3])) 
<reversed at 0x2187afaec50> 
+0

anyway +1, Các phương thức 'itertools.' cũng được thực hiện như các lớp, theo cùng logic mà tôi đoán, mặc dù tôi vẫn chưa rõ tại sao –

+0

Tôi cập nhật câu trả lời một chút để bao gồm một lý do tại sao đây là các lớp trong CPython. Tuy nhiên, không thể trả lời câu hỏi này theo cách có ý nghĩa cho 'đảo ngược' bởi vì điều đó cũng có thể dễ dàng là chức năng của nhà máy (như' lặp'). Nhưng giống như 'iter', giá trị trả về của' reversed' sẽ luôn là một lớp lặp hoặc hàm máy phát. – MSeifert

+1

Thêm một cái gì đó ở đây: hãy nhớ rằng với đánh giá lười biếng đòi hỏi một số loại đối tượng container để lưu trữ thông tin về trạng thái hiện tại. Điều này chỉ có thể được thực hiện thông qua một đối tượng. Và do đó, một lớp học. –

4

Sự khác nhau giữa reversedsorted là gì?

Điều thú vị là reversed không phải là chức năng, trong khi sorted là.

mở một phiên REPL và loại help(reversed):

class reversed(object) 
| reversed(sequence) -> reverse iterator over values of the sequence 
| 
| Return a reverse iterator 

Nó thực sự là một lớp được sử dụng để trả về một iterator ngược lại.

Được rồi, vì vậy reversed không phải là chức năng. Nhưng tại sao không?

Điều này hơi khó trả lời. Một giải thích là các trình vòng lặp có đánh giá lười biếng. Điều này đòi hỏi một số loại container để lưu trữ thông tin về trạng thái hiện tại của trình lặp tại bất kỳ thời điểm nào. Điều này được thực hiện tốt nhất thông qua một đối tượng, và do đó, một class.

+3

Nếu tôi hiểu câu hỏi của OP chính xác, họ hỏi _why_ 'reversed' không phải là một hàm. (Hoặc tại sao 'được sắp xếp' không phải là một loại.) –

+0

Các tài liệu có vẻ hơi gây nhầm lẫn, có lẽ, với 'đảo ngược' (và các lớp khác) được liệt kê trong" Chức năng tích hợp "https://docs.python.org/3/library/functions.html –

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