私が聞いた Ruby についての多くの議論では、人々がこの言語について留保を表明していましたが、モンキー パッチの問題が彼らの主要な関心事の 1 つとして取り上げられました。
ただし、Python 言語でも許可されていますが、Python のコンテキストで同じ議論が行われることはめったにありません。
なぜこの区別?
Python には、この機能のリスクを最小限に抑えるためのさまざまなタイプのセーフガードが含まれていますか?
私が聞いた Ruby についての多くの議論では、人々がこの言語について留保を表明していましたが、モンキー パッチの問題が彼らの主要な関心事の 1 つとして取り上げられました。
ただし、Python 言語でも許可されていますが、Python のコンテキストで同じ議論が行われることはめったにありません。
なぜこの区別?
Python には、この機能のリスクを最小限に抑えるためのさまざまなタイプのセーフガードが含まれていますか?
Python の「コア」クラス (C で実装されたもの) は実際には変更できないため、Python ではあまり実践されていない手法です。一方、Ruby では、内部で実装されている方法 (より優れているというよりは、単に異なるだけです) により、ほぼすべてのものを動的に変更できます。
哲学的には、これは Python コミュニティ内で嫌われる傾向にあるものですが、Ruby の世界ではそうではありません。それがより物議を醸していると主張する理由がわかりません(信頼できる参照にリンクできますか?)-私の経験では、ユーザーが起こりうる結果を認識している必要がある場合、モンキーパッチは受け入れられた手法です。
言語はそれを許可するかもしれませんが、どちらのコミュニティもその慣習を容認しません。モンキーパッチはどちらの言語でも容認されていませんが、Ruby ではより頻繁に耳にします。なぜなら、それが使用するオープン クラスの形式により、クラスへのモンキーパッチが非常に簡単になり、このため、Ruby コミュニティではより受け入れられるからです。まだ眉をひそめています。モンキーパッチは、Python では一般的ではなく、簡単でもありません。そのため、そのコミュニティでモンキーパッチに対する同じ議論を聞くことはありません。Python は、この慣習を防ぐために Ruby がしないことは何もしません。
Ruby でそれについてよく耳にしたり読んだりする理由は、Ruby では次のようになるからです。
class MyClass
def foo
puts "foo"
end
end
class MyClass
def bar
puts "bar"
end
end
foo
は、との 2 つのメソッドを含むクラスを提供しますが、bar
これは Python では次のようになります。
class MyClass:
def foo(self):
print "foo"
class MyClass:
def bar(self):
print "bar"
bar
クラスの再定義は以前の定義を完全に上書きするため、 method のみを含むクラスが残ります。Python でモンキーパッチを適用するには、実際には次のように記述する必要があります。
class MyClass:
def foo(self):
print "foo"
def bar(self):
print "bar"
MyClass.bar = bar
これは Ruby バージョンよりも難しいです。それだけでも、Ruby コードは Python コードよりもモンキーパッチがはるかに簡単になります。
Ruby に少し慣れた (そして好きな) Python プログラマーとして、Python が人気を博し始めた頃と似たような皮肉な点があると思います。
C と Java のプログラマーは、Python は実際の言語ではなく、その型の動的な性質は危険であり、人々が「悪い」コードを作成できると述べて、Python を「bash」します。Python の人気が高まるにつれ、開発時間の短さの利点が明らかになりました。
// Java
Person p = new Person();
# Python
p = Person()
Java の新しいバージョンでは、より動的な機能がいくつか見られるようになりました。autoboxing と -unboxing により、プリミティブを処理する手間が軽減され、Generics を使用すると、一度コーディングして多くの型に適用できます。
Ruby の主要な柔軟な機能の 1 つである Monkey Patching が、Python の群衆によって危険であると宣伝されているのを見たのは、ちょっとした楽しみでした。今年から学生に Ruby を教え始めたので、システムの一部であっても、既存のクラスの実装を「修正」できることは非常に強力だと思います。
確かに、ひどく失敗する可能性があり、プログラムがクラッシュする可能性があります。私も C でかなり簡単に segfault できます。そして、Java アプリケーションは炎上して死ぬ可能性があります。
実のところ、Monkey Patching は動的およびメタ プログラミングの次のステップであると考えています。Smalltalk の頃からあるので、おかしいです。
「この機能のリスクを最小限に抑えるために、Python にはさまざまな種類のセーフガードが含まれていますか?」
はい。コミュニティはそれを拒否します。セーフガードは完全に社会的です。
実際、Python では、基本型を変更するのは少し難しくなります。
たとえば、整数を再定義するとします。
ルビー:
class Fixnum
def *(n)
5
end
end
2*2 は 5 になります。
パイソン:
>>> class int(int):
def __mul__(self, x):
return 5
>>> 2*2
4
>>> int(2)*int(2)
5
Python では、任意のリテラル ( ""
、{}
、1.0
など) によって標準クラスのインスタンスが作成されます。モンキーパッチを適用して、名前空間で対応するクラスを再定義しようとしてもです。
意図したとおりに機能しません。
class str():
# define your custom string type
...
a = "foo" # still a real Python string
a = str("foo") # only this uses your custom class
サルのパッチは最後の解決策としてのみ使用する必要があると思います。
通常、Python プログラマーは、クラスまたはメソッドがどのように動作するかを知っています。彼らは、クラス xxx が特定の方法で物事を行っていることを知っています。
クラスまたはメソッドにモンキー パッチを適用すると、その動作が変更されます。このクラスを使用している他の Python プログラマーは、そのクラスの動作が異なる場合、非常に驚く可能性があります。
物事を行う通常の方法は、サブクラス化です。そうすれば、他のプログラマーは別のオブジェクトを使用していることを知ることができます。必要に応じて、元のクラスまたはサブクラスを使用できます。
Python でモンキー パッチを適用したい場合、組み込み型 (int、float、str) を変更しない限り、比較的簡単です。
class SomeClass:
def foo(self):
print "foo"
def tempfunc(self):
print "bar"
SomeClass.bar = tempfunc
del tempfunc
これにより、bar メソッドが SomeClass に追加され、そのクラスの既存のインスタンスでさえ、その注入されたメソッドを使用できます。