簡體   English   中英

從Ruby學習Python; 異同

[英]Learning Python from Ruby; Differences and Similarities

我非常了解 Ruby。 我相信我現在可能需要學習 Python。 對於兩者都了解的人來說,兩者之間有哪些相似的概念,又有哪些不同?

我正在尋找一個類似於我為 JavaScript 用戶學習 Lua所寫的入門書的列表:簡單的東西,比如空格意義和循環結構; Python 中nil的名稱,以及哪些值被認為是“真實的”; 使用mapeach的等價物是慣用的,還是mumble somethingaboutlistcomprehensions嘟嘟囔囔規范?

如果我得到各種各樣的答案,我很高興將它們匯總到社區 wiki 中。 否則,你們都可以互相爭斗,互相競爭,試圖創建一個真正的綜合列表。

編輯:明確地說,我的目標是“正確的”和慣用的 Python。 如果有一個 Python 等價物inject ,但沒有人使用它,因為有更好/不同的方法來實現迭代列表並在此過程中累積結果的通用功能,我想知道你是如何做事的。 也許我會用一個常見目標列表來更新這個問題,你如何在 Ruby 中實現它們,並詢問 Python 中的等價物是什么。

以下是我認為的一些主要區別:

  1. Ruby 有塊; Python 沒有。

  2. Python有函數; 紅寶石沒有。 在 Python 中,您可以將任何函數或方法傳遞給另一個函數。 在Ruby中,一切都是方法,方法不能直接傳遞。 相反,您必須將它們包裝在 Proc 中才能傳遞它們。

  3. Ruby 和 Python 都支持閉包,但方式不同。 在 Python 中,您可以在另一個函數中定義一個函數。 內部函數對外部函數的變量有讀訪問權限,但沒有寫訪問權限。 在 Ruby 中,您可以使用塊來定義閉包。 閉包具有對外部作用域變量的完全讀寫訪問權限。

  4. Python 具有列表推導式,非常具有表現力。 例如,如果你有一個數字列表,你可以寫

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

    要獲得所有大於 15 的值的平方的新列表。在 Ruby 中,您必須編寫以下內容:

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

    Ruby 代碼感覺沒有那么緊湊。 它也沒有那么高效,因為它首先將值數組轉換為包含大於 15 的值的較短的中間數組。然后,它采用中間數組並生成包含中間值平方的最終數組。 然后將中間數組拋出。 因此,Ruby 在計算過程中最終在內存中擁有 3 個數組; Python 只需要輸入列表和結果列表。

    Python 還提供了類似的地圖理解。

  5. Python 支持元組; 魯比沒有。 在 Ruby 中,您必須使用數組來模擬元組。

  6. Ruby 支持 switch/case 語句; Python 沒有。

  7. Ruby 支持標准的expr ? val1 : val2 expr ? val1 : val2三元運算符; Python 沒有。

  8. Ruby 僅支持單繼承。 如果您需要模擬多重繼承,您可以定義模塊並使用 mix-ins 將模塊方法拉入類中。 Python 支持多重繼承而不是模塊混合。

  9. Python 僅支持單行 lambda 函數。 Ruby 塊是一種/某種 lambda 函數,可以任意大。 正因為如此,Ruby 代碼通常以比 Python 代碼更具功能性的風格編寫。 例如,要在 Ruby 中遍歷列表,您通常會這樣做

    collection.each do |value| ... end

    該塊的工作方式非常類似於傳遞給collection.each的函數。 如果你要在 Python 中做同樣的事情,你必須定義一個命名的內部函數,然后將它傳遞給每個方法的集合(如果列表支持這個方法):

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

    這不是很好地流動。 因此,通常會在 Python 中使用以下非函數式方法:

     for value in collection: ...
  10. 兩種語言以安全的方式使用資源是完全不同的。 這里的問題是你想分配一些資源(打開文件、獲取數據庫游標等),對其執行一些任意操作,然后即使發生異常也以安全的方式關閉它。

    在 Ruby 中,由於塊非常易於使用(參見 #9),您通常將此模式編碼為一種方法,該方法采用塊來對資源執行任意操作。

    在 Python 中,為任意操作傳入函數有點笨拙,因為您必須編寫一個命名的內部函數(請參閱 #9)。 相反,Python 使用with語句來進行安全的資源處理。 請參閱如何正確清理 Python 對象? 了解更多詳情。

我和你一樣,在學習 Python 時尋找了inject和其他函數式方法。 我很失望地發現它們並不都在那里,或者 Python 喜歡命令式方法。 也就是說,如果您看一下,大多數構造都在那​​里。 在某些情況下,圖書館會讓事情變得更好。

對我來說有幾個亮點:

  • 您從 Ruby 中了解到的函數式編程模式可在 Python 中使用。 他們只是看起來有點不同。 例如,有一個 map 函數:

     def f(x): return x + 1 map(f, [1, 2, 3]) # => [2, 3, 4]

    同樣,有一個reduce函數來折疊列表等。

    也就是說,Python 缺少塊,並且沒有用於鏈接或組合函數的流線型語法。 (要在沒有塊的情況下做到這一點的好方法,請查看 Haskell 的豐富語法。)

  • 出於某種原因,Python 社區似乎更喜歡命令式迭代來處理在 Ruby 中無需更改即可完成的事情。 例如,折疊(即inject )通常使用命令式for循環而不是reduce

     running_total = 0 for n in [1, 2, 3]: running_total = running_total + n

    這不僅僅是一個約定,它也得到了 Python 維護者的加強。 例如, Python 3 發行說明明確支持for循環而不是reduce

    如果確實需要,請使用functools.reduce() 但是,在 99% 的情況下,顯式for循環更具可讀性。

  • 列表推導式是表達復雜函數操作的一種簡潔方式(類似於 Haskell 的列表 monad)。 這些在 Ruby 中不可用,在某些情況下可能會有所幫助。 例如,用於查找字符串中所有回文的強力單行(假設您有一個函數p()為回文返回 true)看起來像這樣:

     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])]
  • 在許多情況下,Python 中的方法可以被視為上下文無關函數,這是您必須在 Ruby 中習慣的東西,但可能非常強大。

