Apa yang dimiliki Ruby yang tidak dimiliki Python, dan sebaliknya?


263

Ada banyak diskusi tentang Python vs Ruby, dan saya semua menganggapnya sama sekali tidak membantu, karena mereka semua berbalik mengapa fitur X menyebalkan dalam bahasa Y, atau bahwa bahasa klaim Y tidak memiliki X, meskipun kenyataannya memang demikian. Saya juga tahu persis mengapa saya lebih suka Python, tetapi itu juga subjektif, dan tidak akan membantu siapa pun memilih, karena mereka mungkin tidak memiliki selera yang sama dalam pengembangan seperti saya.

Oleh karena itu, akan menarik untuk membuat daftar perbedaan secara obyektif. Jadi tidak ada "lambda Python menyebalkan". Alih-alih jelaskan apa yang lambda Ruby bisa lakukan yang tidak bisa dilakukan Python. Tidak ada subjektivitas. Kode contoh itu bagus!

Jangan memiliki beberapa perbedaan dalam satu jawaban. Dan pilih yang Anda tahu benar, dan turunkan yang Anda tahu salah (atau subjektif). Selain itu, perbedaan sintaksis juga tidak menarik. Kita tahu Python melakukan indentasi seperti yang dilakukan Ruby dengan tanda kurung dan ujung, dan @ disebut self dalam Python.

PEMBARUAN: Sekarang ini adalah wiki komunitas, jadi kami dapat menambahkan perbedaan besar di sini.

Ruby memiliki referensi kelas di badan kelas

Di Ruby Anda memiliki referensi ke kelas (diri) yang sudah ada di badan kelas. Dengan Python, Anda tidak memiliki referensi ke kelas sampai konstruksi kelas selesai.

Sebuah contoh:

class Kaka
  puts self
end

self dalam hal ini adalah kelas, dan kode ini akan mencetak "Kaka". Tidak ada cara untuk mencetak nama kelas atau dengan cara lain mengakses kelas dari badan definisi kelas dengan Python (definisi metode luar).

Semua kelas bisa berubah di Ruby

Ini memungkinkan Anda mengembangkan ekstensi ke kelas inti. Berikut adalah contoh ekstensi rel:

class String
  def starts_with?(other)
    head = self[0, other.length]
    head == other
  end
end

Python (bayangkan tidak ada ''.startswithmetode):

def starts_with(s, prefix):
    return s[:len(prefix)] == prefix

Anda bisa menggunakannya di urutan apa pun (bukan hanya string). Untuk menggunakannya, Anda harus mengimpornya secara eksplisit misalnya from some_module import starts_with,.

Ruby memiliki fitur scripting seperti Perl

Ruby memiliki regexps kelas satu, $ -variables, awk / perl baris demi baris input loop dan fitur lain yang membuatnya lebih cocok untuk menulis skrip shell kecil yang munge file teks atau bertindak sebagai kode perekat untuk program lain.

Ruby memiliki kelanjutan kelas satu

Berkat pernyataan callcc. Di Python Anda dapat membuat kelanjutan dengan berbagai teknik, tetapi tidak ada dukungan bawaan untuk bahasa tersebut.

Ruby memiliki blok

Dengan pernyataan "do" Anda dapat membuat fungsi anonim multi-baris di Ruby, yang akan diteruskan sebagai argumen ke metode di depan do, dan dipanggil dari sana. Di Python, Anda akan melakukan ini baik dengan meneruskan metode atau dengan generator.

Rubi:

amethod { |here|
    many=lines+of+code
    goes(here)
}

Python (blok Ruby sesuai dengan konstruksi berbeda di Python):

with amethod() as here: # `amethod() is a context manager
    many=lines+of+code
    goes(here)

Atau

for here in amethod(): # `amethod()` is an iterable
    many=lines+of+code
    goes(here)

Atau

def function(here):
    many=lines+of+code
    goes(here)

amethod(function)     # `function` is a callback

Menariknya, pernyataan kemudahan di Ruby untuk memanggil sebuah blok disebut "yield", yang dalam Python akan membuat generator.

Rubi:

def themethod
    yield 5
end

themethod do |foo|
    puts foo
end

Python:

def themethod():
    yield 5

for foo in themethod():
    print foo

Meskipun prinsipnya berbeda, hasilnya sangat mirip.

Ruby mendukung pemrograman gaya fungsional (seperti pipa) dengan lebih mudah

myList.map(&:description).reject(&:empty?).join("\n")

Python:

descriptions = (f.description() for f in mylist)
"\n".join(filter(len, descriptions))

Python memiliki generator bawaan (yang digunakan seperti blok Ruby, seperti disebutkan di atas)

Python memiliki dukungan untuk generator dalam bahasa tersebut. Di Ruby 1.8 Anda dapat menggunakan modul generator yang menggunakan lanjutan untuk membuat generator dari sebuah blok. Atau, Anda bisa menggunakan blok / proc / lambda! Selain itu, di Ruby 1.9 Serat adalah, dan dapat digunakan sebagai, generator, dan kelas Enumerator adalah generator bawaan 4

docs.python.org memiliki contoh generator ini:

def reverse(data):
    for index in range(len(data)-1, -1, -1):
        yield data[index]

Bandingkan ini dengan contoh blok di atas.

Python memiliki penanganan ruang nama yang fleksibel

Di Ruby, saat Anda mengimpor file dengan require, semua hal yang ditentukan dalam file itu akan berakhir di namespace global Anda. Ini menyebabkan polusi namespace. Solusi untuk itu adalah modul Ruby. Tetapi jika Anda membuat namespace dengan modul, maka Anda harus menggunakan namespace itu untuk mengakses kelas yang ada di dalamnya.

Dalam Python, file tersebut adalah modul, dan Anda dapat mengimpor nama yang ada di dalamnya from themodule import *, sehingga mencemari namespace jika Anda mau. Tetapi Anda juga dapat mengimpor nama yang dipilih dengan from themodule import aname, anotheratau Anda dapat dengan mudah import themoduledan kemudian mengakses nama dengan themodule.aname. Jika Anda ingin lebih banyak level di namespace Anda, Anda dapat memiliki paket, yang merupakan direktori dengan modul dan __init__.pyfile.

Python memiliki docstrings

Docstring adalah string yang dilampirkan ke modul, fungsi, dan metode, serta dapat diintrospeksi saat runtime. Ini membantu untuk membuat hal-hal seperti perintah bantuan dan dokumentasi otomatis.

def frobnicate(bar):
    """frobnicate takes a bar and frobnicates it

       >>> bar = Bar()
       >>> bar.is_frobnicated()
       False
       >>> frobnicate(bar)
       >>> bar.is_frobnicated()
       True
    """

Yang setara dengan Ruby mirip dengan javadocs, dan terletak di atas metode, bukan di dalamnya. Mereka bisa diambil pada waktu proses dari file dengan menggunakan metode 1.9 Metode # source_location digunakan

Python memiliki banyak warisan

Ruby tidak ("sengaja" - lihat situs web Ruby, lihat di sini bagaimana hal itu dilakukan di Ruby ). Itu menggunakan kembali konsep modul sebagai jenis kelas abstrak.

Python memiliki pemahaman list / dict

Python:

res = [x*x for x in range(1, 10)]

Rubi:

res = (0..9).map { |x| x * x }

Python:

>>> (x*x for x in range(10))
<generator object <genexpr> at 0xb7c1ccd4>
>>> list(_)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Rubi:

p = proc { |x| x * x }
(0..9).map(&p)

Python 2.7+ :

>>> {x:str(y*y) for x,y in {1:2, 3:4}.items()}
{1: '4', 3: '16'}

Rubi:

>> Hash[{1=>2, 3=>4}.map{|x,y| [x,(y*y).to_s]}]
=> {1=>"4", 3=>"16"}

Python memiliki dekorator

Hal-hal yang mirip dengan dekorator juga dapat dibuat di Ruby, dan juga dapat dikatakan bahwa hal itu tidak sepenting di Python.

Perbedaan sintaks

Ruby membutuhkan "end" atau "}" untuk menutup semua cakupannya, sementara Python hanya menggunakan spasi. Baru-baru ini ada upaya di Ruby untuk mengizinkan indentasi hanya spasi putih http://github.com/michaeledgar/seamless


2
Berkenaan dengan multiple inheritance, mengatakan "Ruby tidak" tidak jujur. Saya tidak dapat memikirkan apa pun yang dapat Anda lakukan dengan Python dengan multiple inheritance yang tidak dapat Anda lakukan di ruby ​​dengan modules / "mixin inheritance". (Itu bahkan dikatakan bahwa termasuk modul sekadar adalah beberapa warisan.)
Logan Capaldo

2
Bahwa Anda dapat melakukan hal yang sama dengan cara lain adalah argumen yang tidak berlaku. Anda dapat melakukan semuanya di sini dengan cara lain. Dan karena modul bukanlah kelas, itu bukan warisan berganda. Anda dipersilakan untuk memberikan contoh kode bagaimana hal itu dilakukan di Pythons multiple inheritence vs dengan modul Ruby.
Lennart Regebro

3
Modul bukanlah Kelas tetapi Kelas adalah Modul. % ruby ​​-e 'p Kelas <Module' true
Logan Capaldo

8
-1 Sayangnya, pertanyaan ini meleset dari tujuannya dan sebagian besar perbedaan yang diklaim bukanlah perbedaan sama sekali dan informasi yang salah berlimpah!
bias

