2009-04-04 9 views
14

In molte discussioni ho sentito parlare di Ruby in cui le persone hanno espresso le loro riserve sulla lingua, il problema delle patch delle scimmie emerge come una delle loro preoccupazioni principali.Se la patch della scimmia è permessa sia in Ruby che in Python, perché è più controversa in Ruby?

Tuttavia, raramente ascolto gli stessi argomenti nel contesto di Python anche se è consentito anche in Python.

Perché questa distinzione?

Python include diversi tipi di protezioni per ridurre al minimo i rischi di questa funzionalità?

+1

È più comune in Javascript che in Python, probabilmente altrettanto comune come in Ruby, se non di più –

risposta

16

Come programmatore Python che ha avuto un assaggio di Ruby (e gli piace), Penso che ci sia un parallelo piuttosto ironico a quando Python stava iniziando a diventare popolare.

C e i programmatori Java "bash" Python, affermando che non era un linguaggio reale, e che la natura dinamica dei suoi tipi sarebbe pericolosa e consentirebbe alle persone di creare codice "cattivo". Come Python è diventato più popolare, ed i vantaggi del suo tempo rapido sviluppo è diventato evidente, per non parlare della sintassi meno prolissa:

// Java 
Person p = new Person(); 
# Python 
p = Person() 

abbiamo iniziato a vedere alcune caratteristiche più dinamiche appaiono nelle versioni successive di Java. Autoboxing e -unboxing rendono meno problematico affrontare le primitive e Generics ci consente di codificare una volta e applicarlo a molti tipi.

E 'stato con un certo divertimento che ho visto una delle principali caratteristiche flessibili di Ruby - Monkey Patching, propagandato come pericoloso dal pubblico di Python. Avendo iniziato a insegnare a Ruby agli studenti quest'anno, penso che essere in grado di "aggiustare" l'implementazione di una classe esistente, anche quella che fa parte del sistema, sia molto potente.

Certo, si può rovinare male e il programma può bloccarsi. Posso anche segfault in C abbastanza facilmente. E le app Java possono morire di morte fiammeggiante.

La verità è che vedo Patch per le scimmie come il prossimo passo nella dinamica e nella meta-programmazione. Divertente, dal momento che è stato in giro da Smalltalk.

+3

Ho sentito il termine "duck-punching" usato nella stessa vena di "monkey-patching" ". È un po 'un gioco di "duck typing" (se cova come un'anatra, allora potrebbe anche essere un'anatra, anche se è un numero intero). Se non cova come un'anatra, la colpisci finché non lo fa (aggiungi nuovi metodi, ecc.). –

15

Le lingue potrebbero consentirlo, ma nessuna delle due comunità lo condona. Monkeypatching non è perdonato in nessuna delle due lingue, ma ne senti parlare più spesso in Ruby perché la forma di open class che usa rende molto, molto facile da monkeypatch una classe e per questo, it's more acceptable in the Ruby community, but still frowned upon. Monkeypatching semplicemente non è così diffuso o facile in Python, ed è per questo che non sentirai gli stessi argomenti contro di essa in quella comunità. Python non fa nulla che Ruby non faccia per impedire la pratica.

La ragione che si sente/leggere su di esso più spesso in Ruby è che questo in Ruby:

class MyClass 
    def foo 
    puts "foo" 
    end 
end 
class MyClass 
    def bar 
    puts "bar" 
    end 
end 

vi darà una classe che contiene due metodi, foo e bar, che tale in Python :

class MyClass: 
    def foo(self): 
     print "foo" 
class MyClass: 
    def bar(self): 
     print "bar" 

vi lascerà con una classe che contiene solo il m ethod bar, poiché la ridefinizione di una classe elimina completamente la definizione precedente. Per monkeypatch in Python, in realtà si deve scrivere questo:

class MyClass: 
    def foo(self): 
     print "foo" 
def bar(self): 
    print "bar" 
MyClass.bar = bar 

che è più duro rispetto alla versione di Ruby. Questo da solo rende il codice Ruby molto più facile da monkeypatch rispetto al codice Python.

+0

Anche l'esempio Python è valido. La seconda definizione crea solo una nuova classe MyClass e non estende quella precedente (suppongo che questo sia ciò che fa ruby). –

+0

Dovresti aggiungere una nota che è tecnicamente valida – hasen

+0

Puoi fornire qualche riferimento che mostra la "comunità" Ruby che non condona la pratica? Che dire di ActiveSupport :: CoreExtensions? –

13

"Python include diversi tipi di protezioni per ridurre al minimo i rischi di questa funzionalità?"

Sì. La comunità si rifiuta di farlo. La salvaguardia è interamente sociale.

21

