Ruby'den Python Öğrenmek; Farklılıklar ve Benzerlikler


131

Ruby'yi çok iyi tanırım. Şu anda Python öğrenmem gerekebileceğine inanıyorum. Her ikisini de bilenler için, ikisi arasında hangi kavramlar benzer ve farklı olan nedir?

JavaScripters için Lua'yı Öğrenmek için yazdığım bir öncüle benzer bir liste arıyorum : boşluk önemi ve döngü yapıları gibi basit şeyler; nilPython'daki adı ve hangi değerlerin "doğru" kabul edildiği; o eşdeğer kullanmak deyimseldir mapve eachya vardır mırıl somethingaboutlistcomprehensions Mumble norm?

Çok çeşitli yanıtlar alırsam, bunları bir topluluk wiki'sinde toplamaktan mutluluk duyarım. Ya da hepiniz tek bir gerçek kapsamlı liste oluşturmaya çalışmak için birbirinizle savaşabilir ve beşik atabilirsiniz.

Düzenleme : Açık olmak gerekirse, amacım "uygun" ve deyimsel Python. Bir Python eşdeğeri varsa inject, ancak kimse onu kullanmıyorsa, bir listeyi yinelemenin ve yol boyunca bir sonuç toplamanın ortak işlevselliğini elde etmenin daha iyi / farklı bir yolu varsa, işleri nasıl yaptığınızı bilmek istiyorum. Belki bu soruyu ortak hedeflerin bir listesiyle, bunları Ruby'de nasıl elde ettiğinizi ve Python'da karşılığının ne olduğunu sorarak güncelleyeceğim.


1
Okuduğum tek şey c2.com/cgi/wiki? PythonVsRuby idi , gerçekten kendimi ve girintileri sevmiyorum ama alıştım :)
Saif al Harthi

1
İlgili: stackoverflow.com/questions/1113611/… (Bu soru eşdeğeri olmayan şeyleri sorduğundan, kopya olup olmadığından tam olarak emin değilim).

19
@SilentGhost Kesinlikle katılmıyorum. "Diller arasında aynı ve farklı olan nedir?" Diye soruyorum. Aşağıdaki cevapların çoğunda gösterildiği gibi, bunun için çok açık ve faydalı cevaplar var.
Phrogz

3
@Phrogz: Bunu görüyorum ve soruyu cevapsız kılıyor.
SilentGhost

2
@Phrongz - Gönderdiğiniz meta konu hakkında söylediklerimi tekrarlamak için, bu sorudaki sorun, sorun alanının çok büyük olmasıdır - bu konu yalnızca bir soru için çok büyük. İki dil arasında binlerce fark var.
Adam Davis

Yanıtlar:


153