2
Modul termasuk pada kenyataannya adalah multiple inheritance, tidak hanya dalam konsep tetapi juga dalam implementasi aktual di interpreter Ruby. Saat modul Ruby disertakan, modul tersebut dimasukkan ke dalam rantai pewarisan persis sama dengan superclass. Resolusi metode sama. Di Ruby, beberapa modul termasuk multi-inheritance. Siapapun yang ingin menggugat ini secara semantik sebagai "bukan hal yang sama" sebagai pewarisan ganda hanya sedang bertele-tele. Apa gunanya sesuatu tidak menjadi "hal yang sama" jika efeknya sama dan mudah dicapai? Perbedaan tanpa perbedaan.
Dave Sims

Jawaban:


34

Ruby memiliki konsep blok , yang pada dasarnya adalah gula sintaksis di sekitar bagian kode; mereka adalah cara untuk membuat penutupan dan meneruskannya ke metode lain yang mungkin menggunakan blok tersebut atau tidak. Sebuah blok dapat dipanggil nanti melalui sebuah yieldpernyataan.

Misalnya, definisi sederhana dari sebuah eachmetode di Arraymungkin seperti ini:

class Array
  def each
    for i in self  
      yield(i)     # If a block has been passed, control will be passed here.
    end  
  end  
end  

Kemudian Anda dapat memohon seperti ini:

# Add five to each element.
[1, 2, 3, 4].each{ |e| puts e + 5 }
> [6, 7, 8, 9]

Python memiliki fungsi / closures / lambda anonim, tetapi tidak cukup memiliki blok karena kehilangan beberapa gula sintaksis yang berguna. Namun, setidaknya ada satu cara untuk mendapatkannya secara ad-hoc. Lihat, misalnya, di sini .


6
@ Lennart: selain dari contoh Anda hanya menjadi mengerikan, itu juga salah secara sintaksis.

2
@ tanpa sepengetahuan: A, benar. Tetapi jika itu adalah fungsi alih-alih mencetak, itu akan berhasil. Di python 3 ini berfungsi: [print (e + 5) for e in [1,2,3,4]] Dan ketika berbicara tentang mengerikan, saya pikir kode ruby ​​di atas sangat buruk, jadi itu jelas subjektif dan karenanya bukan bagian dari pertanyaan ini. @ John Saya tidak mengatakan itu setara, saya mengatakan tidak jelas apa perbedaannya dari contoh Anda. @Bastien, tidak, tetapi Anda dapat melakukan hal yang serupa tidak berarti mereka sama. Perbedaan di sini harus dicantumkan meskipun ada cara lain untuk melakukannya.
Lennart Regebro

22
Saya seorang Python Programmer. Saya ingin melihat contoh bagaimana blok Ruby membantu Anda menulis sesuatu yang lebih ringkas atau lebih indah daripada dengan Python karena tidak memiliki blok. Contoh Anda bisa ditulis: untuk i di [1, 2, 3, 4]: print (i + 5). Itu tidak menggunakan balok, tetapi ringkas dan indah serta ruby ​​di setiap contohnya.
Manuel Ceron

10
@Manuel, procs berguna untuk memasang functor ke struktur data non-trivial (pohon, grafik ...) yang tidak dapat 'diulang' dan karenanya memerlukan iterator khusus untuk melintang. Blok, yang merupakan procs anonim, memungkinkan Anda mengimplementasikan functor dalam satu ekspresi (vs. mendefinisikan lalu mengimplementasikan) yang secara dramatis mempercepat proses pengkodean dan menjelaskan maksud. Misalnya jika Anda membuat struktur data grafik, Anda dapat menentukan satu 'setiap' iterator dan kemudian mencampur Enumerable yang akan langsung memberi Anda akses ke lusinan iterator (urutkan, semua ?, any ?, grep). Sekarang Anda memanggil blok ...
bias

4
@RommeDeSerieux, karena itu membutuhkan nama dalam bahasa! Selain itu, ini adalah objek fungsi, bukan fungsi. Mari kita lihat Dokumen Ruby: "Objek Proc adalah blok kode yang telah terikat ke sekumpulan variabel lokal" jadi Proc anonim hanyalah bloknya dan tentunya bukan hanya sebuah fungsi!
bias

28

Contoh Python

Fungsi adalah variabel kelas satu di Python. Anda dapat mendeklarasikan sebuah fungsi, menyebarkannya sebagai sebuah objek, dan menimpanya:

def func(): print "hello"
def another_func(f): f()
another_func(func)

def func2(): print "goodbye"
func = func2

Ini adalah fitur dasar dari bahasa skrip modern. JavaScript dan Lua melakukan ini juga. Ruby tidak memperlakukan fungsi seperti ini; menamai suatu fungsi menyebutnya.

Tentu saja, ada cara untuk melakukan hal-hal ini di Ruby, tetapi itu bukan operasi kelas satu. Misalnya, Anda bisa membungkus fungsi dengan Proc.new untuk memperlakukannya sebagai variabel - tapi itu bukan lagi fungsi; itu adalah objek dengan metode "panggilan".

Fungsi Ruby bukanlah objek kelas satu

Fungsi Ruby bukanlah objek kelas satu. Fungsi harus dibungkus dalam sebuah objek untuk menyebarkannya; objek yang dihasilkan tidak dapat diperlakukan seperti fungsi. Fungsi tidak dapat ditetapkan dengan cara kelas satu; sebagai gantinya, fungsi dalam objek kontainernya harus dipanggil untuk memodifikasinya.

def func; p "Hello" end
def another_func(f); method(f)[] end
another_func(:func)      # => "Hello"

def func2; print "Goodbye!"
self.class.send(:define_method, :func, method(:func2))
func                     # => "Goodbye!"

method(:func).owner      # => Object
func                     # => "Goodbye!"
self.func                # => "Goodbye!"    

8
Anda sangat bingung. Objek kelas satu ditetapkan dengan tugas:, x = ybukan dengan memanggil self.class.send(:define_method, :func, method(:func2)). "Counterexample" Anda menunjukkan bagaimana fungsi Ruby tidak kelas satu. Jika Anda tidak setuju, silakan posting jawaban Anda sendiri; jangan taruh kebingunganmu pada milikku.
Glenn Maynard

