はじめに
この記事は主に Python3 について取り扱っています.Python2 ではお話が変わってくるかもしれません
みなさんSwiftのextension(拡張メソッド,プロパティなど)ってご存知でしょうか?
まずは以下をご覧ください.
class Person {
var name = ""
init(name: String) {
self.name = name
}
}
extension Person {
func say_hello() {
print("Hello, my name is " + self.name)
}
}
var p = Person(name: "Tom")
p.say_hello()
出力
Hello, my name is Tom
このように既存のクラスに対してメソッドとかを直接拡張することができます.
まあこの程度なら最初からPersonにsay_hello()実装すればよくね?って思うわけです.
ところがこんなこともできます.
import Foundation
extension String {
func remove_spaces() -> String {
return self.replacingOccurrences(of: " ", with: "")
}
}
print("hello world !".remove_spaces())
出力
helloworld!
そうです,既存のクラスでもextensionすることができます.
Python でもやりたい!
以下のようにしてそれっぽく出来ます.
class Person():
def __init__(self, name):
self.name = name
def ex_func(self):
print("Hello, my name is", self.name)
Person.say_hello = ex_func
p = Person("Tom")
p.say_hello()
出力
Hello, my name is Tom
やったぜ。
じゃあこれもきっと......
def ex_func(self):
return self.replace(" ", "")
str.remove_spaces = ex_func
print("hello world !")
あるぇ??
TypeError: can't set attributes of built-in/extension type 'str'
built-inクラスは拡張できないようです.
禁断の果実
まずはやってみよう
forbiddenfruitというライブラリをインストールしましょう.
pip install forbiddenfruit
from forbiddenfruit import curse
def remove_spaces(self):
return self.replace(" ", "")
curse(str, "remove_spaces", remove_spaces)
print("hello world !".remove_spaces())
やったぜ。
helloworld!
使い方
登録
curse([built-inクラス], [登録名], [メソッドとか])
禁断の果実とか呪うとかなんだか恐ろしいライブラリですね.
解除
from forbiddenfruit import reverse
reverse([built-inクラス], [登録名])
どういう仕組みなんだこれ......
extension の難点
こうして見るとなかなかに便利で可読性が上がりそうな extension ですが,多用するのはあまり良くないと思います.
とりわけPythonは任意のタイミングで付与することができ,さらに既にインスタンスを生成済みのオブジェクトにまで影響を及ぼすためです.
また以下のような難点も有ります.
extension はある意味クラスを継承せずとも,新たなメソッドやプロパティなどを追加できます.
しかし,他人からしたら知らないメソッドなどをいつでも追加できてしまう というのは可読性を下げうる欠点となりえます.
ある人にとっての remove_spaces
は半角スペースを削除するメソッドであっても,ある人にとっては全角スペースを削除するメソッドとして想定しているかもしれません.
同じ str
,同じ意味の名前のメソッドで挙動が異なると多くの人は混乱するでしょう.
このような混乱を避けるためにbuilt-inクラスに関しては拡張できないように制限されているのかもしれませんね.