İşte benim için bazı önemli farklılıklar:

  1. Ruby'de bloklar vardır; Python yapmaz.

  2. Python'un işlevleri vardır; Ruby yapmaz. Python'da, herhangi bir işlevi veya yöntemi alıp başka bir işleve geçirebilirsiniz. Ruby'de her şey bir yöntemdir ve yöntemler doğrudan aktarılamaz. Bunun yerine, onları geçmek için Proc'lara sarmanız gerekir.

  3. Ruby ve Python, kapanışları destekler, ancak farklı şekillerde. Python'da, başka bir işlevin içinde bir işlev tanımlayabilirsiniz. İç işlevin dış işlevdeki değişkenlere okuma erişimi vardır, ancak yazma erişimi yoktur. Ruby'de, blokları kullanarak kapanışları tanımlarsınız. Kapanışlar, dış kapsamdaki değişkenlere tam okuma ve yazma erişimine sahiptir.

  4. Python, oldukça etkileyici olan liste anlayışlarına sahiptir. Örneğin, bir numara listeniz varsa, yazabilirsiniz

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

    15'ten büyük tüm değerlerin karelerinin yeni bir listesini almak için Ruby'de aşağıdakileri yazmanız gerekir:

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

    Ruby kodu kompakt görünmüyor. Ayrıca, değerler dizisini ilk önce 15'ten büyük değerleri içeren daha kısa bir ara diziye dönüştürdüğü için de o kadar verimli değildir. Ardından, ara diziyi alır ve ara ürünlerin karelerini içeren son bir dizi oluşturur. Ara dizi daha sonra atılır. Dolayısıyla, Ruby hesaplama sırasında bellekte 3 dizi ile sonuçlanır; Python yalnızca giriş listesine ve sonuç listeye ihtiyaç duyar.

    Python ayrıca benzer harita anlayışları sağlar.

  5. Python tupleları destekler; Ruby yapmaz. Ruby'de tupleları simüle etmek için dizileri kullanmanız gerekir.

  6. Ruby anahtar / durum ifadelerini destekler; Python yapmaz.

  7. Ruby standart expr ? val1 : val2üçlü operatörü destekler ; Python yapmaz.

  8. Ruby yalnızca tek kalıtımı destekler. Birden çok kalıtımı taklit etmeniz gerekiyorsa, modülleri tanımlayabilir ve modül yöntemlerini sınıflara çekmek için karışımları kullanabilirsiniz. Python, modül karışımları yerine çoklu kalıtımı destekler.

  9. Python yalnızca tek satırlı lambda işlevlerini destekler. Bir çeşit lambda işlevi olan Ruby blokları, keyfi olarak büyük olabilir. Bu nedenle, Ruby kodu genellikle Python kodundan daha işlevsel bir tarzda yazılır. Örneğin, Ruby'de bir liste üzerinde döngü yapmak için genellikle

    collection.each do |value|
      ...
    end

    Blok, aktarılan bir işlev gibi çalışır collection.each. Aynı şeyi Python'da yapacak olsaydınız, adlandırılmış bir iç işlev tanımlamanız ve ardından bunu her yöntemi koleksiyona iletmeniz gerekir (liste bu yöntemi destekliyorsa):

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

    Bu pek hoş akmıyor. Bu nedenle, tipik olarak aşağıdaki işlevsel olmayan yaklaşım Python'da kullanılacaktır:

    for value in collection:
      ...
  10. Kaynakları güvenli bir şekilde kullanmak iki dil arasında oldukça farklıdır. Burada sorun, bir miktar kaynak ayırmak (bir dosya açmak, bir veritabanı imleci elde etmek, vb.), Üzerinde rastgele bazı işlemler gerçekleştirmek ve ardından bir istisna oluşsa bile onu güvenli bir şekilde kapatmak istemenizdir.

    Ruby'de, blokların kullanımı çok kolay olduğundan (bkz. # 9), genellikle bu kalıbı, kaynakta keyfi işlemin gerçekleştirilmesi için bir blok alan bir yöntem olarak kodlarsınız.

    Python'da, rastgele eylem için bir işlev aktarmak, adlandırılmış, içsel bir işlev yazmanız gerektiğinden biraz daha zordur (bkz. # 9). Bunun yerine Python, withgüvenli kaynak işleme için bir ifade kullanır . Bkz nasıl doğru bir Python nesne temizlemek mi? daha fazla ayrıntı için.


2
3. Python 3 bunu nonlocaldüzeltir 4. Python ayrıca size üreteç ifadeleri verir (liste anlamalarına benzer, ancak listsorulana kadar hiçbir şey hesaplamayın - liste anlamalarını, beslenen oluşturucu ifadeleri olarak düşünün (bu, yinelenebilir ve her şeyi içeren bir liste döndürür) yinelenebilir) - bu, bazı durumlarda çok fazla çaba tasarrufu sağlayabilir).

25
7. Evet öyle. val1 if expr else val2. 8. Bunun çoğunlukla mixin tarzı büyütme için kullanıldığını görmeme rağmen.

2
@ClintMiller Whoa, anahtar / durum yok mu? Öyleyse, Python'da benzer işlevselliği elde etmenin önerilen yolu nedir? if / else if /?
Phrogz

15
# 4'teki ruby ​​örneğiniz deyimsel değil. Yazmak daha yakutsu (ve okunaklı) olurdu values.map{|v| v*v if v > 15}.compact. IMHO, bu sizin python örneğinizden daha etkileyici (ve kesinlikle daha açık).
sml

10
Yukarıdakilere ek olarak,! Kompakt fonksiyonun versiyonu dizisinin bir kopyasını önler: values.map{|v| v*v if v > 15}.compact!. Bu, bellekte yalnızca girdi listesinin ve sonuç listesinin var olduğu anlamına gelir. Burada # 4'e bakın: igvita.com/2008/07/08/6-optimization-tips-for-ruby-mri
sml

27

6 yıllık Ruby'den sonra Python öğrenmek için birkaç ay harcadım. İki dil arasında gerçekten harika bir karşılaştırma yoktu, bu yüzden kendim bir tane oluşturup yazmaya karar verdim. Şimdi, bir çoğunlukla fonksiyonel programlama ile ilgili, ancak Ruby'nin söz beri injectyöntemini, biz aynı dalga boyunda olduğunu tahmin ediyorum.

Umarım bu yardımcı olur: Python'un 'çirkinliği'