7
Hal-hal yang didefinisikan def ... enddalam ruby ​​bukanlah fungsi. Mereka adalah metode (cara Anda mendefinisikannya, dari Kernel). Metode bisa tidak terikat (menggunakan #methodmetode), yang kemudian merupakan objek. Hal terdekat yang dimiliki ruby ​​dengan fungsi adalah Procinstance, yang juga merupakan objek, dan dapat diteruskan atau dipanggil. Ini juga memiliki sintaks khusus untuk meneruskan satu callback Procke suatu metode, seperti yang dibahas John Feminella dalam jawabannya .
rampion

4
@ Glenn: Saya mengerti apa yang Anda katakan, tetapi saya berdalih dengan pernyataan bahwa fungsi mendefinisikan ulang Ruby - metode adalah konsep semantik yang terpisah. Jika Anda ingin memainkan permainan definisi, kode yang paling penting adalah prosedur, bukan fungsi. Saya tidak berusaha untuk menjadi sulit, hanya saja saya percaya definisi dan ketepatan itu penting. Aku setuju bahwa memanipulasi UnboundMethodkaleng menjadi PITA, tho.
rampion

5
@ Glenn: Kecantikan ada di mata yang melihatnya. Meskipun demikian, metode adalah objek kelas satu dengan memenuhi definisi (dalam hal ini saya mengacu pada definisi Wikipedia). Mungkin, Anda memiliki definisi lain tentang kelas satu? Apakah mereka memerlukan Kartu Platinum Frequent Flier untuk naik ke kelas satu?
bias

4
@Glenn Lihat bagian SO FAQ "Orang lain dapat mengedit barang saya ?!" - ini adalah Wiki Komunitas.
bias

26

Pada akhirnya semua jawaban akan menjadi subyektif pada tingkat tertentu, dan jawaban yang diposting sejauh ini cukup banyak membuktikan bahwa Anda tidak dapat menunjukkan satu fitur yang tidak dapat dilakukan dalam bahasa lain dengan cara yang sama bagusnya (jika tidak serupa). , karena kedua bahasa tersebut sangat ringkas dan ekspresif.

Saya suka sintaks Python. Namun, Anda harus menggali sedikit lebih dalam dari sintaks untuk menemukan keindahan Ruby yang sebenarnya. Ada keindahan seperti zen dalam konsistensi Ruby. Meskipun tidak ada contoh sepele yang dapat menjelaskan hal ini sepenuhnya, saya akan mencoba memberikan satu contoh di sini hanya untuk menjelaskan apa yang saya maksud.

Balik kata-kata dalam string ini:

sentence = "backwards is sentence This"

Ketika Anda memikirkan tentang bagaimana Anda akan melakukannya, Anda akan melakukan hal berikut:

  1. Pisahkan kalimat menjadi kata-kata
  2. Balik kata-katanya
  3. Gabungkan kembali kata-kata tersebut menjadi string

Di Ruby, Anda akan melakukan ini:

sentence.split.reverse.join ' '

Persis seperti yang Anda pikirkan, dalam urutan yang sama, satu metode memanggil demi satu.

Dalam python, akan terlihat seperti ini:

" ".join(reversed(sentence.split()))

Ini tidak sulit untuk dipahami, tetapi tidak memiliki aliran yang sama. Subjek (kalimat) terkubur di tengah. Operasi adalah campuran dari fungsi dan metode objek. Ini adalah contoh yang sepele, tetapi orang menemukan banyak contoh berbeda ketika benar-benar bekerja dengan dan memahami Ruby, terutama pada tugas-tugas yang tidak sepele.


1
Saya setuju. Ruby sepertinya mengalir secara alami saat saya menulisnya, jadi "zenlike" adalah istilah yang bagus.
Manusia Timah

18

Python memiliki mentalitas "kita semua dewasa di sini". Dengan demikian, Anda akan menemukan bahwa Ruby memiliki hal-hal seperti konstanta sedangkan Python tidak (meskipun konstanta Ruby hanya memunculkan peringatan). Cara berpikir Python adalah jika Anda ingin membuat sesuatu yang konstan, Anda harus meletakkan nama variabel dalam huruf besar semua dan tidak mengubahnya.

Misalnya, Ruby:

>> PI = 3.14
=> 3.14
>> PI += 1
(irb):2: warning: already initialized constant PI
=> 4.14

Python:

>>> PI = 3.14
>>> PI += 1
>>> PI
4.1400000000000006

19
Ha .. ini hanya mengingatkan saya bahwa setidaknya di python 2. *, Anda dapat melakukan "Benar, Salah = Salah, Benar" ... Saya yakin mereka telah memperbaikinya dengan benar di python 3.0 ... itu sesuatu yang harus Anda dicegah dari melakukan.
Tom

11
Secara pribadi, saya suka pedoman ketat yang diberlakukan oleh bahasa karena membuat semua kode yang ditulis dalam bahasa itu konsisten. Ini memaksa Anda untuk mengikuti pedoman, dan pengembang yang membaca kode Anda dapat mengetahui dengan cepat apa itu. Sementara kebanyakan pembuat kode Python menggunakan "gaya" umum yang sama, saya telah melihat beberapa inkonsistensi yang cukup besar yang tidak mungkin terjadi di Ruby.
Sasha Chedygov

8
@bias - Saya tidak yakin mengapa Anda merendahkan saya. Jawaban ini tidak setuju atau tidak setuju dengan cara python dalam melakukan sesuatu. Itu hanya pernyataan fakta.
Jason Baker

13
@Jason "kita semua orang dewasa di sini" adalah pernyataan fakta? Saya ingin menyebutnya sebagai opini yang melingkupi fitur, oleh karena itu suara negatifnya.
bias

7
@bias - Mengatakan "kita semua dewasa di sini" tidak dimaksudkan sebagai hal yang kecil. Ini adalah moto Python tidak resmi, yang saya yakin paling baik dijelaskan di sini: mail.python.org/pipermail/tutor/2003-October/025932.html
Evan Porter

18

Anda hanya dapat mengimpor fungsi tertentu dari modul dengan Python. Di Ruby, Anda mengimpor seluruh daftar metode. Anda bisa "membatalkan impor" mereka di Ruby, tapi itu bukan tentang semua itu.

EDIT:

mari kita ambil modul Ruby ini:


module Whatever
  def method1
  end

  def method2
  end
end

jika Anda memasukkannya ke dalam kode Anda:


include Whatever

Anda akan melihat bahwa metode1 dan metode2 telah ditambahkan ke ruang nama Anda. Anda tidak dapat mengimpor hanya metode1 . Anda bisa mengimpor keduanya atau tidak mengimpornya sama sekali. Dengan Python, Anda hanya dapat mengimpor metode yang Anda pilih. Jika ini memiliki nama, mungkin itu akan disebut impor selektif?


2
Oh iya! Python menyukai ruang nama. Bukankah itu yang terjadi di Ruby? Anda tidak import bla; bla.foo()di Ruby?
Lennart Regebro

2
Anda hanya dapat mengimpor fungsi a, tidak semua fungsi di dalamnya. Jika misalnya Anda menyertakan modul Ruby yang mendeklarasikan 3 fungsi non-statis, Anda akan memasukkan semuanya ke dalam namespace Anda. Dengan python Anda harus menulis dari module import *.
Geo

6
Bukankah itu menyebabkan banyak kekacauan namespace?
Lennart Regebro

1
Saya pikir itu benar. Itulah yang saya benci tentang modul Ruby.
Geo

8
Ruby tidak benar-benar memiliki sistem modul dalam arti yang sama seperti python. Requirement bekerja pada dasarnya sebagai inklusi tekstual dengan beberapa pemeriksaan untuk dupilicate inclusion yang dimasukkan. Anda dapat (ab) menggunakan modul sebagai ruang nama tetapi modulesebenarnya sedikit keliru. Modul pada dasarnya kelas sans new, allocatemetode. Mereka bekerja paling baik sebagai cara untuk berbagi kode berdasarkan kelas / objek, bukan sebagai mekanisme untuk mempartisi perpustakaan, atau untuk berbagi kode di seluruh program.
Logan Capaldo

16

Dari situs Ruby :

Kemiripan Seperti Python, di Ruby, ...

  • Ada prompt interaktif (disebut irb).
  • Anda dapat membaca dokumen di baris perintah (dengan perintah ri, bukan pydoc).
  • Tidak ada terminator jalur khusus (kecuali jalur baru biasa).
  • Literal string dapat menjangkau beberapa baris seperti string yang dikutip tiga kali pada Python.
  • Tanda kurung untuk daftar, dan tanda kurung untuk dict (yang, di Ruby, disebut "hashes").
  • Array bekerja sama (menambahkannya membuat satu array panjang, tetapi menyusunnya seperti ini a3 = [ a1, a2 ]memberi Anda sebuah array).
  • Objek diketik dengan kuat dan dinamis.
  • Semuanya adalah objek, dan variabel hanyalah referensi ke objek.
  • Meskipun kata kuncinya sedikit berbeda, pengecualian berfungsi hampir sama.
  • Anda memiliki alat dokumen tertanam (Ruby disebut rdoc).

Perbedaan Tidak seperti Python, di Ruby, ...

  • String bisa berubah.
  • Anda dapat membuat konstanta (variabel yang nilainya tidak ingin Anda ubah).
  • Ada beberapa konvensi kasus yang diberlakukan (mis. Nama kelas diawali dengan huruf kapital, variabel diawali dengan huruf kecil).
  • Hanya ada satu jenis wadah daftar (Array), dan itu bisa berubah.
  • String kutip ganda memungkinkan escape sequences (seperti \ t) dan sintaks "substitusi ekspresi" khusus (yang memungkinkan Anda memasukkan hasil ekspresi Ruby langsung ke string lain tanpa harus "menambahkan" + "string" + "bersama-sama") . String kutip tunggal seperti r "string mentah" Python.
  • Tidak ada kelas "gaya baru" dan "gaya lama". Hanya satu jenis.
  • Anda tidak pernah mengakses atribut secara langsung. Dengan Ruby, itu semua adalah pemanggilan metode.
  • Tanda kurung untuk panggilan metode biasanya opsional.
  • Ada publik, pribadi, dan dilindungi untuk menegakkan akses, bukan milik Python _voluntary_ underscore __convention__.
  • "Mixin's" digunakan sebagai pengganti multiple inheritance.
  • Anda dapat menambah atau mengubah metode kelas bawaan. Kedua bahasa memungkinkan Anda membuka dan memodifikasi kelas kapan saja, tetapi Python mencegah modifikasi bawaan - Ruby tidak.
  • Anda mendapatkan benar dan salah, bukan Benar dan Salah (dan nihil alih-alih Tidak ada).
  • Saat diuji kebenarannya, hanya false dan nil yang dievaluasi ke nilai salah. Semua yang lain benar (termasuk 0, 0,0, "", dan []).
  • Ini elsif, bukan elif.
  • Ini membutuhkan, bukan impor. Jika tidak, penggunaannya sama.
  • Komentar gaya biasa pada baris di atas (bukan docstring di bawahnya) digunakan untuk membuat dokumen.
  • Ada sejumlah jalan pintas yang, meskipun memberi Anda lebih banyak untuk diingat, Anda dengan cepat belajar. Mereka cenderung membuat Ruby menyenangkan dan sangat produktif.

2
"Ini membutuhkan alih-alih impor. Namun jika tidak, penggunaannya sama." Tampaknya sama sekali tidak akurat.
Glenjamin

Ada juga Set di Ruby yang jarang digunakan orang, tetapi sudah ada di dalamnya. Jadi saya bisa katakan, stuff_in_backpack = Set.new; stuff_in_backpack << "computer"; stuff_in_backpack << "shoes"; # dan himpunan akan menyimpan semua nilai tanpa menjamin ketertiban.
zachaysan

12

Apa yang dimiliki Ruby atas Python adalah kemampuan bahasa skripnya. Bahasa skrip dalam konteks ini berarti digunakan untuk "kode perekat" dalam skrip shell dan manipulasi teks umum.

Ini sebagian besar dibagikan dengan Perl. Ekspresi reguler bawaan kelas satu, $ -Variabel, opsi baris perintah yang berguna seperti Perl (-a, -e) dll.

Bersama dengan sintaks yang singkat namun cepat, ini sempurna untuk jenis tugas ini.

Bagi saya Python lebih merupakan bahasa bisnis yang diketik secara dinamis yang sangat mudah dipelajari dan memiliki sintaks yang rapi. Tidak sekeren Ruby tapi rapi. Apa yang Python miliki atas Ruby bagi saya adalah banyaknya binding untuk libs lain. Pengikatan ke Qt dan pustaka GUI lainnya, banyak pustaka dukungan permainan dan dan dan. Ruby memiliki lebih sedikit. Sementara banyak binding yang digunakan misalnya untuk Database memiliki kualitas yang baik, saya menemukan libs niche lebih baik didukung dengan Python meskipun untuk perpustakaan yang sama ada juga pengikatan Ruby.

Jadi, saya akan mengatakan kedua bahasa memiliki kegunaannya dan itu adalah tugas yang menentukan mana yang akan digunakan. Keduanya cukup mudah dipelajari. Saya menggunakannya secara berdampingan. Ruby untuk scripting dan Python untuk aplikasi yang berdiri sendiri.


1
Pertanyaan dari seseorang yang belum mengenal Ruby: Apa yang Anda maksud dengan "$ -Variables"? Apakah yang Anda maksud variabel global? Jika demikian, dalam Python, variabel yang ditentukan dalam modul di luar kelas atau fungsi bersifat global. Jika tidak - apa bedanya?
Anon

1
Anon: jika Anda mendeklarasikan $ variabel di mana saja dalam kode itu global karena awalan. Jadi, tidak masalah di mana ia didefinisikan, ia selalu global, dan selalu dikenal seperti itu.
Robert K

8
Tidak juga, sebenarnya yang saya maksud adalah variabel yang telah ditentukan sebelumnya seperti $ _, $ 1 dll. Ini secara otomatis diisi dengan nilai oleh ruby ​​itu sendiri. $ _ adalah baris terakhir yang dibaca. $ 1, $ 2, dll. Adalah persamaan reguler yang cocok dari pencocokan terakhir. Lihat di sini untuk daftar lengkapnya: zenspider.com/Languages/Ruby/QuickRef.html#17 Ini pada dasarnya adalah hack untuk skrip kompak. Anda bisa mendapatkan semua info melalui panggilan API juga, tetapi menggunakan $ variabel itu lebih singkat. Variabel semacam itu tidak sesuai dengan gaya Python, mereka sengaja meninggalkannya.
haffax

Terima kasih untuk tautan zenspider itu - telah mencari sesuatu seperti itu untuk nuansa singkat (non-tutorial) untuk Ruby.
Anon

12

Saya tidak berpikir "Ruby memiliki X dan Python tidak, sedangkan Python memiliki Y dan Ruby tidak" adalah cara yang paling berguna untuk melihatnya. Mereka adalah bahasa yang sangat mirip, dengan banyak kemampuan yang sama.

Untuk sebagian besar, perbedaannya adalah apa yang dibuat bahasa itu elegan dan mudah dibaca. Untuk menggunakan contoh yang Anda kemukakan, keduanya secara teoritis memiliki lambda, tetapi programmer Python cenderung menghindarinya, dan konstruksi yang dibuat menggunakan keduanya tidak terlihat seperti dapat dibaca atau idiomatis seperti di Ruby. Jadi dengan Python, seorang programmer yang baik akan ingin mengambil rute yang berbeda untuk memecahkan masalah daripada dia akan di Ruby, hanya karena sebenarnya adalah cara yang lebih baik untuk melakukannya.


5
Saya setuju bahwa lambda memiliki ruang lingkup terbatas dan tidak berguna dalam banyak kasus. Namun, menurut saya tidak adil untuk mengatakan bahwa programmer Python menghindari mereka seperti wabah.
Jason Baker

1
Saya setuju bahwa lambda sering digunakan dengan Python - seperti pada map, filter, reduce. Perbedaan besar tampaknya bahwa Python lambda terbatas pada ekspresi sedangkan blok Ruby bisa multiline dan melibatkan pernyataan. Kesan umum saya dari apa yang saya baca tentang Ruby adalah bahwa fitur ini secara khusus membuat Rubyist menggunakan pendekatan DSL, sedangkan Pythonistas lebih cenderung membuat API. Info saya tentang Ruby masih sangat dangkal.
Anon

2
@ Lennart: Blok multiline digunakan sepanjang waktu di Ruby - lebih sering daripada yang saya lihat lambda digunakan dalam kode Python idiomatik, sebenarnya. Untuk contoh umum, lihat info.michael-simons.eu/2007/08/06/rails-respond_to-method .
Chuck

1
@ Lennart: Tidak, itu tidak menggunakan hasil. (Hasil Ruby benar-benar berbeda dari Python - ia tidak mengembalikan generator.) Menulis itu tidak akan berarti for format in respond_to(). The respond_toMetode tidak kembali sesuatu yang berarti - itu hanya merespon permintaan HTTP saat ini. Bagian dodalam respond_to doadalah awal dari sebuah blok. Di blok itu, kita berbicara dengan objek sementara (diberi label formatdalam contoh ini) yang mengimplementasikan DSL yang sangat dasar untuk merespons permintaan HTTP.
Chuck

3
Bisakah Anda 'mencampur Enumerable' dengan generator dan langsung mendapatkan 30 iterator baru dan hebat? Anda perlu melihat bahasa secara keseluruhan sebelum Anda memahami mengapa blok / Pro itu hebat.
bias

12

Saya ingin menyarankan varian dari pertanyaan awal, "Apa yang dimiliki Ruby yang tidak dimiliki Python, dan sebaliknya?" yang mengakui jawaban yang mengecewakan, "Nah, apa yang dapat Anda lakukan dengan Ruby atau Python yang tidak dapat dilakukan di Intercal?" Tidak ada di level itu, karena Python dan Ruby adalah bagian dari keluarga kerajaan besar yang duduk di atas takhta yang hampir menyerupai Turing.

Tapi bagaimana dengan ini:

Apa yang bisa dilakukan dengan anggun dan baik dengan Python yang tidak bisa dilakukan di Ruby dengan keindahan dan teknik yang bagus, atau sebaliknya?

Itu mungkin jauh lebih menarik daripada sekadar perbandingan fitur.


komentar terbaik. masih +1 saya
nawfal

11

Python memiliki sintaksis bawaan yang eksplisit untuk pemahaman daftar dan generator sedangkan di Ruby Anda akan menggunakan blok peta dan kode.

Membandingkan

list = [ x*x for x in range(1, 10) ]

untuk

res = (1..10).map{ |x| x*x }

bagaimana pemahaman daftar bukan Python biasa ? dan ada fungsi peta dengan Python juga.
SilentGhost

Tetapi tidak ada sintaks pemahaman daftar di Ruby
Dario

Python: res = map (lambda x: x * x, range (1,10))
GogaRieger

Python:res=map(2 .__rpow__, range(1,10))
John La Rooy

11

"Variabel yang dimulai dengan huruf kapital menjadi konstanta dan tidak dapat dimodifikasi"

Salah. Mereka bisa.

Anda hanya mendapat peringatan jika melakukannya.


2
Jika suatu bahasa memberi Anda peringatan untuk suatu operasi, menurut saya Anda dapat menganggap operasi tersebut "tidak mungkin". Yang lainnya adalah kegilaan.
porgarmingduod

11

Sedikit lebih banyak di sisi infrastruktur:

  • Python memiliki integrasi yang jauh lebih baik dengan C ++ (melalui hal-hal seperti Boost.Python , SIP , dan Py ++ ) daripada Ruby, di mana opsinya tampaknya menulis langsung pada API interpreter Ruby (yang juga dapat Anda lakukan dengan Python, tentu saja, tetapi dalam kedua kasus melakukannya adalah tingkat rendah, membosankan, dan rawan kesalahan) atau gunakan SWIG (yang, meskipun berfungsi dan pasti bagus jika Anda ingin mendukung banyak bahasa, tidak sebagus Boost. Python atau SIP jika Anda secara khusus ingin mengikat C ++).

  • Python memiliki sejumlah lingkungan aplikasi web (Django, Pylons / Turbogears, web.py, mungkin setidaknya setengah lusin lainnya), sedangkan Ruby (efektif) memiliki satu: Rails. (Kerangka web Ruby lain memang ada, tetapi tampaknya kesulitan mendapatkan banyak daya tarik terhadap Rails). Apakah aspek ini baik atau buruk? Sulit untuk dikatakan, dan mungkin sangat subjektif; Saya dapat dengan mudah membayangkan argumen bahwa situasi Python lebih baik dan situasi Ruby lebih baik.

  • Secara budaya, komunitas Python dan Ruby tampak agak berbeda, tetapi saya hanya dapat mengisyaratkan hal ini karena saya tidak memiliki banyak pengalaman dalam berinteraksi dengan komunitas Ruby. Saya menambahkan ini sebagian besar dengan harapan bahwa seseorang yang memiliki banyak pengalaman dengan keduanya dapat memperkuat (atau menolak) pernyataan ini.


7
Poin kedua Anda paling-paling salah informasi. Anda harus mulai dengan melihat Rack dan Sinatra
Max Ogden

6
Saya secara eksplisit mencatat bahwa tumpukan Rails lain ada; Saya hanya tidak berpikir ada orang yang benar-benar menggunakannya. Memeriksa Sinatra dan Rack tidak benar-benar mengubah kesan itu. Apakah menurut Anda, katakanlah, Sinatra (total 94 pertanyaan SO), atau Camping (total 2 pertanyaan SO), atau yang lainnya, benar-benar memiliki basis pengguna / komunitas yang nyata? Kebanyakan dari mereka bahkan tidak memiliki pengguna di kehidupan nyata, sejauh yang saya tahu. Bandingkan dengan Django (4K +) atau Rails (7K +), atau bahkan web.py dalam hal ini.
Jack Lloyd

1
Sinatra sebenarnya agak populer untuk tugas yang berbeda dan ringan karena DSL-nya. Ini hanya kurang digunakan karena MVC Rail menyediakan lebih banyak. Rails sebenarnya dibangun di atas Rack - Itulah yang memungkinkan Phusion Passenger.
alternatif

11

Salin / tempel tanpa malu-malu dari: Alex Martelli menjawab tentang utas " Apa yang lebih baik tentang Ruby daripada Python " dari milis comp.lang.python .

18 Agustus 2003, 10:50 Erik Max Francis menulis:

"Brandon J. Van Every" menulis:

Apa yang lebih baik tentang Ruby daripada Python? Saya yakin ada sesuatu. Apa itu?

Bukankah lebih masuk akal untuk menanyakan hal ini kepada orang Ruby, daripada orang Python?

Mungkin, atau mungkin tidak, bergantung pada tujuan seseorang - misalnya, jika tujuan seseorang termasuk "studi sosiologis" dari komunitas Python, maka mengajukan pertanyaan ke komunitas tersebut kemungkinan besar akan membuktikan lebih banyak informasi tentang hal itu, daripada menempatkannya di tempat lain :-).