È una tecnica meno praticata in Python, in parte perché le classi "core" in Python (quelle implementate in C) non sono realmente modificabili. In Ruby, d'altra parte, a causa del modo in cui è implementato internamente (non meglio, solo diverso), praticamente tutto può essere modificato dinamicamente.

Filosoficamente, è qualcosa che tende a essere disapprovato all'interno della comunità Python, decisamente meno nel mondo Ruby. Non so perché affermi che è più controverso (puoi collegarti a un riferimento autorevole?) - la mia esperienza è stata che la patch delle scimmie è una tecnica accettata se l'utente deve essere consapevole delle possibili conseguenze.

+0

Non posso parlare della community di Ruby, quindi ti prendo atto che la monkeypatching è accettata lì, ma se entri in una stanza piena di sviluppatori Python e chiedi loro cosa pensano di Ruby, sei più probabile che non sentire il termine "patch per scimmia", e non in una luce positiva. –

+0

Sì, ma "controverso tra programmatori Python" è diverso da "controverso tra programmatori Rub". Mentre è possibile eseguire il patch-patch in Python (e riconosciuto come a volte utile ma pericoloso), ci sono un certo numero di funzionalità linguistiche di Ruby che sembrano incoraggiarlo attivamente. –

+0

(argh, che dovrebbe essere "controverso tra i programmatori Ruby" sopra, ovviamente ...) –

3

In realtà in Python è un po 'più difficile modificare i tipi di base.

Ad esempio, immagina di ridefinire l'intero.

Rubino:

class Fixnum 
    def *(n) 
     5 
    end 
end 

Ora 2 * 2 rendimenti 5.

Python:

>>> class int(int): 
    def __mul__(self, x): 
     return 5 


>>> 2*2 
4 
>>> int(2)*int(2) 
5 
+0

Questo esempio di Ruby non fa quello che pensi. Ciò renderebbe così che tu farebbe Integer.times {| five | "Il numero è uno in meno di # {cinque + 1}"} e restituirà 6. 2 * 2, tuttavia, sarebbe ancora 4. Volete la classe Fixnum; def * (n); 5; fine; fine . – Chuck

+0

@Chuck: grazie, non ho molta esperienza con Ruby (ancora), sono un ragazzo di Python ;-) – vartec

3

In Python, qualsiasi letterale ("", {}, 1.0, ecc) crea un'istanza della classe standard, anche se si è tentato di monkeypatch e ridefinito il corrispondente classe nello spazio dei nomi.

Semplicemente non funzionerà come previsto:

class str(): 
    # define your custom string type 
    ... 

a = "foo"  # still a real Python string 
a = str("foo") # only this uses your custom class 
+0

Ruby funziona allo stesso modo, quindi non è una differenza. Se io 'def String.new (* args, & block); Array.nuovo; end' in Ruby, anche se 'String.new (" pippo ")' risulta in '[]', '" pippo "' risulta ancora in '" pippo "'. –

+0

Considerate questo pezzo di rubino: –

2

penso che patch scimmia deve essere utilizzato solo come ultima soluzione.

Normalmente i programmatori Python sanno come si comportano una classe o un metodo. Sanno che la classe xxx sta facendo le cose in un certo modo.

Quando si esegue il patch di una classe o di un metodo, si modifica il suo comportamento. Altri programmatori Python che usano questa classe possono essere molto sorpresi se quella classe si comporta diversamente.

Il modo normale di fare le cose è la sottoclasse. In questo modo, altri programmatori sanno che stanno usando un oggetto diverso. Possono usare la classe originale o la sottoclasse se scelgono di farlo.

+0

Cosa succede se non ci sono altri programmatori Python che usano uno script? O lo script è breve? Il tipo di argomenti "pericolosi" che sentiamo è molto valido quando si tratta di un progetto 50 + kLOC. Per le sceneggiature di piccole dimensioni, tuttavia, non essere in grado di convertire denaro può significare da decine a centinaia di righe di testo per una sceneggiatura che altrimenti sarebbe lunga alcune righe. Mi piacerebbe un 'python sciatto' per piccoli script (dove ogni programmatore competente può leggere e ricordare l'intera cosa in pochi minuti). La maggior parte delle discipline di ingegneria del software sono per grandi progetti. –

1

Se si desidera eseguire alcune patch di scimmia in Python, è relativamente semplice, purché non si modifichi un tipo predefinito (int, float, str).

class SomeClass: 
    def foo(self): 
     print "foo" 

def tempfunc(self): 
    print "bar" 
SomeClass.bar = tempfunc 
del tempfunc 

Questo aggiungerà il metodo bar a SomeClass e anche le istanze esistenti di quella classe possono utilizzare quel metodo iniettato.

+0

Anche not-monkey-patchable: datetime.datetime, datetime.timedelta e molti altri ancora. Peccato, perché ci sono modi in cui voglio estendere queste lezioni spesso. –

Problemi correlati