2011-01-22 38 views
116

Tôi biết Ruby rất rõ. Tôi tin rằng tôi có thể cần phải học Python hiện nay. Đối với những người biết cả hai, khái niệm nào tương tự nhau giữa hai khái niệm và khác nhau là gì?Học Python từ Ruby; Sự khác biệt và tương đồng

Tôi đang tìm danh sách tương tự như mồi tôi đã viết cho Learning Lua for JavaScripters: những thứ đơn giản như ý nghĩa khoảng trắng và cấu trúc vòng lặp; tên của nil bằng Python và giá trị nào được coi là "trung thực"; có phải là thành ngữ để sử dụng tương đương với mapeach hoặc mumblesomethingaboutlistcomprehensionsmumble tiêu chuẩn?

Nếu tôi nhận được nhiều câu trả lời hay, tôi rất vui khi tổng hợp chúng thành một wiki cộng đồng. Hoặc người nào khác tất cả các bạn có thể chiến đấu và nôi với nhau để cố gắng tạo ra một danh sách toàn diện thực sự.

Chỉnh sửa: Để rõ ràng, mục tiêu của tôi là "đúng" và thành ngữ Python. Nếu có một Python tương đương với inject, nhưng không ai sử dụng nó vì có một cách tốt hơn/khác để đạt được chức năng chung của việc lặp lại danh sách và tích luỹ kết quả trên đường đi, tôi muốn biết bạn làm việc như thế nào. Có lẽ tôi sẽ cập nhật câu hỏi này với một danh sách các mục tiêu chung, cách bạn đạt được chúng trong Ruby, và hỏi tương đương với Python.

+1

điều duy nhất tôi đọc được http : //c2.com/cgi/wiki? PythonVsRuby, tôi thực sự không thích bản thân và sự chú ý nhưng tôi đã quen với nó :) –

+1

Liên quan: http://stackoverflow.com/questions/1113611/what-does-ruby- có-đó-python-doesnt-và-vice-versa (Tôi không hoàn toàn chắc chắn nếu nó là một bản sao, như câu hỏi đó yêu cầu những điều mà không có một tương đương). – delnan

+1

@Saif Cuộc thảo luận đó có rất nhiều ví dụ lỗi thời và tồi tệ lần cuối tôi kiểm tra. Đề xuất 'a = []; 0.upto (2) {| i | 0.upto (2) {| j | a << [i, j] nếu i! = J}}' tương đương với Ruby của '[ (x, y) cho x trong xrange (3) cho y trong xrange (3) nếu x! = y] '(và sau đó loại bỏ tất cả khoảng trắng và gọi rằng một cải tiến) là khá nhiều những gì bạn có nguy cơ làm khi bạn không lưu ý lời khuyên của ircmaxell. – badp

Trả lời

141