Secara pribadi, saya dengan senang hati mengambil kesempatan untuk mengikuti tutorial Ruby satu hari Dave Thomas di OSCON terakhir. Di bawah lapisan tipis perbedaan sintaks, saya menemukan Ruby dan Python sangat mirip - jika saya menghitung pohon rentang minimum di antara hampir semua bahasa, saya cukup yakin Python dan Ruby akan menjadi dua daun pertama yang bergabung menjadi simpul perantara :-).

Tentu, saya lelah, di Ruby, mengetik "akhir" konyol di akhir setiap blok (bukan hanya membuka tanda) - tapi kemudian saya bisa menghindari mengetik ':' yang sama-sama konyolnya di yang start dari setiap blok, sehingga hampir mencuci :-). Perbedaan sintaks lainnya seperti '@foo' versus 'self.foo', atau signifikansi yang lebih tinggi dari case di Ruby vs Python, sama tidak relevannya bagi saya.

Yang lain tidak diragukan lagi mendasarkan pilihan bahasa pemrograman mereka hanya pada masalah seperti itu, dan mereka menghasilkan perdebatan terpanas - tetapi bagi saya itu hanya contoh dari salah satu Hukum Parkinson yang sedang berjalan (jumlah perdebatan tentang suatu masalah berbanding terbalik dengan masalah itu. kepentingan aktual).

Edit (oleh AM 6/19/2010 11:45): ini juga dikenal sebagai "melukis bikeshed" (atau, singkatnya, "bikeshedding") - rujukannya, sekali lagi, ke Northcote Parkinson, yang memberikan "debat tentang warna apa untuk melukis bikeshed "sebagai contoh khas dari" debat panas tentang topik sepele ". (akhir Edit).

Satu perbedaan sintaks yang saya anggap penting, dan mendukung Python - tetapi orang lain pasti akan berpikir sebaliknya - adalah "bagaimana Anda memanggil fungsi yang tidak mengambil parameter". Dalam Python (seperti di C), untuk memanggil sebuah fungsi, Anda selalu menerapkan "operator panggilan" - tanda kurung di belakang tepat setelah objek yang Anda panggil (di dalam tanda kurung tersebut terdapat argumen yang Anda berikan dalam panggilan - jika Anda tidak memberikan args, maka tanda kurung kosong). Ini hanya menyisakan penyebutan apapunobjek, tanpa operator yang terlibat, sebagai makna hanya referensi ke objek - dalam konteks apa pun, tanpa kasus khusus, pengecualian, aturan ad-hoc, dan sejenisnya. Di Ruby (seperti di Pascal), untuk memanggil fungsi DENGAN argumen Anda meneruskan argumen (biasanya dalam tanda kurung, meskipun itu tidak selalu terjadi) - TETAPI jika fungsi tidak membutuhkan argumen maka cukup menyebutkan fungsi secara implisit memanggilnya. Ini mungkin memenuhi ekspektasi banyak orang (setidaknya, tidak diragukan lagi, mereka yang hanya memiliki pengalaman pemrograman sebelumnya dengan Pascal, atau bahasa lain dengan "panggilan implisit" serupa, seperti Visual Basic) - tetapi bagi saya, itu berarti hanya menyebutkan suatu objek dapat SALAH SATU berarti referensi ke objek, ATAU panggilan ke objek, tergantung pada jenis objek - dan dalam kasus di mana saya bisa ' t mendapatkan referensi ke objek hanya dengan menyebutkannya, saya perlu menggunakan eksplisit "beri saya referensi untuk ini, JANGAN menyebutnya!" operator yang tidak diperlukan sebaliknya. Saya merasa ini berdampak pada "kelas satu" fungsi (atau metode, atau objek yang dapat dipanggil lainnya) dan kemungkinan pertukaran objek dengan lancar. Oleh karena itu, bagi saya, perbedaan sintaks khusus ini adalah tanda hitam yang serius terhadap Ruby - tetapi saya mengerti mengapa orang lain akan menganggap sebaliknya, meskipun saya hampir tidak bisa tidak setuju dengan mereka :-). fungsi (atau metode, atau objek yang dapat dipanggil lainnya) dan kemungkinan pertukaran objek dengan lancar. Oleh karena itu, bagi saya, perbedaan sintaks khusus ini adalah tanda hitam yang serius terhadap Ruby - tetapi saya mengerti mengapa orang lain akan menganggap sebaliknya, meskipun saya hampir tidak bisa tidak setuju dengan mereka :-). fungsi (atau metode, atau objek panggilan lainnya) dan kemungkinan pertukaran objek dengan lancar. Oleh karena itu, bagi saya, perbedaan sintaks khusus ini adalah tanda hitam yang serius terhadap Ruby - tetapi saya mengerti mengapa orang lain akan menganggap sebaliknya, meskipun saya hampir tidak bisa tidak setuju dengan mereka :-).

Di bawah sintaks, kita masuk ke beberapa perbedaan penting dalam semantik dasar - misalnya, string di Ruby adalah objek yang bisa berubah (seperti di C ++), sedangkan di Python tidak bisa berubah (seperti di Java, atau saya percaya C #). Sekali lagi, orang-orang yang menilai terutama dari apa yang sudah mereka kenal mungkin berpikir bahwa ini adalah nilai tambah bagi Ruby (kecuali mereka terbiasa dengan Java atau C #, tentu saja :-). Saya, saya pikir string yang tidak dapat diubah adalah ide yang bagus (dan saya tidak terkejut bahwa Java, secara independen saya pikir, menemukan kembali ide yang sudah ada di Python), meskipun saya tidak keberatan memiliki jenis "buffer string yang bisa berubah" juga (dan idealnya satu dengan kemudahan penggunaan yang lebih baik daripada "buffer string" Java sendiri); dan saya tidak memberikan penilaian ini karena keakraban - sebelum mempelajari Java, semua data tidak dapat diubah, semua bahasa yang saya tahu memiliki string yang dapat berubah - namun ketika saya pertama kali melihat ide string yang tidak dapat diubah di Java (yang saya pelajari dengan baik sebelum saya belajar Python), saya langsung merasa sangat baik, sangat cocok untuk referensi-semantik dari bahasa pemrograman tingkat yang lebih tinggi (sebagai lawan dari nilai-semantik yang paling cocok dengan bahasa yang lebih dekat ke mesin dan lebih jauh dari aplikasi, seperti C) dengan string sebagai kelas satu, built-in (dan cukup penting) tipe data.

Ruby memang memiliki beberapa keunggulan dalam semantik dasar - misalnya, penghapusan perbedaan "list vs tuple" Python sangat tipis. Tetapi sebagian besar skor (seperti yang saya simpan, dengan kesederhanaan plus besar dan halus, perbedaan pintar minus penting) berlawanan dengan Ruby (misalnya, memiliki interval tertutup dan setengah terbuka, dengan notasi a..b dan a .. .b [ada yang ingin mengklaim bahwa sudah jelas mana yang mana? -)], konyol - IMHO, tentu saja!). Sekali lagi, orang-orang yang menganggap memiliki banyak kesamaan tetapi hal-hal yang agak berbeda sebagai inti dari sebuah bahasa PLUS, bukan MINUS, tentu saja akan menghitung ini "sebaliknya" dari cara saya menghitungnya :-).

Jangan disesatkan oleh perbandingan ini dengan berpikir bahwa kedua bahasa itu adalah sangat miripberbeda, ingatlah. Mereka tidak. Tetapi jika saya diminta untuk membandingkan "capelli d'angelo" dengan "spaghettini", setelah menunjukkan bahwa kedua jenis pasta ini hampir tidak dapat dibedakan oleh siapa pun dan dapat dipertukarkan dalam hidangan apa pun yang mungkin ingin Anda siapkan, saya pasti akan memilikinya untuk beralih ke pemeriksaan mikroskopis tentang bagaimana panjang dan diameter sangat berbeda, bagaimana ujung untaian meruncing dalam satu kasus dan bukan di kasus lain, dan seterusnya - untuk mencoba dan menjelaskan mengapa saya, secara pribadi, lebih suka memiliki capelli d 'angelo sebagai pasta dalam segala jenis kaldu, tetapi lebih suka spaghettini sebagai pastasciutta daripada saus yang cocok untuk bentuk pasta tipis yang panjang (minyak zaitun, bawang putih cincang, cabai merah cincang, dan ikan teri yang digiling halus, misalnya - tetapi jika Anda mengiris bawang putih dan paprika alih-alih mencincangnya, Anda harus memilih badan spageti yang lebih sehat daripada spageti yang lebih encer, dan akan sangat disarankan untuk tidak menggunakan teri dan menambahkan kemangi segar [ atau bahkan - saya seorang bidat ...! - daun mint ringan ...] - pada saat-saat terakhir sebelum menyajikan hidangan). Ups, maaf, itu menunjukkan bahwa saya bepergian ke luar negeri dan sudah lama tidak makan pasta, saya rasa. Tapi analoginya masih cukup bagus! -) - daun mint ringan ...] - pada saat-saat terakhir sebelum menyajikan hidangan). Ups, maaf, itu menunjukkan bahwa saya bepergian ke luar negeri dan sudah lama tidak makan pasta, saya rasa. Tapi analoginya masih cukup bagus! -) - daun mint ringan ...] - pada saat-saat terakhir sebelum menyajikan hidangan). Ups, maaf, itu menunjukkan bahwa saya bepergian ke luar negeri dan sudah lama tidak makan pasta, saya rasa. Tapi analoginya masih cukup bagus! -)

Jadi, kembali ke Python dan Ruby, kita sampai pada dua biggies (dalam hal bahasa yang tepat - meninggalkan perpustakaan, dan tambahan penting lainnya seperti alat dan lingkungan, bagaimana menyematkan / memperluas setiap bahasa, dll, dll, dari itu untuk saat ini - mereka tidak akan berlaku untuk semua IMPLEMENTASI setiap bahasa, misalnya, Jython vs Classic Python menjadi dua implementasi dari bahasa Python!):

  1. Iterator dan blok kode Ruby vs iterator dan generator Python;

  2. TOTAL Ruby, "dinamika" tak terkendali, termasuk kemampuannya
    untuk "membuka kembali" kelas yang ada, termasuk semua kelas yang sudah ada, dan mengubah perilakunya pada waktu proses - vs dinamisitas luas tetapi terbatas Python , yang tidak pernah mengubah perilaku yang ada kelas bawaan dan contoh mereka.

Secara pribadi, saya pertimbangkan 1 mencuci (perbedaan yang begitu dalam bahwa saya bisa dengan mudah melihat orang-orang membenci pendekatan baik dan memuja yang lain, tetapi dalam skala pribadi MY plus dan minus hanya tentang bahkan sampai); dan 2 masalah krusial - yang membuat Ruby jauh lebih cocok untuk "mengutak-atik", TETAPI Python sama-sama lebih cocok untuk digunakan dalam aplikasi produksi besar. Ini lucu, di satu sisi, karena kedua bahasa itu JAUH lebih dinamis daripada kebanyakan bahasa lainnya, sehingga pada akhirnya perbedaan utama di antara mereka dari POV saya harus bergantung pada itu - bahwa Ruby "menjadi sebelas" dalam hal ini (referensi di sini adalah untuk "Tap Spinal", tentu saja). Di Ruby,AKU BISA MELAKUKANNYA ! Yaitu, saya dapat secara dinamis mengubah kelas string built-in sehingga a = "Hello World" b = "hello world" jika a == b print "sama! \ N" else print "berbeda! \ N" end AKAN mencetak " sama". Dengan python, TIDAK ADA cara saya bisa melakukan itu. Untuk tujuan metaprogramming, mengimplementasikan framework eksperimental, dan sejenisnya, kemampuan dinamis Ruby yang luar biasa ini sangatlah luar biasa menarik. TAPI - jika kita berbicara tentang aplikasi besar, dikembangkan oleh banyak orang dan dikelola oleh lebih banyak orang, termasuk semua jenis perpustakaan dari berbagai sumber, dan perlu masuk ke produksi di situs klien ... yah, saya tidak MAU bahasa yang cukup dinamis, terima kasih banyak. Saya sangat membenci gagasan dari beberapa perpustakaan tanpa disadari melanggar yang tidak terkait lainnya yang bergantung pada string yang berbeda - itulah jenis "saluran" yang dalam dan sangat tersembunyi, antara potongan kode yang TERLIHAT terpisah dan HARUS dipisahkan, yang berarti kematian di pemrograman skala besar. Dengan membiarkan modul apa pun memengaruhi perilaku "terselubung" lainnya, kemampuan untuk mengubah semantik tipe bawaan hanyalah ide BURUK untuk pemrograman aplikasi produksi,

Jika saya harus menggunakan Ruby untuk aplikasi sebesar itu, saya akan mencoba mengandalkan pembatasan gaya pengkodean, banyak tes (untuk dijalankan kembali setiap kali ADA yang berubah - bahkan apa yang seharusnya sama sekali tidak terkait ...), dan sejenisnya, untuk melarang penggunaan fitur bahasa ini. Tetapi TIDAK memiliki fitur di tempat pertama bahkan lebih baik, menurut saya - sama seperti Python itu sendiri akan menjadi bahasa yang lebih baik untuk pemrograman aplikasi jika sejumlah built-in dapat "dipaku", jadi saya TAHU itu , misalnya, len ("ciao") adalah 4 (daripada harus khawatir secara mendalam tentang apakah seseorang mengubah pengikatan nama 'len' di modul bawaan ...). Saya berharap bahwa pada akhirnya Python benar-benar "memakukan" bawaannya.

Tapi masalahnya kecil, karena rebinding built-in sudah cukup usang dan juga praktik langka di Python. Di Ruby, menurut saya ini adalah yang utama - sama seperti fasilitas makro yang terlalu kuat dari bahasa lain (seperti, katakanlah, Dylan) menghadirkan risiko serupa menurut pendapat saya (saya berharap Python tidak pernah mendapatkan sistem makro yang begitu kuat, tidak peduli daya pikat "membiarkan orang mendefinisikan bahasa kecil khusus domain mereka yang tertanam dalam bahasa itu sendiri" - itu akan, IMHO, merusak kegunaan luar biasa Python untuk pemrograman aplikasi, dengan menghadirkan "gangguan menarik" kepada calon pengotak-atik yang mengintai di hati setiap programmer ...).

Alex


9

Beberapa lainnya dari:

http://www.ruby-lang.org/en/documentation/ruby-from-other-languages/to-ruby-from-python/

(Jika saya telah salah mengartikan sesuatu atau salah satu dari ini telah berubah di sisi Ruby sejak halaman itu diperbarui, seseorang silakan mengedit ...)

String bisa berubah di Ruby, bukan di Python (di mana string baru dibuat oleh "perubahan").

Ruby memiliki beberapa konvensi kasus yang diberlakukan, sedangkan Python tidak.

Python memiliki daftar dan tupel (daftar yang tidak dapat diubah). Ruby memiliki array yang sesuai dengan daftar Python, tetapi tidak ada varian yang tidak dapat diubah.

Dengan Python, Anda bisa langsung mengakses atribut objek. Di Ruby, selalu melalui metode.

Di Ruby, tanda kurung untuk panggilan metode biasanya opsional, tetapi tidak di Python.

Ruby memiliki public, private, dan protected untuk memaksakan akses, bukan konvensi Python menggunakan garis bawah dan name mangling.

Python memiliki banyak warisan. Ruby memiliki "mixin."

Dan tautan lain yang sangat relevan:

http://c2.com/cgi/wiki?PythonVsRuby

Yang, khususnya, tautan ke yang bagus lainnya oleh Alex Martelli , yang juga memposting banyak hal hebat di sini di SO:

http://groups.google.com/group/comp.lang.python/msg/028422d707512283


1
Di ruby, Anda cukup membekukan array Anda untuk mengubahnya menjadi sesuatu yang tidak dapat diubah
user163365

Pos luar biasa oleh Alex Martelli :)
Skilldrick

8

Saya tidak yakin tentang ini, jadi saya menambahkannya sebagai jawaban terlebih dahulu.

Python memperlakukan metode tidak terikat sebagai fungsi

Itu berarti Anda dapat memanggil metode seperti theobject.themethod()atau dengan TheClass.themethod(anobject).

Sunting: Meskipun perbedaan antara metode dan fungsi kecil di Python, dan tidak ada di Python 3, itu juga tidak ada di Ruby, hanya karena Ruby tidak memiliki fungsi. Saat Anda mendefinisikan fungsi, Anda sebenarnya mendefinisikan metode pada Objek.

Tetapi Anda masih tidak dapat menggunakan metode satu kelas dan memanggilnya sebagai fungsi, Anda harus mengikatnya kembali ke objek yang ingin Anda panggil, yang jauh lebih banyak rintangan.


Ruby tidak memiliki fungsi sama sekali. Bisa dikatakan, TheClass.instance_method(:themethod).bind(anobject).callakan menjadi ruby ​​yang setara.
Logan Capaldo

Oh. Jadi, ada semacam kelas utama ajaib saat Anda mendefinisikan fungsi yang tidak ada di kelas eksplisit?
Lennart Regebro

Ya, metode yang ditentukan di tingkat atas adalah metode privat Object.
Logan Capaldo

1
FWIW, tampaknya dalam Python, fungsi dan metode sebenarnya adalah tipe yang sama, dan perilakunya yang berbeda berasal dari deskriptor: users.rcn.com/python/download/… .
Bastien Léonard

