Học Python từ Ruby; Sự khác biệt và tương đồng


131

Tôi biết Ruby rất rõ. Tôi tin rằng tôi có thể cần phải học Python ngay bây giờ. Đối với những người biết cả hai, những khái niệm nào giống nhau giữa hai và những gì khác nhau?

Tôi đang tìm kiếm một danh sách tương tự như một đoạn mồi tôi đã viết cho Learning Lua cho JavaScript : những điều đơn giản như tầm quan trọng của khoảng trắng và các cấu trúc lặp; tên của nilPython và giá trị nào được coi là "trung thực"; là nó thành ngữ để sử dụng tương đương với mapeach, hoặc là lí nhí somethingaboutlistcomprehensions Mumble chuẩn mực?

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 wiki cộng đồng. Hoặc nếu không, tất cả các bạn có thể chiến đấu và cũi lẫn 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à Python "phù hợp" và thành ngữ. Nếu có một Python tương đương inject, nhưng không ai sử dụng nó bởi vì có một cách tốt hơn / khác nhau để đạt được chức năng chung là lặp lại danh sách và tích lũy kết quả trên đường đi, tôi muốn biết cách bạn làm mọi thứ. 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 phổ biến, cách bạn đạt được chúng trong Ruby và hỏi tương đương với Python là gì.


1
điều duy nhất tôi đọc là c2.com/cgi/wiki?PythonVsRuby , tôi thực sự không thích bản thân và các vết lõm nhưng tôi đã quen với nó :)
Saif al Harthi

1
Liên quan: stackoverflow.com/questions/1113611/ (Tôi không chắc đó có phải là bản sao không, vì câu hỏi đó yêu cầu mọi thứ không có tương đương).

19
@SilentGhost Tôi rất không đồng ý. Tôi đang hỏi "Điều gì giống nhau giữa các ngôn ngữ và sự khác biệt là gì?" Như được thể hiện bởi nhiều câu trả lời dưới đây, có những câu trả lời rất rõ ràng và hữu ích cho việc này.
Phrogz

3
@Phrogz: Tôi thấy điều đó và làm cho câu hỏi không thể trả lời được.
SilentGhost

2
@Phrongz - Để lặp lại những gì tôi đã nói về chủ đề meta mà bạn đã đăng, vấn đề với câu hỏi này là không gian vấn đề quá lớn - đó là một chủ đề quá lớn cho chỉ một câu hỏi. Có hàng ngàn sự khác biệt giữa hai ngôn ngữ.
Adam Davis

Câu trả lời:


153

Dưới đây là một số khác biệt chính đối 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ó sang 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ợ các bao đóng, nhưng theo những 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 đọc vào các biến từ hàm ngoài, nhưng không truy cập ghi. Trong Ruby, bạn xác định các bao đóng bằng các khối. Các bao đóng có quyền truy cập đọc và ghi đầy đủ vào các biến từ phạm vi bên ngoài.

  4. Python có danh sách hiểu, đó là biểu cảm khá. Ví dụ: nếu bạn có một danh sách các số, bạn có thể viết

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

    để có danh sách mới về bình phươ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ì lần đầu tiên nó chuyển đổi các mảng giá trị thành một 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. Các mảng trung gian sau đó được ném ra. 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 sự hiểu biết 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ợ expr ? val1 : val2toán tử ternary tiêu chuẩn ; Python thì không.

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

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

    collection.each do |value|
      ...
    end

    Các khối hoạt động rất giống như một chức năng được truyền đến collection.each. Nếu bạn đã làm điều tương tự trong Python, bạn phải xác định hàm bên trong có tên và sau đó chuyển nó vào bộ sưu tập mỗi phương thức (nếu danh sách hỗ trợ phương thức này):

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

    Điều đó không chảy rất độc đáo. Vì vậy, thông thường, cách tiếp cận phi chức năng sau đây 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á 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ở tệp, lấy con trỏ cơ sở dữ liệu, v.v.), thực hiện một số thao tác tùy ý trên nó, sau đó đóng nó một cách an toàn ngay cả khi xảy ra ngoại lệ.

    Trong Ruby, vì các khối rất dễ sử dụng (xem # 9), bạn thường mã hóa mẫu này như một 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, truyền vào một hàm cho hành động tùy ý là một chút vụng về 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 một withcâu lệnh để xử lý tài nguyên an toàn. Xem Làm thế nào để tôi dọn sạch chính xác một đối tượng Python? để biết thêm chi tiết.


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

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

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

15
Ví dụ ruby ​​của bạn trong # 4 không phải là thành ngữ. Nó sẽ là ruby-ish (và dễ đọc) hơn để viết values.map{|v| v*v if v > 15}.compact. IMHO, điều này thậm chí còn biểu cảm hơn (và chắc chắn rõ ràng hơn) so với ví dụ về con trăn của bạn.
sml

10
Ngoài việc trên, sử dụng! phiên bản của hàm compact tránh một bản sao của mảng : values.map{|v| v*v if v > 15}.compact!. Điều này có nghĩa là chỉ có danh sách đầu vào và danh sách kết quả tồn tại trong bộ nhớ. Xem # 4 tại đây: igvita.com/2008/07/08/6-optimization-tips-for-ruby-mri
sml

27

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

Tôi hy vọng điều này sẽ giúp: 'Sự xấu xí' của Python

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

  • Tất cả các tính năng lập trình chức năng mà bạn sử dụng trong Ruby là ở Python và thậm chí còn dễ dàng hơn nữa. Ví dụ: bạn có thể ánh xạ các chức năng chính xác như bạn mong đợi:

    def f(x):
        return x + 1
    
    map(f, [1, 2, 3]) # => [2, 3, 4]
  • Python không có một phương thức hoạt động như thế each. Vì bạn chỉ sử dụng eachcho các hiệu ứng phụ, tương đương trong Python là vòng lặp for:

    for n in [1, 2, 3]:
        print n
  • Khả năng hiểu danh sách là rất tốt khi a) bạn phải xử lý các hàm và bộ sưu tập đối tượng cùng 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 palindrome trong một chuỗi (giả sử bạn có một hàm p()trả về true cho palindromes), tất cả những gì bạn cần là một sự hiểu biết danh sách 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