Dưới đây là một số khác biệt quan trọng với tôi:

  1. Ruby có khối ; Python thì không.

  2. Python có chức năng; Ruby thì không. Trong Python, bạn có thể lấy bất kỳ hàm hoặc phương thức nào và chuyển nó đến một hàm khác. Trong Ruby, mọi thứ đều là một phương thức và các phương thức không thể được truyền trực tiếp. Thay vào đó, bạn phải bọc chúng trong Proc để vượt qua chúng.

  3. Cả Ruby và Python đều hỗ trợ đóng, nhưng theo nhiều cách khác nhau. Trong Python, bạn có thể định nghĩa một hàm bên trong một hàm khác. Hàm bên trong đã đọc quyền truy cập vào các biến từ hàm bên ngoài, nhưng không có quyền ghi. Trong Ruby, bạn định nghĩa các bao đóng bằng cách sử dụng các khối. Các bao đóng có khả năng đọc và ghi đầy đủ các biến từ phạm vi bên ngoài.

  4. Python có khả năng hiểu danh sách khá rõ ràng. Ví dụ: nếu bạn có danh sách các số, bạn có thể viết

    [x*x for x in values if x > 15] 
    

    để nhận danh sách mới của các ô vuông của tất cả các giá trị lớn hơn 15.Trong Ruby, bạn phải viết như sau:

    values.select {|v| v > 15}.map {|v| v * v} 
    

    Mã Ruby không cảm thấy nhỏ gọn. Nó cũng không hiệu quả vì nó đầu tiên chuyển mảng giá trị thành mảng trung gian ngắn hơn chứa các giá trị lớn hơn 15. Sau đó, nó lấy mảng trung gian và tạo ra một mảng cuối cùng chứa các bình phương của các trung gian. Mảng trung gian sau đó được ném ra ngoài. Vì vậy, Ruby kết thúc với 3 mảng trong bộ nhớ trong quá trình tính toán; Python chỉ cần danh sách đầu vào và danh sách kết quả.

    Python cũng cung cấp khả năng hiểu bản đồ tương tự.

  5. Python hỗ trợ bộ dữ liệu; Ruby thì không. Trong Ruby, bạn phải sử dụng các mảng để mô phỏng các bộ dữ liệu.

  6. Ruby hỗ trợ báo cáo chuyển đổi/trường hợp; Python thì không.

  7. Ruby hỗ trợ toán tử ternary tiêu chuẩn expr ? val1 : val2; Python thì không.

  8. Ruby chỉ hỗ trợ kế thừa đơn. Nếu bạn cần bắt chước nhiều thừa kế, bạn có thể định nghĩa các mô đun và sử dụng các mix-in để kéo các phương thức mô-đun vào các lớp. Python hỗ trợ đa kế thừa hơn là các kết hợp mô-đun.

  9. Python chỉ hỗ trợ các hàm lambda một dòng. Khối Ruby, là loại/loại hàm lambda, có thể tùy ý lớn. Bởi vì điều này, mã Ruby thường được viết theo một phong cách chức năng hơn mã Python. Ví dụ: để lặp qua danh sách trong Ruby, bạn thường làm

    collection.each do |value| 
        ... 
    end 
    

    Khối hoạt động giống như một hàm được chuyển đến collection.each. Nếu bạn đã làm điều tương tự bằng Python, bạn phải xác định một hàm bên trong đặt tên và sau đó vượt qua đó để thu thập từng phương pháp (nếu danh sách được hỗ trợ phương pháp này):

    def some_operation(value): 
        ... 
    
    collection.each(some_operation) 
    

    Đó không chảy rất độc đáo. Vì vậy, thường thì phương pháp tiếp cận phi chức năng sau sẽ được sử dụng trong Python:

    for value in collection: 
        ... 
    
  10. Sử dụng tài nguyên một cách an toàn là khác nhau giữa hai ngôn ngữ. Ở đây, vấn đề là bạn muốn phân bổ một số tài nguyên (mở một tệp, lấy một con trỏ cơ sở dữ liệu, vv), thực hiện một số thao tác tùy ý trên nó, và sau đó đóng nó một cách an toàn ngay cả khi một ngoại lệ xảy ra.

    Trong Ruby, vì các khối rất dễ sử dụng (xem # 9), bạn thường sẽ viết mã mẫu này làm phương thức lấy một khối để hoạt động tùy ý thực hiện trên tài nguyên.

    Trong Python, chuyển một hàm cho hành động tùy ý là một chút clunkier vì bạn phải viết một hàm bên trong có tên (xem # 9). Thay vào đó, Python sử dụng câu lệnh with để xử lý tài nguyên an toàn. Xem How do I correctly clean up a Python object? để biết thêm chi tiết.

+2

3. Python 3 'nonlocal' sửa lỗi này 4. Python cũng cung cấp cho bạn biểu thức máy phát (tương tự như danh sách comprehensions, nhưng không tính toán bất cứ điều gì cho đến khi được yêu cầu - suy nghĩ của danh sách comprehensions như máy phát biểu biểu thức ăn vào' danh sách' (mà mất một có thể lặp lại và trả về một danh sách chứa mọi thứ có thể lặp lại được) - điều này có thể tiết kiệm nhiều công sức trong một số trường hợp). – delnan

+25

7. Có. 'val1 nếu expr else val2'. số 8.Mặc dù tôi thấy nó chủ yếu được sử dụng để tăng cường kiểu mixin. – delnan

+2

@ClintMiller Whoa, không có chuyển đổi/trường hợp? Vì vậy, cách đề xuất để đạt được chức năng tương tự trong Python là gì? nếu/else/if? – Phrogz

10

Đề xuất của tôi: Đừng cố gắng tìm hiểu sự khác biệt. Tìm hiểu cách tiếp cận vấn đề bằng Python. Cũng giống như có một cách tiếp cận Ruby cho mỗi vấn đề (hoạt động rất tốt givin những hạn chế và thế mạnh của ngôn ngữ), có một cách tiếp cận Python cho vấn đề. chúng đều khác nhau. Để tận dụng tối đa từng ngôn ngữ, bạn thực sự nên tự học ngôn ngữ và không chỉ là "dịch" từ ngôn ngữ này sang ngôn ngữ khác.

Bây giờ, với điều đó đã nói, sự khác biệt sẽ giúp bạn điều chỉnh nhanh hơn và thực hiện 1 sửa đổi đối với chương trình Python. Và đó là tốt cho một bắt đầu để có được văn bản. Nhưng cố gắng học hỏi từ các dự án khác tại sao đằng sau những quyết định kiến ​​trúc và thiết kế chứ không phải là như thế nào đằng sau những ngữ nghĩa của ngôn ngữ ...

+7

Tôi đánh giá cao đề xuất của bạn. Tôi hoàn toàn đồng ý với tình cảm _ (mà tôi hiểu là "Học lập trình Python thành ngữ") _. Đó chính là điều tôi đang cố gắng làm. Tôi không hỏi _ "Tên Python cho phương thức' each' của Ruby là gì? "_ Tôi hỏi _" Làm thế nào mọi thứ được thực hiện đúng trong Python khác với Ruby, và chúng được làm đúng ở đâu? "_ Nếu 'False' của Python thực sự là' False', điều quan trọng là phải biết ở đâu và khi nào tôi nên làm mọi thứ theo cách Rubyesque, và ở đâu và khi nào thì tôi không nên làm. – Phrogz

+1

@Phrogz: Thật công bằng. Cách tôi giải thích câu hỏi của bạn là: * Hãy tạo một danh sách các khác biệt để chúng tôi có thể thay đổi ngôn ngữ mà chúng tôi đang lập trình *. Nhưng đó là một câu hỏi công bằng. Tôi đoán tôi chỉ hiểu sai những gì bạn đang yêu cầu. Tôi sẽ để nó ở đây để tham khảo, nhưng nó sẽ rất thú vị khi xem những gì khác xuất hiện ... – ircmaxell

+0

Tôi đang học python và ruby ​​cùng một lúc, và trong dev ứng dụng web tôi thấy nhiều điểm tương đồng hơn sự khác biệt. – FaithReaper

7

Tôi biết rất ít Ruby, nhưng đây là một vài điểm nhấn về những điều bạn đề cập:

  • nil, giá trị chỉ thiếu một giá trị, sẽ None (lưu ý rằng bạn kiểm tra nó giống như x is None hoặc x is not None, không phải với == - hoặc bằng cách ép buộc với boolean, xem điểm tiếp theo).
  • None, số zero-esque (0, 0.0, 0j (số phức)) và bộ sưu tập rỗng ([], {}, set(), chuỗi rỗng "", vv) được coi là falsy, mọi thứ khác được coi truthy.
  • Để biết các tác dụng phụ, (for -) lặp lại một cách rõ ràng. Để tạo ra một loạt các công cụ mới mà không có tác dụng phụ, sử dụng danh sách comprehensions (hoặc người thân của họ - biểu thức máy phát điện cho một lần lặp lười biếng, dict/set comprehensions cho các bộ sưu tập nói).

Liên quan đến vòng lặp: Bạn có for, hoạt động trên một lần lặp (! Không đếm) và while, điều bạn mong đợi. Từ xa mạnh hơn rất nhiều, nhờ sự hỗ trợ rộng rãi cho các trình vòng lặp. Không chỉ gần như tất cả mọi thứ có thể là một iterator thay vì một danh sách là một iterator (ít nhất là trong Python 3 - trong Python 2, bạn có cả hai và mặc định là một danh sách, thật đáng buồn). Có rất nhiều công cụ để làm việc với các trình lặp - zip lặp lại bất kỳ số lần lặp nào song song, enumerate cung cấp cho bạn (index, item) (trên bất kỳ nào có thể lặp lại, không chỉ trên danh sách), thậm chí cắt vòng lặp (có thể lớn hoặc vô hạn). Tôi thấy rằng những điều này làm cho nhiều nhiệm vụ lặp lại đơn giản hơn rất nhiều. Không cần phải nói, chúng tích hợp tốt với tính năng hiểu danh sách, biểu thức trình tạo, v.v.

+2

Biểu thức máy phát điện rất tuyệt. Họ cung cấp cho Python một chút về khả năng đánh giá lười biếng của các ngôn ngữ như Haskell. –

+0

@Clint: Có. Và máy phát điện đầy đủ thậm chí còn có khả năng hơn (mặc dù không cần thiết cho các trường hợp đơn giản, xảy ra là đa số). – delnan

+0

Tại sao bạn kiểm tra bằng 'x là None' hoặc' x không phải là None'? Tôi luôn luôn kiểm tra với 'x == None' và' x! = None'. – John

6

Trong Ruby, các biến mẫu và phương thức hoàn toàn không liên quan, ngoại trừ khi bạn liên kết chúng với attr_accessor hoặc tương tự.

Trong Python, các phương thức chỉ là một lớp thuộc tính đặc biệt: một thuộc tính có thể thực thi được.

Vì vậy, ví dụ:

>>> class foo: 
...  x = 5 
...  def y(): pass 
... 
>>> f = foo() 
>>> type(f.x) 
<type 'int'> 
>>> type(f.y) 
<type 'instancemethod'> 

khác biệt đó có rất nhiều ý nghĩa, ví dụ như là ám chỉ đến f.x đề cập đến đối tượng phương pháp, thay vì gọi nó. Ngoài ra, như bạn có thể thấy, f.x được công khai theo mặc định, trong khi trong Ruby, các biến mẫu là riêng tư theo mặc định.

+1

Thực ra, tôi muốn nói rõ hơn: trong Python, các phương thức chỉ là một kiểu thuộc tính cụ thể, trong khi trong Ruby, các thuộc tính chỉ là một kiểu phương thức cụ thể. Một số tính năng tương phản quan trọng giữa hai ngôn ngữ rơi ra khỏi điều này: Các hàm lớp đầu tiên trong Python và Nguyên tắc truy cập thống nhất trong Ruby – philomory

26

Tôi vừa dành một vài tháng để học Python sau 6 năm của Ruby. Thực sự không có sự so sánh tuyệt vời cho hai ngôn ngữ này, vì vậy tôi quyết định tự mình lên và viết một bản. Bây giờ, nó chủ yếu liên quan đến lập trình hàm, nhưng vì bạn đề cập đến phương pháp inject của Ruby, tôi đoán chúng ta đang ở trên cùng một bước sóng.

Tôi hy vọng điều này sẽ giúp: The 'ugliness' of Python

Một vài điểm sẽ giúp bạn di chuyển đúng hướng:

  • Tất cả sự tốt lành chức năng lập trình bạn sử dụng trong Ruby bằng Python, và nó dễ dàng hơn.Ví dụ, bạn có thể lập bản đồ trên các chức năng chính xác như bạn mong muốn:

    def f(x): 
        return x + 1 
    
    map(f, [1, 2, 3]) # => [2, 3, 4] 
    
  • Python không có một phương pháp mà hành động như each. Kể từ khi bạn chỉ sử dụng each cho tác dụng phụ, tương đương với bằng Python là vòng lặp for:

    Danh sách
    for n in [1, 2, 3]: 
        print n 
    
  • comprehensions là tuyệt vời khi a) bạn phải đối phó với các chức năng và các bộ sưu tập đối tượng với nhau và b) khi bạn cần lặp lại bằng nhiều chỉ mục. Ví dụ, để tìm tất cả các palindromes trong một chuỗi (giả sử bạn có một hàm p() mà trả về true cho palindromes), tất cả bạn cần là một danh sách hiểu duy nhất:

    s = 'string-with-palindromes-like-abbalabba' 
    l = len(s) 
    [s[x:y] for x in range(l) for y in range(x,l+1) if p(s[x:y])] 
    