1
Tetapi jika Anda mengikatnya ke suatu objek, maka itu tidak terlepas. Duh. :-) Dan mereka juga sama dengan Python. Hanya saja Ruby sebenarnya tidak memiliki fungsi. Dan itu berarti pernyataan saya benar. Anda dapat memanggil metode tidak terikat seolah-olah itu adalah fungsi dalam Python. Dan itu sebenarnya berguna, itu berarti misalnya Anda dapat memanggil metode yang ditentukan pada kelas pada objek yang tidak memiliki kelas itu, yang terkadang berguna.
Lennart Regebro

7

Saya ingin menyebutkan API deskriptor Python yang memungkinkan seseorang menyesuaikan "komunikasi" objek-ke-atribut. Perlu juga dicatat bahwa, dengan Python, seseorang bebas mengimplementasikan protokol alternatif melalui menimpa default yang diberikan melalui implementasi default __getattribute__metode tersebut. Izinkan saya memberikan lebih banyak detail tentang hal tersebut di atas. Deskriptor adalah kelas reguler dengan __get__, __set__dan / atau __delete__metode. Ketika juru bahasa menemukan sesuatu seperti anObj.anAttr, berikut ini dilakukan:

  • __getattribute__metode anObjdipanggil
  • __getattribute__ mengambil objek anAttr dari kelas dict
  • itu memeriksa apakah objek abAttr memiliki __get__, __set__atau __delete__objek yang dapat dipanggil
  • konteks (yaitu, objek pemanggil atau kelas, dan nilai, bukan yang terakhir, jika kita memiliki penyetel) diteruskan ke objek yang dapat dipanggil
  • hasilnya dikembalikan.

Seperti yang telah disebutkan, ini adalah perilaku default. Satu bebas untuk mengubah protokol dengan mengimplementasikan ulang __getattribute__.

Teknik ini jauh lebih kuat daripada dekorator.


6

Ruby memiliki dukungan kelanjutan bawaan menggunakan callcc.

Karenanya Anda dapat menerapkan hal-hal keren seperti amb-operator


Saya berharap saya mengerti callcc. Dapatkah Anda memberikan skenario aplikasi yang lebih biasa daripada Operator Ambigu McCarthy, untuk menghargai manfaatnya? Maksudku sesuatu di dunia nyata, bukan CS yang funky ?!
ThomasH

"Hal-hal CS yang funky" itu nyata. Luangkan waktu untuk belajar: intertwingly.net/blog/2005/04/13/Continuations-for-Curmudgeons
Stephen Eilert


5

Python memiliki docstrings dan ruby ​​tidak ... Atau jika tidak, mereka tidak dapat diakses semudah di python.

Ps. Jika saya salah, tolong, tinggalkan contoh? Saya memiliki solusi yang saya bisa monkeypatch ke dalam kelas dengan cukup mudah tetapi saya ingin memiliki semacam fitur docstring dalam "cara asli".


3
tidak memiliki docstring, tapi, memiliki RDoc. Jadi ya, tidak mudah diakses, tapi tidak 100% tersembunyi.
Omar Qureshi

Ruby tidak menggunakan docstrings. Itu melakukan dokumentasi dengan cara yang berbeda.
Chuck

1
Omar: ya, saya tahu tentang rdoc tapi afaik, mereka tidak "semudah itu" seperti docstrings python. Sebagai contoh, jika saya memiliki sebuah kelas dan saya ingin mengeluarkan dokumentasi rdoc dari dalam kelas pekerjaannya yang cukup lumayan. Apa yang telah saya lakukan adalah bahwa saya menghasilkan dokumentasi ri yang saya coba untuk tetap up2date dan kemudian mengambil info itu sendiri. Jelas tidak sampai pada level yang sama dengan docstrings python ..
rasjani

Docstrings dapat digunakan untuk menyediakan doctests. Apakah ada yang seperti itu untuk Ruby?
Lennart Regebro

2
Ya, ini disebut "Ruby Doctest". Sejauh menyangkut doctests, yang paling penting adalah Anda memiliki dokumentasi yang dapat dibaca di suatu tempat yang menyertakan cuplikan kode yang dapat diuji - tidak ada bedanya apakah itu dalam docstring atau dalam komentar.
Chuck

5

Ruby memiliki perulangan baris demi baris di atas file input (tanda '-n') dari baris perintah sehingga dapat digunakan seperti AWK. Ruby one-liner ini:

ruby -ne 'END {puts $.}'

akan menghitung baris seperti satu baris AWK:

awk 'END{print NR}'

Ruby mendapatkan fitur ini melalui Perl, yang mengambilnya dari AWK sebagai cara agar sysadmin bergabung dengan Perl tanpa harus mengubah cara mereka melakukan sesuatu.


1
Saya ingin menambahkan bahwa dukungan baris perintah Python agak lemah. Selain loop otomatis yang hilang, Anda tidak dapat menempatkan beberapa pernyataan dalam satu baris dan meneruskannya sebagai argumen baris perintah string tunggal ke interpreter. Setidaknya saya gagal melakukannya.
ThomasH

Tentu saja Anda bisa. Tetapi Anda (seperti halnya bahasa lain) perlu menyertakan tanda kutip.
Lennart Regebro

Python tidak dibuat untuk digunakan pada baris perintah, karena Anda harus eksplisit tentang beberapa hal (seperti sys.stdin) jika Anda ingin menggunakannya seperti itupython -c "import sys; print len(list(sys.stdin))"
u0b34a0f6ae

5

Ruby memiliki sigil dan ranting, Python tidak.

Sunting : Dan satu hal yang sangat penting yang saya lupa (setelah semua, yang sebelumnya hanya nyala sedikit :-p):

Python memiliki kompiler JIT ( Psyco ), bahasa tingkat yang lebih rendah untuk menulis kode yang lebih cepat ( Pyrex ) dan kemampuan untuk menambahkan kode C ++ inline ( Weave ).


Benar, tapi itu hanya sintaks.
Lennart Regebro

6
Nah, jika Anda ingin menempuh jalan itu: keduanya lengkap Turing. Yang lainnya hanyalah sintaks.
Jörg W Mittag

Ya dan perbedaan sintaks importax ;-)
fortran

1
Seberapa penting jika Anda menulis @foo atau self.foo?
Lennart Regebro

1
@ Jörg: Oke, sebut saja selain "sintaks". Intinya adalah @foo dan self.foo melakukan hal yang sama, sebenarnya ini bukan fungsi yang dimiliki Ruby dan Python tidak.
Lennart Regebro

5

Python saya berkarat, jadi beberapa di antaranya mungkin ada di python dan saya tidak ingat / tidak pernah belajar di tempat pertama, tetapi berikut adalah beberapa yang pertama saya pikirkan:

Spasi Putih

Ruby menangani whitespace yang sangat berbeda. Sebagai permulaan, Anda tidak perlu membuat indentasi apa pun (yang berarti tidak masalah jika Anda menggunakan 4 spasi atau 1 tab). Itu juga melakukan kelanjutan smart line, jadi yang berikut ini valid:

def foo(bar,
        cow)

Pada dasarnya, jika Anda mengakhiri dengan operator, itu akan mencari tahu apa yang sedang terjadi.

Mixins

Ruby memiliki mixin yang dapat memperluas instance, bukan kelas penuh:

module Humor
  def tickle
    "hee, hee!"
  end
end
a = "Grouchy"
a.extend Humor
a.tickle    »   "hee, hee!"

Enum

Saya tidak yakin apakah ini sama dengan generator, tetapi pada Ruby 1.9 ruby ​​sebagai enum, jadi

>> enum = (1..4).to_enum
=> #<Enumerator:0x1344a8>

Referensi: http://blog.nuclearsquid.com/writings/ruby-1-9-what-s-new-what-s-changed

"Argumen Kata Kunci"

Kedua item yang terdaftar di sana didukung di Ruby, meskipun Anda tidak dapat melewatkan nilai default seperti itu. Anda bisa pergi secara berurutan

def foo(a, b=2, c=3)
  puts "#{a}, #{b}, #{c}"
end
foo(1,3)   >> 1, 3, 3
foo(1,c=5) >> 1, 5, 3
c          >> 5

Perhatikan bahwa c = 5 sebenarnya memberikan variabel c dalam lingkup panggilan nilai 5, dan menetapkan parameter b nilai 5.

atau Anda dapat melakukannya dengan hash, yang membahas masalah kedua

def foo(a, others)
  others[:b] = 2 unless others.include?(:b)
  others[:c] = 3 unless others.include?(:c)
  puts "#{a}, #{others[:b]}, #{others[:c]}"
end
foo(1,:b=>3) >> 1, 3, 3
foo(1,:c=>5) >> 1, 2, 5

Referensi: Panduan Progammer Pragmatis untuk Ruby


Contoh kedua Anda foo (1, c = 5) tidak melakukan apa yang Anda pikirkan. Ruby tidak memiliki parameter bernama.
horseyguy