如果這有幫助,我在 2011 年在這里寫了更多的想法: Python 的“丑陋” 鑒於當今對 ML 的關注,它們可能需要更新。

我的建議:不要試圖學習差異。 了解如何在 Python 中解決問題。 就像每個問題都有一種 Ruby 方法(考慮到語言的局限性和優勢,這種方法非常有效),也有一種 Python 方法可以解決這個問題。 他們都是不同的。 為了充分利用每種語言,您確實應該學習語言本身,而不僅僅是從一種語言到另一種語言的“翻譯”。

現在,話雖如此,差異將幫助您更快地適應,並對 Python 程序進行 1 次修改。 這對於開始寫作來說很好。 但是嘗試從其他項目中了解架構和設計決策背后的原因,而不是語言語義背后的原因……

我知道一點 Ruby,但這里有一些關於你提到的事情的要點:

  • nil ,表示缺少值的值,將是None (請注意,您檢查它就像x is Nonex is not None ,不使用== - 或強制轉換為布爾值,請參閱下一點)。
  • None 、零式數字( 00.00j (復數))和空集合( []{}set() 、空字符串""等)被認為是假的,其他一切都被認為是真。
  • 對於副作用,( for -) 顯式循環。 為了生成一堆沒有副作用的新東西,請使用列表推導(或它們的親戚 - 惰性一次性迭代器的生成器表達式,所述集合的字典/集合推導)。

關於循環:你有for ,它在一個可迭代(!不計數)上運行,而while ,它做你所期望的。 由於對迭代器的廣泛支持, fromer 更加強大。 不僅幾乎所有可以是迭代器而不是列表的東西都是迭代器(至少在 Python 3 中 - 在 Python 2 中,您兩者都有,遺憾的是默認值是列表)。 使用迭代器的眾多工具 - zip並行迭代任意數量的可迭代對象, enumerate為您提供(index, item) (在任何可迭代對象上,而不僅僅是在列表上),甚至切片 abritary(可能很大或無限)可迭代對象! 我發現這些使許多循環任務變得更加簡單。 不用說,它們與列表推導式、生成器表達式等集成得很好。

在 Ruby 中,實例變量和方法是完全不相關的,除非你明確地將它們與 attr_accessor 或類似的東西相關聯。

在 Python 中,方法只是一類特殊的屬性:可執行的。

例如:

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

這種差異有很多含義,例如,引用 fx 是指方法對象,而不是調用它。 此外,如您所見,fx 默認是公開的,而在 Ruby 中,實例變量默認是私有的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM