0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

技術書一冊やり込もうAdvent Calendar 2024

Day 8

Pythonチュートリアル #7 -クラスについて 前編-

Last updated at Posted at 2024-12-07

※以下の企画です

今回は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'

まずは上記のように定義。nameiが属性で、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という新しい実体を作っただけなので。

初期状態

インスタンスを生成する(=クラスオブジェクトをコールする ともいうらしい)際に、初期状態をカスタマイズすることができる。
どういうことかというと…まぁこれは例を見ていただいた方がスッと理解できると思う。

init
>> 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に頼りすぎて自分がどんどんショボいコーダーになっていると改めて認識した( ◠‿◠ ) 辛い

まだまだ頑張ります!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?