Doğru yönde ilerlemenizi sağlayacak birkaç nokta:

  • Ruby'de kullandığınız tüm işlevsel programlama iyiliği Python'da ve daha da kolay. Örneğin, tam olarak beklediğiniz gibi işlevleri eşleyebilirsiniz:

    def f(x):
        return x + 1
    
    map(f, [1, 2, 3]) # => [2, 3, 4]
  • Python'un bunun gibi davranan bir yöntemi yoktur each. Yalnızca eachyan etkiler için kullandığınızdan , Python'daki eşdeğeri for döngüsüdür:

    for n in [1, 2, 3]:
        print n
  • Liste anlayışları, a) işlevler ve nesne koleksiyonlarıyla birlikte uğraşmanız gerektiğinde ve b) birden çok dizin kullanarak yinelemeniz gerektiğinde harikadır. Örneğin, bir dizedeki tüm palindromları bulmak p()için (palindromlar için true döndüren bir işleve sahip olduğunuzu varsayarak ), ihtiyacınız olan tek şey tek bir liste anlayışıdır:

    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
Ah, o yazıyı okudum ve şüphelerimi doğruluyor: çok az kişi özel yöntemlerin Python'daki rolünü ve faydasını anlıyor. İnanılmaz derecede kullanışlı ve standartlaştırılmışlar ve sıklıkla uyguladıkları yerleşiklerle çatışmaları adlandırmaktan kaçınmak için bu şekilde altı çiziliyorlar. Python'u gerçekten bilen hiç kimse kullanımlarını caydırmaya çalışmıyor.
Rafe Kettler

5
Yöntemlerin nasıl çalıştığını anlamıyor gibisin. Bir yöntem, esasen, ilk argümanı yöntemin ait olduğu sınıfın bir örneği olan bir işlevdir. Yazdığınızda Class.method, yöntem "ilişkisizdir" ve ilk argüman bir Classörnek olmalıdır ; yazdığınızda object.method, yöntem objectörneğine "bağlıdır" Class. Bu, yöntemi her seferinde bir fark örneğinde çağırmak için (ilişkisiz bir yöntem iletmek) veya örneği sabit tutmak ve her seferinde farklı bir ikinci bağımsız değişken geçirmek için eşlemeyi (vb.) Kullanıp kullanmamayı seçmenize olanak tanır. İkisi de faydalıdır.
LaC

2
Haklısın, nasıl çalıştıklarını anlamadım. Makaleyi yayınladığımdan beri, onu daha iyi anladım. Teşekkürler!
David J.

10
[s[x:y] for x in range(l) for y in range(x,l+1) if p(s[x:y])]- bu satır Python'un okumanın ne kadar zor olduğunu gösterir. Ruby kodunu okuduğunuzda, geri dönüşler olmadan gözlerinizi soldan sağa kaydırırsınız. Ancak Python kodunu okumak için, sol-sağ-sol-sağ-sol-sağa gitmeniz gerekir ... ve parantezler, parantezler, parantezler, parantezler ... Ayrıca Python'da genellikle yöntemlerin ve işlevin karıştırılmasına ihtiyaç duyarsınız. Bu delilik: E(C(A.B()).D())yerine Ruby'ninA.B.C.D.E
Nakilon

2
@Nakilon Bu yüzden iç içe geçmiş liste anlamalarını sadece gerçekten basit durumlar için kullanmalısınız, yukarıdakiler gibi değil. Bir dizedeki tüm palindromları bulan tek satırlık bir yazı yazmak 'akıllı' olabilir, ancak en iyisi kod golfü için ayrılmıştır. Bir başkasının daha sonra okuması gereken gerçek kod için, sadece birkaç satırlık fonksiyon yazarsınız. Yani evet, bu satırı okumak zor, ama bu dilin değil, programcının hatası.
Cam Jackson

10

Benim önerim: Farklılıkları öğrenmeye çalışmayın. Python'da soruna nasıl yaklaşılacağını öğrenin. Tıpkı her soruna bir Ruby yaklaşımı olduğu gibi (dilin sınırlarını ve güçlü yönlerini çok iyi işleyen), soruna bir Python yaklaşımı var. ikisi de farklı. Her dilden en iyi şekilde yararlanmak için, sadece birinden diğerine "çeviri" yi değil, gerçekten dilin kendisini öğrenmelisiniz.

Şimdi, bununla birlikte, fark daha hızlı adapte olmanıza ve bir Python programına 1 defalık değişiklikler yapmanıza yardımcı olacaktır. Ve yazmaya başlamak için sorun değil. Ancak dilin anlambiliminin ardında yatan nedenlerden çok, mimari ve tasarım kararlarının nedenini diğer projelerden öğrenmeye çalışın ...


7
Önerin için minnettarım. Bu düşünceye tamamen katılıyorum ("Deyimsel Python'u programlamayı öğrenin" olarak yorumluyorum) . Ben de tam olarak bunu yapmaya çalışıyorum. "Ruby'nin eachyönteminin Python adı nedir ?" Diye sormuyorum. "Python'da işler nasıl düzgün bir şekilde Ruby'den farklıdır ve nerede düzgün bir şekilde aynı şekilde yapılır?" Diye soruyorum. Eğer Python'unki falsegerçekten ise False, bu, işleri Rubyesk bir şekilde nerede ve ne zaman yapmam gerektiğini ve nerede ve ne zaman yapmamam gerektiğini bilmek kadar önemlidir.
Phrogz

2
@Phrogz: Bu adil. Sorunuzu yorumlama şeklim şuydu: Farklılıkların bir listesini yapalım, böylece programlama yaptığımız dili değiştirebiliriz . Ama bu adil bir soru. Sanırım ne istediğini yanlış yorumladım. Bunu referans için burada bırakacağım, ancak başka ne olacağını görmek ilginç olacak ...
ircmaxell

Python ve Ruby'yi aynı anda öğreniyorum ve web uygulaması geliştirmede farklılıktan daha fazla benzerlik görüyorum.
WesternGun

8

Küçük Ruby'yi tanıyorum, ama işte bahsettiğiniz şeyler hakkında birkaç madde işareti:

  • nil, bir değerin eksikliğini gösteren değer şöyle olacaktır None(bunun gibi x is Noneveya x is not Nonedeğil ==- veya boolean'a zorlayarak, bir sonraki noktaya bakın).
  • NoneSıfır-vari sayılar ( 0, 0.0, 0j(karmaşık sayı)) ve boş koleksiyonları ( [], {}, set(), boş dize "", vb) falsy, her şey kabul edilir truthy kabul edilir.
  • Yan etkiler için, ( for-) açıkça döngü yapın. Yan etkileri olmayan yeni bir şeyler oluşturmak için liste anlayışlarını (veya akrabalarını - tembel tek seferlik yineleyiciler için oluşturucu ifadeleri, söz konusu koleksiyonlar için dikte / set anlayışları) kullanın.

Döngü ile ilgili olarak: forYinelenebilir (! Sayma yok) üzerinde çalışan ve whilebeklediğiniz şeyi yapan var. Iner, yineleyiciler için kapsamlı destek sayesinde çok daha güçlü. Bir liste yerine yineleyici olabilecek neredeyse her şey bir yineleyici değildir (en azından Python 3'te - Python 2'de, her ikisine de sahipsiniz ve maalesef varsayılan bir listedir). Adım adım elde çalışmak için çok sayıda araç vardır - zipparalel Iterables herhangi bir sayıda yinelenir enumerateverir (index, item)(üzerinde herhangi hatta abritary (muhtemelen büyük veya sonsuz) Iterables dilimleme, değil, sadece listelerde iterable)! Bunların birçok döngü görevini çok daha basit hale getirdiğini buldum. Söylemeye gerek yok, liste anlayışları, üreteç ifadeleri vb. İle gayet iyi bütünleşiyorlar.


2
Jeneratör ifadeleri harika. Python'a Haskell gibi dillerin biraz tembel değerlendirme yeteneklerini veriyorlar.
Clint Miller

@Clint: Evet. Ve tam üreteçler daha da yeteneklidir (çoğunluk olan basit durumlar için gerekli olmasa da).

Neden x is Noneveya ile kontrol ediyorsunuz x is not None? Her zaman x == Noneve ile kontrol ederim x != None.
John

@John: Aptalca bir şekilde xtanımlarsa __eq__, yanlış bir pozitif verebilir. Eğer __eq__yeterince dikkatli programlanmış edilmez, (örneğin kaza olabilir AttributeError(yani) verilen bazı değerleri None). Aksine, isgeçersiz kılınamaz - her zaman nesne kimliğini karşılaştırır; bu, bir tekli tonu kontrol etmenin doğru (en sağlam, en basit ve en temiz) yoludur.

1
@John. "x Yoktur" bunu yapmanın kesinlikle deyimsel yoludur. python.net/~goodger/projects/pycon/2007/idiomatic/handout.html
tokland

6

Ruby'de, örnek değişkenleri ve yöntemler, bunları attr_accessor veya bunun gibi bir şeyle açıkça ilişkilendirdiğiniz durumlar dışında tamamen birbiriyle ilişkisizdir.

Python'da, yöntemler yalnızca özel bir nitelik sınıfıdır: çalıştırılabilir nitelikte.

Yani mesela:

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

Bu farkın birçok sonucu vardır, örneğin fx'e atıfta bulunmak, onu çağırmak yerine yöntem nesnesine atıfta bulunur. Ayrıca, görebileceğiniz gibi fx varsayılan olarak geneldir, oysa Ruby'de örnek değişkenleri varsayılan olarak özeldir.


2
Aslında bunu daha da açık bir şekilde ifade ederim: Python'da yöntemler sadece belirli bir niteliktir, Ruby'de ise nitelikler sadece belirli bir yöntem türüdür. İki dil arasındaki bazı önemli zıt özellikler bunun dışında
kalıyor
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.