+3

Sigh, tôi đọc bài đó và nó xác nhận sự nghi ngờ của tôi: ít người hiểu vai trò và tiện ích của các phương pháp đặc biệt trong Python. Chúng cực kỳ hữu ích và được tiêu chuẩn hóa, và chúng được nhấn mạnh như vậy để tránh đặt tên xung đột với các nội trang mà chúng thường thực hiện. Không ai thực sự biết rằng Python đang cố gắng ngăn cản việc sử dụng chúng. –

+5

Bạn dường như không hiểu cách thức hoạt động của các phương thức. Một phương thức, về cơ bản, một hàm có đối số đầu tiên là một thể hiện của lớp mà phương thức thuộc về. Khi bạn viết 'Class.method', phương thức là" unbound "và đối số đầu tiên sẽ là một cá thể' Class'; khi bạn viết 'object.method', phương thức này là" bound "đối với cá thể' object' của 'Class'. Điều này cho phép bạn chọn có sử dụng bản đồ (vv) để gọi phương thức trên một cá thể khác biệt mỗi lần (truyền một phương thức không liên kết) hay giữ cho cá thể cố định và chuyển một đối số thứ hai khác nhau mỗi lần. Cả hai đều hữu ích. – LaC

+2

Bạn nói đúng, tôi không hiểu cách họ làm việc. Kể từ khi xuất bản bài báo, tôi đã hiểu rõ hơn về nó. Cảm ơn! –

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