Thở dài, tôi đọc bài đăng đó và nó xác nhận sự nghi ngờ của tôi: ít người hiểu được vai trò và tiện ích của các phương thức đặ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 dung mà chúng thường thực hiện. Không ai thực sự biết Python đang cố gắng ngăn cản việc sử dụng chúng.
Rafe Kettler

5
Bạn dường như không hiểu làm thế nào các phương pháp làm việc. Về cơ bản, một phương thức là 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à "không ràng buộc" và đối số đầu tiên phải là một Classthể hiện; Khi bạn viết object.method, phương thức được "ràng buộc" với objectthể hiện của Class. Điều này cho phép bạn chọn sử dụng bản đồ (v.v.) để gọi phương thức trên một trường hợp khác nhau mỗi lần (truyền một phương thức không liên kết) hoặc để giữ cho cá thể cố định và truyề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!
David J.

10
[s[x:y] for x in range(l) for y in range(x,l+1) if p(s[x:y])]- dòng này cho thấy Python khó đọc như thế nào. Khi bạn đọc mã Ruby, bạn di chuyển mắt từ trái sang phải mà không cần quay lại. Nhưng để đọc mã Python, bạn cần đi sang trái-phải-trái-phải-trái-phải ... và dấu ngoặc đơn, dấu ngoặc đơn, dấu ngoặc đơn, dấu ngoặc đơn ... Ngoài ra, trong Python bạn thường cần trộn lẫn các phương thức và hàm. Thật điên rồ: E(C(A.B()).D())thay vì Ruby'sA.B.C.D.E
Nakilon

2
@Nakilon Đó là lý do tại sao bạn chỉ nên sử dụng cách hiểu danh sách lồng nhau cho các trường hợp thực sự đơn giản, và không giống như trên. Có thể là 'thông minh' khi viết một lớp lót tìm thấy tất cả các palindromes trong một chuỗi, nhưng nó được dành riêng cho golf mã. Đối với mã thực mà người khác phải đọc sau này, bạn sẽ chỉ viết một vài hàm dòng. Vì vậy, có, dòng đó khó đọc, nhưng đó là lỗi của lập trình viên, không phải ngôn ngữ.
Cam Jackson

10

