デフォルト引数を使って偽のアヒルを作る
まずは見ての通りの物を。言語はPython。
>>> def hideyoshi(bird): #鳥を受け取ると鳴かせてみせる関数。 ... bird.quack() ... >>> class Duck: ... def quack(self): ... print "ガァガァ" ... >>> duck = Duck() >>> hideyoshi(duck) ガァガァ >>> >>> class RoboDuck: #アヒルのように鳴くならアヒルを継承する必要は無い。 ... def quack(self): ... print "ガーガー" ... >>> roboduck = RoboDuck() >>> hideyoshi(roboduck) #秀吉はロボでも満足。 ガーガー >>> >>> class BrokenRoboDuck: ... def quack(self, times): #壊れたロボアヒルはtimes回鳴く。 ... print "ガー"*times ... >>> brokenroboduck = BrokenRoboDuck() >>> hideyoshi(brokenroboduck) #秀吉は壊れたロボアヒルを鳴かせようとするが、失敗する。 Traceback (most recent call last): File "<stdin>", line 1, in ? File "<stdin>", line 2, in hideyoshi TypeError: quack() takes exactly 2 arguments (1 given) >>> >>> class RepairedBrokenRoboDuck: ... def quack(self, times=3): ... print "ガー"*times ... >>> repaired_duck = RepairedBrokenRoboDuck() >>> hideyoshi(repaired_duck) #修理済ロボアヒルはデフォルト引数がついてるので大丈夫。 ガーガーガー
BrokenRoboDuckではquackが引数を要求するので、引数を与えようとしない秀吉はBrokenRoboDuckを鳴かせることができない。
しかし、追加された引数にデフォルト引数を設定しておけば(RepairedBrokenRoboDuck)秀吉は鳴かせることができる。
他の言語ではどうだか知らないけど、Pythonのデフォルト引数ってのはなかなか便利だし面白いと思う。
どんなときに使いたいと考えたか
例えば角度angleと威力powerを設定して弾bulletを撃つfire(angle, power, bullet=Bullet)があるとする。
BulletのコンストラクタはBullet(angle,power)だというので、fire()は内部でbullet(angle,power)という式で弾を作るとする(引数bulletで指定されたクラスで弾を作る)。
ところがBulletのサブクラスにLaserBulletがあったとして、LaserBulletのコンストラクタはLaserBullet(angle,power,length)だったとする。
するとfire内部での弾作りでは引数にangle,powerしか使わないので、lengthが無いためLaserBulletの生成に失敗してしまう。例えばfire(30,5,LaserBullet)という式は失敗する。
しかしここでLaserBulletのコンストラクタで引数lengthにデフォルト引数が設定してあったとする(def __init__(self,angle,power,length=10)のような感じ)。
するとfire内部ではlengthを設定しないけれどもデフォルト引数を使ってLaserBulletを撃つことができる(fire(30,5,LaserBullet)が上手くいく)。
この例だとそもそも設計が悪いんじゃないかという話になるけど、何はともあれこれに類する事態で何とかできるのでサブクラスを作りやすい、かも知れない。