Python学習【365日チャレンジ!】83日目のマスターU(@Udemy11)です。
ダックだかタッグだかわかりませんが、どんどん内容が難しくなってくるので、酒井さんの講座だけじゃなく、Webからどんどん情報を収集して学習内容をデコレーションしないと理解が追いつかなくなってきました。
シリコンバレーの現役エンジニア酒井さんの講座はこちら
学校の学習にしても、社会人の仕事に関しても、一つの情報源から答えを導き出すのではなく、いくつかの情報源を調べて答えを導き出す必要がありますよね。
集めた情報を噛み砕いて理解するための【情報編集力】が大切なので、しっかりと自分で考える力をつけていかないといけませんね。
それではさっそくPython学習をはじめましょう!
昨日の復習
昨日は、クラスをデータ構造体として取り扱う際の注意点について学習しました。
クラス内で定義した変数への外部からのアクセスをコントロールするために@property
を使って、クラス変数を設定しましたが、クラスの外からクラス変数を直接上書きしてしまえるので、注意が必要でした。
class Person:
def __init__(self, name='male'):
self._gender = name
@property
def gender(self):
return self._gender
p = Person()
print(p._gender)
print(p.gender)
p._gender = 'female'
print(p._gender)
print(p.gender)
出力結果
male
male
female
female
3行目、7行目までのように、_(アンダーバー)
が一つであれば、クラス外からもアクセス可能でしたが、@property
を使うことで元のgender
を読み込み属性にすることができました。
なので、クラス変数のgender
は、外部からは書き換えることはできません。
ただ、直接_gender
を書き換えてしまうと、gender
も上書きされてしまいましたね。
クラス外部から読み込みができないようにするためには、__(アンダーバーアンダーバー)
をつけることでクラス変数にアクセスできなくなりました。
とはいっても、アンダーバー一つのときと同じように、直接__gender
のように指定して変数を定義すると上書きされてしまいましたね。
通常は、インスタンスを作成したあとにクラス変数を作ることはあまりないのですが、上書き可能なので、すでにあるクラス変数を上書きしないように注意する必要がありました。
詳しい内容は、昨日の記事を参考にしてください。
それでは、本日のダックタイピングに入りましょう!
ダックタイピングとは
最初、タッグタイピングだと思ったんですよね。
違う別のクラス同士がタッグを組んでいるから【タッグタイピング】。
そうじゃなくて、ダック(Duck)タイピングで、アヒルさんやカモさんのことなんですよね。
名前がダックタイピングというくらいなので、もとは個別的・特殊的な事例から一般的・普遍的な規則・法則を見出そうとする帰納法の一つである【ダック・テスト】に関係しています。
ダック・テストとは
「農場のそばを歩いている鳥を見たとしよう。鳥は「鴨」という名札をつけてはいない。しかし、鳥は確かに鴨のように見える。また、その鳥は池に入り、鴨のように泳ぐ。そこでその鳥はくちばしを開き、鴨のように鳴く。ここまで来れば、鳥が名札をつけていようがいなかろうが、その鳥が鴨であるという結論にはとっくに達したであろう。」
という、ある者が認識可能な事象から、未知のものの真の姿を推し量ることができるというものである。引用元: ダック・テスト
もうこの時点でわけがわからなくなってきちゃいますが、ここで思考停止に陥ってはいけません!
ダックテストをより単純にすると、
もしもそれがアヒルのように歩き、アヒルのように鳴くのなら、それはアヒルに違いない
ということで、これをPythonのオブジェクトやメソッドに当てはめてみると、
もしもそのオブジェクトがDuck
オブジェクトのようにWalk
メソッドを使えたり、Duck
オブジェクトのようにCry
メソッドを使えたりするのなら、そのオブジェクトはDuck
オブジェクトに違いない
これでもイマイチよくわからないと思うので、実際にコードを書いていきましょう。
コードを書いてみる
まずは、Car
クラスに変数person
を引数にしたride
メソッドを定義して、person.drive()
メソッドを実行するコードを書きます。
class Car:
def ride(self, person):
person.drive()
次にdrive
メソッドを定義したPerson
クラスを上部に付け加えます。
class Person:
def __init__(self, age=1):
self.age = age
def drive(self):
if self.age >= 18:
print("Yes! You can do it.")
else:
print("No! You can't drive")
class Car:
def ride(self, person):
person.drive()
この時点で、Person
クラスを元に、オブジェクトであるperson
インスタンスを生成して、person.drive()
を実行すると、No! You can't drive
が出力されます。
person = Person()
person.drive()
素人的には、person
インスタンスを生成してから、Car
クラスのオブジェクトとして、car
インスタンスを生成して、car.ride()
を実行すれば、ride
メソッドで指定している引数に、person
が入って、No! You can't drive
が出力されるかと思ってしまいました。
person = Person()
car = Car()
car.ride()
しかし、この時点で、Person
オブジェクトのperson
と、ride
メソッドの引数であるperson
はつながっていないので、ride(person)
と記述して、引数にperson
オブジェクトをわたしてやる必要があります。
person = Person()
car = Car()
car.ride(person)
出力結果
No! You can't drive
これで人というオブジェクトが車に乗れるかどうかという判断を行えるようになりました。
ここで、Person
クラスから、次のような2つのオブジェクトbaby
インスタンスとadult
インスタンスを生成して、car.ride()
の引数にbaby
やadult
を渡して実行すると、どうなるでしょう?
baby = Person(1)
adult = Person(18)
car = Car()
car.ride(baby)
car.ride(adult)
出力結果
No! You can't drive
Yes! You can do it.
たぶん、これでもすでにダックタイピングということになると思います。
つまり、Car
の引数であるperson
がどのような引数であっても、人は人(DuckはDuck)としてdrive
メソッドを扱えるということなので、この段階ですでにbaby
もadult
も人というオブジェクトとして扱っているということです。
続いて、Person
クラスを継承して、違う条件を持ったクラスを追加してみます。
違う条件のPersonを作る
18歳以上のAdult
クラスと18歳以下のKids
クラスとを作ります。
class Person(object):
def __init__(self, age=1):
self.age = age
def drive(self):
if self.age >= 18:
print("Yes! You can do it.")
else:
print("No! You can't drive.")
class Kids(Person):
def __init__(self, age=1):
if age < 18:
super().__init__(age)
else:
raise ValueError
class Adult(Person):
def __init__(self, age=18):
if age >= 18:
super().__init__(age)
else:
raise ValueError
class Car:
def ride(self, person):
person.drive()
tom = Kids()
mark = Adult()
car = Car()
car.ride(tom)
car.ride(mark)
出力結果
No! You can't drive.
Yes! You can do it.
Person
クラスを継承したKids
クラスとAdult
クラスを定義して、それぞれのインスタンスを作成し、car.ride()
メソッドに引数として渡しています。
これが、Person
クラスから作ったインスタンスを使う場合と何が違うかというと、条件を個別に指定できるかどうかの違いだと思うのですが、もし間違いだったら、コメントで教えてもらえると嬉しいです。
じっくり読み解く
酒井さんのダックタイピングに関するレクチャーを受講したときは、全く意味がわかりませんでした。
ほんと一度見ただけでは理解できないんです。
今回、最終的に、私が理解したダックタイピングは、
クラスが違っても、オブジェクトを切り替えて、同じメソッドを使える
というコードの書き方という感じです。
何がどうなっているのか、何度も見て、部分部分に分けて理解していくことで、なんとなく理解できるようになります。
さらに同じレクチャーを繰り返し受講し、理解を深めることが大切です。
まさに、【継続は力なり】ですね。
それでは、明日もGood Python!