5
Python memiliki kelanjutan baris implisit di dalam tanda kurung (, [atau{
u0b34a0f6ae

5

Anda dapat memiliki kode dalam definisi kelas di Ruby dan Python. Namun, di Ruby Anda memiliki referensi ke kelas (mandiri). Dengan Python Anda tidak memiliki referensi ke kelas tersebut, karena kelas tersebut belum ditentukan.

Sebuah contoh:

class Kaka
  puts self
end

self dalam hal ini adalah kelas, dan kode ini akan mencetak "Kaka". Tidak ada cara untuk mencetak nama kelas atau dengan cara lain mengakses kelas dari badan definisi kelas dengan Python.


Bisakah Anda memberikan detail lebih lanjut (seperti kode) untuk poin pertama Anda?
Loïc Wolff

Kode contoh adalah ide yang bagus, saya menambahkan, meskipun kasus ini sepele.
Lennart Regebro

@SilentGhost: Saya tidak bisa memikirkan salah satu yang tidak terlalu jelas sekarang. :)
Lennart Regebro

Anda dapat mengakses nama kelas di dalam kelas dengan python: class foo (): def init __ (self): print self .__ class .__ name__
txwikinger

1
@txwikinger: ya, tetapi tidak di dalam badan kelas, yang dijalankan bersamaan dengan classpernyataan.
Bastien Léonard

4

Sintaks bukanlah hal yang kecil, ia berdampak langsung pada cara kita berpikir. Ini juga memiliki efek langsung pada aturan yang kami buat untuk sistem yang kami gunakan. Sebagai contoh, kita memiliki urutan operasi karena cara kita menulis persamaan atau kalimat matematika. Notasi standar untuk matematika memungkinkan orang membacanya lebih dari satu cara dan sampai pada jawaban yang berbeda dengan persamaan yang sama. Jika kita menggunakan awalan atau notasi postfix kita akan membuat aturan untuk membedakan angka yang akan dimanipulasi daripada hanya memiliki aturan untuk urutan menghitung nilai.

Notasi standar memperjelas angka apa yang kita bicarakan sambil membuat urutan penghitungannya menjadi ambigu. Prefix dan notasi postfix membuat urutan penghitungan menjadi polos sambil membuat angka menjadi ambigu. Python sudah memiliki lambda multiline jika bukan karena kesulitan yang disebabkan oleh spasi putih sintaksis. (Ada proposal untuk menarik hal semacam ini tanpa perlu menambahkan pembatas blok secara eksplisit.)

Saya merasa lebih mudah untuk menulis kondisi di mana saya ingin sesuatu terjadi jika kondisi salah jauh lebih mudah untuk menulis dengan pernyataan kecuali di Ruby daripada konstruksi "jika-tidak" yang setara secara semantik di Ruby atau bahasa lain misalnya. Jika sebagian besar bahasa yang digunakan orang saat ini memiliki kekuatan yang sama, bagaimana sintaks setiap bahasa dapat dianggap sebagai hal yang sepele? Setelah fitur khusus seperti blok dan mekanisme pewarisan, dll. Sintaks adalah bagian terpenting dari sebuah bahasa, hampir tidak merupakan hal yang dangkal.

Apa yang dangkal adalah kualitas estetika keindahan yang kita anggap berasal dari sintaksis. Estetika tidak ada hubungannya dengan cara kerja kognisi kita, sintaks.


"Komentar" ini tiga kali lebih panjang dari yang diizinkan dalam sebuah komentar, terlepas dari rep.
Andrew Grimm

Ini sebenarnya tampak bagus sebagai jawaban bagi saya. Mengedit sedikit "ini adalah komentar".
Bill the Lizard

3

Terkejut melihat tidak ada yang disebutkan tentang mekanisme "metode hilang" ruby. Saya akan memberikan contoh metode find_by _... di Rails, sebagai contoh kekuatan fitur bahasa tersebut. Dugaan saya adalah bahwa sesuatu yang serupa dapat diterapkan dengan Python, tetapi sepengetahuan saya itu tidak ada secara asli.


Python memiliki get_attribute , yang pada dasarnya menyelesaikan hal yang sama dengan method_missing Ruby.
mipadi

3
Mengapa pengembang python selalu terluka parah ketika ruby ​​disebutkan DI MANA SAJA? Anda tidak dapat menyangkal ini tidak benar.
aarona

method_missingdapat ditiru di Python dalam beberapa kasus: class M(): def __getattr__(self, n): return lambda: "Missing! " + n; M().hi(). Namun, ada sedikit perbedaan dan saya ragu itu idiomatis dengan Python :-)

1
@DJTripleThreat: Saya menyangkal bahwa itu benar.
Lennart Regebro

3

Perbedaan lain dalam lambda antara Python dan Ruby ditunjukkan oleh masalah Generator Akumulator Paul Graham . Dicetak ulang di sini:

Tulis fungsi foo yang mengambil angka n dan mengembalikan fungsi yang mengambil angka i, dan mengembalikan n ditambah dengan i. Catatan: (a) itu angka, bukan integer, (b) itu bertambah, bukan plus.

Di Ruby, Anda dapat melakukan ini:

def foo(n)
  lambda {|i| n += i }
end

Dengan Python, Anda akan membuat objek untuk menampung keadaan n:

class foo(object):
    def __init__(self, n):
        self.n = n
    def __call__(self, i):
        self.n += i
        return self.n

Beberapa orang mungkin lebih suka pendekatan Python eksplisit karena lebih jelas secara konseptual, bahkan jika itu sedikit lebih bertele-tele. Anda menyimpan keadaan seperti yang Anda lakukan untuk hal lain. Anda hanya perlu memikirkan gagasan tentang objek yang dapat dipanggil. Tetapi terlepas dari pendekatan mana yang lebih disukai secara estetika, itu menunjukkan satu hal di mana Ruby lambda adalah konstruksi yang lebih kuat daripada Python.


3
Anda tidak bisa menambah angka dengan Python, jadi pembatasan itu tidak masuk akal. Dalam Python angka tidak dapat diubah. Jika kita mengubahnya menjadi "plus", kelas tersebut tidak diperlukan. Karenanya ini tidak menunjukkan apa pun tentang perbedaan lambda, tetapi perbedaan dalam cara kerja angka. Kecuali tentu saja Anda membuat kelas angka yang bisa berubah. :)
Lennart Regebro

2
Batasan ada untuk memperjelas perilaku yang diinginkan. Masalah yang ditanyakan adalah: f = foo (10) f (2) >> 12 f (3) >> 15 ... lambda {| i | n + i} memberikan: f = foo (10) f (2) >> 12 f (3) >> 13 ... Angka juga tidak dapat diubah di Ruby - Anda tidak bisa mengatakan 2 + = 1 misalnya. Dan n + = 1 baik-baik saja dalam fungsi Python biasa, tetapi bukan lambda. Jadi masalahnya adalah apa itu "n", fakta bahwa itu dibuat ketika fungsi dipanggil dan lambda terbentuk, bahwa Anda dapat melakukan penugasan dalam lambda (bukan hanya ekspresi), dan dapat menampung nilai n melalui beberapa panggilan.
asrama

Saya tidak berpikir Anda perlu terlalu jauh dengan Python. Fungsi dapat didefinisikan dalam fungsi lain. def foo(n): def f(i): return n + i return f.
FMc

2
Ini masih tidak sama, dan contoh Anda setara dengan lambda Python di komentar di atas. Versi Ruby membuat lambda yang menjaga status antar panggilan. Contoh yang Anda posting memungkinkan Anda mengkonfigurasi nilai awal untuk n, tetapi fungsi yang dikembalikan foo akan selalu memiliki nilai awal tersebut. Versi Ruby bertambah. Jadi katakanlah f = foo (10). Versi Python: f (1) => 11, f (1) => 11. Versi Ruby f.call (1) => 11, f.call (1) => 12.
dormsbee

def foo(n): L=[n] def f(i): L[0] += i return L[0] return f. Di Python3 Anda bisa menggunakan nonlocalkata kunci.
jfs

3

python memberi nama argumen opsional

def func(a, b=2, c=3):
    print a, b, c

>>> func(1)
1 2 3
>>> func(1, c=4)
1 2 4

AFAIK Ruby hanya memposisikan argumen karena b = 2 dalam deklarasi fungsi merupakan pengaruh yang selalu ditambahkan.


3
apa artinya "Ruby hanya memposisikan argumen karena b = 2 dalam deklarasi fungsi adalah pengaruh yang selalu menambahkan" bahkan artinya?
horseyguy

3
Entah di planet mana Anda tinggal, tetapi def my_method(param1, optional = false)bekerja di Ruby 1.8.6, 1.8.7, dan mungkin 1.9!
Robert K

5
The Wicked Flea, dan orang-orang yang memberikan suara positif pada komentarnya, Anda tidak melihat contoh tersebut dengan cukup dekat. Dia dapat melewati bparameter dalam funcpanggilan dan masih mempertahankan defaultnya. Artinya, badalah argumen kedua dalam tanda tangan, tetapi dia bisa melewatinya dengan mengawali parameter kedua dengan c=. Ruby menggunakan hash untuk mensimulasikan ini, tetapi tidak persis sama.
maček

2

Ruby memiliki dokumentasi tertanam:

 =begin

 You could use rdoc to generate man pages from this documentation

 =end

5
Docstrings berakhir sebagai bagian dari metode / kelas yang Anda atur. Jadi Anda dapat melakukan bantuan (kelas) dan itu akan menunjukkan kepada Anda dokumennya, dll.
Lennart Regebro


2

Di Ruby, saat Anda mengimpor file dengan require, semua hal yang ditentukan dalam file itu akan berakhir di namespace global Anda.

Dengan Cargo Anda dapat " meminta pustaka tanpa mengacaukan namespace Anda ".

# foo-1.0.0.rb
class Foo
  VERSION = "1.0.0"
end

# foo-2.0.0.rb
class Foo
  VERSION = "2.0.0"
end
>> Foo1 = import ("foo-1.0.0")
>> Foo2 = impor ("foo-2.0.0")
>> Foo1 :: VERSI
=> "1.0.0"
>> Foo2 :: VERSION
=> "2.0.0"

Ini seharusnya menjadi komentar, bukan jawaban baru.
Lennart Regebro
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.