Đề nghị 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 đề trong Python. Giống như cách tiếp cận của Ruby đối với từng vấn đề (hoạt động rất tốt với những hạn chế và điểm mạnh của ngôn ngữ), có một cách tiếp cận Python đối với vấn đề. cả hai đều khác nhau Để tận dụng tốt nhất từng ngôn ngữ, bạn thực sự nên 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 đó, sự khác biệt sẽ giúp bạn thích nghi nhanh hơn và thực hiện 1 sửa đổi cho chương trình Python. Và đó là tốt để bắt đầu viết. Nhưng hãy cố gắng học hỏi từ các dự án khác tại sao đằng sau các quyết định về kiến ​​trúc và thiết kế hơn là cách thức đằng sau ngữ nghĩa của ngôn ngữ ...


7
Tôi đánh giá cao đề nghị của bạn. Tôi hoàn toàn đồng ý với tình cảm (mà tôi diễn giải là "Học cách lập trình Python thành ngữ") . Đó chính xác là những gì tôi đang cố gắng làm. Tôi không hỏi "Tên Python cho eachphương thức của Ruby là gì?" Tôi đang 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 thực hiện đúng như thế nào?" Nếu Python falsethực sự False, thì điều quan trọng là phải biết tôi nên làm mọi thứ theo cách nào và khi nào tôi không nên làm.
Phrogz

2
@Phrogz: Thật công bằng. Cách tôi diễn giải câu hỏi của bạn là: Hãy tạo một danh sách về sự khác biệt để chúng ta có thể thay đổi ngôn ngữ mà chúng ta đ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 sẽ rất thú vị để xem những gì khác sẽ xuất hiện ...
ircmaxell

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

8

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

  • nil, giá trị biểu thị thiếu giá trị, sẽ là None(lưu ý rằng bạn kiểm tra xem nó có giống x is Nonehay x is not Nonekhông, với== hoặc bằng cách ép buộc đối với boolean, xem điểm tiếp theo).
  • None, Zero-esque số ( 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.
  • Đối với các tác dụng phụ, ( for-) vòng lặp 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ụ, hãy sử dụng cách hiểu danh sách (hoặc người thân của chúng - biểu thức trình tạo cho các trình lặp một lần lười biếng, đọc chính tả / thiết lập 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 vòng lặp (! Không tính), và while, đó là những gì bạn mong đợi. Các fromer 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 trình vòng lặp thay vì danh sách là một trình vòng lặp (í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 vòng lặp - ziplặp đi lặp lại bất kỳ số lần lặp song song nào, enumeratemang lại cho bạn (index, item)(trên bất kỳ lần lặp nào , không chỉ trong danh sách), thậm chí cắt các lần 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 đơn giản hơn nhiều. Không cần phải nói, họ tích hợp tốt với việc 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 là mát mẻ. Chúng cung cấp cho Python một chút khả năng đánh giá lười biếng của các ngôn ngữ như Haskell.
Clint Miller

@Clint: Vâng. 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, điều này xảy ra chiếm đa số).

Tại sao bạn kiểm tra với x is Nonehoặc x is not None? Tôi luôn luôn kiểm tra với x == Nonex != None.
John

@ John: Nếu xđịnh nghĩa __eq__một cách ngớ ngẩn, nó có thể cho kết quả dương tính giả. Nếu __eq__không được lập trình đủ cẩn thận, nó có thể bị sập (ví dụ AttributeError) khi được cung cấp một số giá trị nhất định (nghĩa là None). Ngược lại, iskhông thể bị ghi đè - nó luôn so sánh danh tính đối tượng, đó là cách đúng (mạnh mẽ nhất, đơn giản nhất và sạch nhất) để kiểm tra đơn lẻ.

1
@John. "X là Không" là cách hoàn toàn thành ngữ để làm điều đó. python.net/~goodger/projects/pycon/2007/idiomatic/handout.html
tokland

6

Trong Ruby, các biến và phương thức thể hiện hoàn toàn không liên quan, ngoại trừ khi bạn liên kết rõ ràng với attr_accessor hoặc một cái gì đó 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í dụ:

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

Sự khác biệt đó có rất nhiều hàm ý, ví dụ như việc đề cập đến fx đề cập đến đối tượng phương thức, thay vì gọi nó. Ngoài ra, như bạn có thể thấy, fx được công khai theo mặc định, trong khi trong Ruby, các biến thể hiện là riêng tư theo mặc định.


2
Trên thực tế, tôi nói rõ hơn nữa: trong Python, các phương thức chỉ là một loại thuộc tính cụ thể, trong khi trong Ruby, các thuộc tính chỉ là một loại 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ữ nằm ngoài điều này: Các hàm hạng nhất trong Python và Nguyên tắc truy cập thống nhất trong Ruby
triết học
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.