※以下の企画です
今回は9章をやっていきます。
9章は「クラス」というタイトルで、結構しっかり目にクラスの説明をしてくれていそうな感じ。
全くと行っていいほどクラスを使いこなせている感覚はないので、ここで改めてクラスの概念と使い所を抑えていきたい。
クラスもまともに使いこなせていない奴がエンジニアを名乗るなというツッコミが聞こえてきますが、勘弁してください。もうほんと頑張ります。
それではやっていきますぅ。
9章 学習内容まとめ
オブジェクト型
本書の中に「新しいクラスを作ることは新しいオブジェクト型を作ること」と記載されており、学部時代にJava多少かじった程度の僕からすると、「オブジェクト型ってなんだ」という疑問が生じた。
これ以上の言及が文書中になかったので、いつものごとくGPT様のお力をお借りした。
オブジェクト型とは
- オブジェクト(Object): メモリ上に存在するデータの単位で、属性(データ)とメソッド(操作)を持ちます
- 型(Type): オブジェクトの種類や性質を定義するもので、オブジェクトがどのようなデータを持ち、どのような操作が可能かを決定します
属性は、クラス内(オブジェクト型の定義内)で用いる変数のことで、メソッドは、クラス内で定義して活用できる関数のことと理解。
厳密には違うのかもしれないが、まぁ多分イメージとしてそこまで間違っていなさそう。
ここらへんはJavaやC++と同じ。というか、Pythonのクラス関連はC++を基にしているらしい。
クラスの書き方
クラスの定義はめちゃくちゃシンプルで
>> class ClassName:
>> <属性とかメソッドとか>
これだけ。Javaとかと同じ感じ。
ちなみに、クラス名の命名規則は通例的にアッパーキャメルケースになっている。
割となんでもスネークケースにしてしまっているので、ここらへんはさすがにもう少し意識しよう…
クラスオブジェクトの取り扱い
実際に属性やらメソッドやら触ってみる。
>> class TestClass:
>> """this is a sample class"""
>> name = "test"
>> i = 100
>>
>> def f(self):
>> return 'hello world'
まずは上記のように定義。name
とi
が属性で、f
がメソッド。
>> TestClass.__doc__
this is a sample class
>> TestClass.i
100
>> TestClass.name
test
>> TestClass.i = 200
>> TestClass.i
200
ざっくりこんな感じで、取り扱いはめちゃ簡単。クラス名.属性
を指定するだけ。
メソッドの呼び出しについてはインスタンスの生成
を学ぶ必要がある。
インスタンス化
作り方
クラスという設計図からオブジェクト(インスタンス) を具体的に作り出すことを指す。
クラスを基にインスタンスを作って、そのインスタンスを操作して処理していくというイメージ。
ここらへんはJavaで苦労して理解したのでスッと入ってくるが、初めて触れる方にとってはややこしポイントだと思う。
生成方法も、取り扱いも簡単。
test = TestClass()
おわり。
これで、testがクラスオブジェクトTestClass
で定義された属性やメソッドを活用できる。
ここで注意なのは、testの属性やメソッドをどんなにいじくっても、元のクラス(TestClass
)には何の影響もないということ。クラスという設計図を基に、test
という新しい実体を作っただけなので。
初期状態
インスタンスを生成する(=クラスオブジェクトをコールする ともいうらしい)際に、初期状態をカスタマイズすることができる。
どういうことかというと…まぁこれは例を見ていただいた方がスッと理解できると思う。
>> class TestClass2:
>> def __init__(self):
>> self.name = "test"
>> self.age = 100
>> print("init class")
>> def f(self):
>> return 'hello world'
>> test2 = TestClass2()
init class
こんな感じで__init__
というメソッドを記述すると、インスタンスを生成した瞬間(test2 = TestClass2()
)に呼び出されていることがわかる。
self
というのは、「このインスタンス」という意味を持つ。通常、一つのClass
に対して、複数のインスタンスが生成されるので、**このname
は、自分自身のインスタンスのname
**と表明している感じ。ここは説明が難しく感じるので、自分の中でも実はちゃんと理解できていないのかもしれない…
※ちなみにself
じゃないキーワードに変えることもできる。this
とか。だが、慣習的にself
と表記されることが多いので、よほどな理由がない限りは変えないほうが可読性を下げないかも?
クラスへンストインスタンス変数
クラスの中で変数を宣言するときはスコープに要注意。
これは恥ずかしながら「たしかに」と思う内容だった。
クラス内でかつ__init__
外で宣言すればクラス変数、クラス内でかつ__init__
内で定義すればインスタンス変数となる。
百聞は一見に如かずということでコードを見ていく。
>> class dog:
>> tricks = [] # <-- これがクラス変数
>> def __init__(self, name):
>> self.name = name # <-- これがインスタンス変数
>> dog_a = dog("taro")
>> dog_b = dog("hachi")
>> print(f"dogs are {dog_a.name} and {dog_b.name}")
dogs are taro and hachi
ここまでは問題なし。
※ちなみに上記のように__init__
に引数を設定すれば、コール時に値をあらかじめセットすることができる。
ここからが2つの変数の取り扱い時の注意。
>> dog_a.tricks.append("jump")
>> dog_b.tricks.append("run")
>> print(dog_a.tricks)
['jump', 'run']
なんと、dog_b
で登録したはずのrun
が、dog_a
にまで登録されている!
これがクラス変数の特性。
クラス変数として宣言した変数については、全インスタンスで共有されてしまう。
こういうときは、インスタンス間でしか共有されないインスタンス変数
として定義すべきだ。
>> class dog:
>> def __init__(self, name):
>> self.name = name
>> self.tricks = []
まとめ
実はまだ9章の内容は残っているので、次の投稿でも引き続きクラスの内容を学んでいく。
クラスの概念などは知っていたものの、__init__
のこととか、変数のスコープとか忘れていることが多数あったので、もっと普段から意識してクラスは使うべきだと感じた。
GPTに頼りすぎて自分がどんどんショボいコーダーになっていると改めて認識した( ◠‿◠ ) 辛い
まだまだ頑張ります!