見出し画像

10分以内にPython3クラス詳細入門〈講座10〉

画像1

前回見た Coin クラスなのですが、空のクラスを作って好きに属性を加えていってもいいのですが、クラスごとに属性を統一させたり、インスタンスを作るときに初期値を与えたい場合がほとんどです。
そのための方法を見ていきましょう。

 
今回、Coin 型の属性は name のみとして、インスタンス化するときにその値を与えることにしましょう。
その場合、btc = Coin("btc") としてあげて、同じように eth を作りたい場合は、eth = Coin("eth") としてあげます。

 
こちらで入れた値はコンストラクタという特殊な関数を定義して、
コンストラクタの名前は決まっていて、__init__() としてあげて、引数には self と、こちらから渡ってくる値を受ける変数を書いてあげます。

# クラス
class Coin:
   def __init__(self, name):
       # インスタンス変数
       self.name = name
btc = Coin("btc")
eth = Coin("eth")
print(btc.name)
print(eth.name) 


今回 name としてあげます。
ここで self は、このクラスから作られるインスタンスを指します。
なので、self の name 属性に渡ってきた name を渡したいので、self.name = name としてあげれば OK です。
ではこちらのほうで print(btc.name)、そして print(eth.name) としてあげたいと思います。 


実行してあげると

画像2


今までインスタンスに紐付いた変数であるインスタンス変数を見ましたが、実はクラスに紐付いたクラス変数というものも定義することができます。

今回、このクラスからいくつインスタンスを作ったかをカウントするクラス変数を作ってあげたいと思います。

今回クラス変数 count という名前にしてあげて、0 で初期化してあげます。

 
インスタンスを作るたびに 1 ずつ増やせばいいので、コンストラクタ内で 1 足せばいいです。

 
クラス変数にアクセスするには、クラス名のあとに続けて書けば OK です。
では User.count += 1 としてあげます。

class Coin:
   # クラス変数
   count = 0
   def __init__(self, name):
       Coin.count += 1
       self.name = name

 
そこまでできたらカウントを表示してあげます。 


クラス変数はインスタンスを作らなくてもいきなり使えるので、例えば print(Coin.count) としてあげます。

print(Coin.count) # 0

この時点ではインスタンスが無いので、0 が表示されるはずです。
下でいくつかインスタンスを作ってあげて再度表示してあげると、

print(Coin.count) # 0
btc = Coin("btc")
eth = Coin("eth")
print(Coin.count) # 2

 
続きをやっていきましょう。 


クラスなのですが、コンストラクタ以外にも関数を定義することができて、クラスに定義した関数はメソッドというので、まずは用語としておさえておいてください。 


コンストラクタもメソッドの一種になります。 構造方法


メソッドにはいくつかの種類があるのですが、今回はインスタンス変数に紐付いたインスタンスメソッド、それからクラスに紐付いたクラスメソッドについて見ていきます。

 
まずはインスタンスメソッドを作ってみたいと思います。
では今回 def show_name(self): として、name の値を表示してみます。
引数には self を与えてあげてください。 


そうするとこのクラスのインスタンスの値が使えるので、print( .... ) としてあげて、 name を表示したいので、"コイン名: {0}".format(self.name) としてあげれば OK ですね。
btc.show_name()、それから eth.show_name() としてあげます。 

画像3

では次にクラスメソッドを見ていきましょう。 


クラスメソッドの場合は、デコレーターというのですが、@classmethod というおまじないをつけてあげてください。 


今回ですが、def show_info(cls): としてあげます。
引数にはこのクラス自身である cls という特殊なキーワードを与えてあげてください。 インスタンスの数を表示してあげましょう。

 
クラスには cls でアクセスできるので、"{0} instances".format(cls.count) としてあげれば OK かと思います。 


クラスメソッドはインスタンス化せずに使えるので、Coin.show_info() とすれば OK です。

 #coding : utf-8
# クラス
class Coin:
   count = 0
   def __init__(self, name):
       Coin.count += 1
       self.name = name
   # インスタンスメソッド
   def show_name(self):
       print("コイン名:{0}".format(self.name))
   # クラスメソッド
   @classmethod
   def show_info(cls):
       print("{0} instances".format(cls.count))
btc = Coin("ビットコイン")
eth = Coin("イーサリアム")
btc.show_name()
eth.show_name()
Coin.show_info()

 

次はクラスの変数やメソッドにアクセス制限をつける方法について見ていきましょう。 
  ただ Python では他の言語にあるような private、protected などの仕組みはなくて、慣習的にこう書きましょう、というルールだけがあるので、そのあたりを見ていきたいと思います。 


今回、こちらの name 属性にはクラスの外からはアクセスしてほしくないというケースを考えてみます。 


つまり、こちらのクラス内では使ってはいいけれど、クラスの外では使ってほしくないという場合です。

 
その場合は、変数名の前にアンダースコア"_"をつけると、「これは外からアクセスしないでね」という意味になります。 


例えば btc._name といった形ですね。 


ただ、これは単なる慣習的なお約束なので、実際に実行してみるとアクセスできてしまっているのがわかるかと思います。 


そこで、さらに厳密にしたい場合の方法も実はあって、その場合はアンダースコア 1 つではなく、アンダースコア 2 つにするというルールがあったりします。 


こちらでもう 1 度実行してみると,今度はアクセスできなくなっているのがわかるかと思います。 


ただ、これもある特殊な仕組みを使っているだけで、実は btc._Coin__name のように「_クラス名__属性名」とすると、実はアクセスできてしまいます。

 
実際は厳密にはアクセスを禁止する方法はないのですが、こういうルールがあることを覚えておきましょう。

 
なので、アクセスしてほしくないときにはアンダーバーをつけたり、もしくは他の人のコードを見ていてアンダーバーがあるときにはアクセスをしないようにする、と注意しておけばいいかと思います。 

画像4


次はクラスの継承について見ていきます。

これは既存のクラスをもとに新しいクラスを作るための仕組みです。

 
今回、Coin クラスをもとに btc クラスを作ってみます。
その際に、こちらのもととなるクラスを親クラスもしくはスーパークラス、

そこから作られるクラスを子クラス、サブクラスといったりするので、用語として覚えておいてください。

 
では Coin クラスをもとに Btc クラスを作っていきましょう。 

# Coin -> Btc
class Coin:
   def __init__(self, name):
       self.name = name
   def show_name(self):
       print("name {0}".format(self.name))

class Btc(Coin):


Coin クラスを継承するには、括弧の中にそのクラスを入れてあげれば OK です。 


Btcクラスに独自の変数とメソッドを追加してみます。

 
まずインスタンス変数を追加したいのですが、Btc には name に加えて price も渡してあげましょう。 

class Btc(Coin):
   def __init__(self, name, price):
       super().__init__(name)
       self.price = price


btc = Btc("btc", 1000000) といった形です。 

説明:
name のほうは親クラスのコンストラクタを使って設定してあげます。
親クラスは super() というキーワードで表現できるので、super().__init(name)__ としてあげれば OK です。
あとは self.price = price とすれば OK です。 


次に独自のメソッドを追加してみましょう。 


こちらで show_coin_info() というメソッドにしてあげます。 

    def show_coin_info(self):
       print("hello {0} ({1})".format(self.name, self.price))



実行してみましょう。
print(btc.name) としてあげて、btc.show_name() と btc.show_coin_info() が使えるはずなので、では実行してあげると

 #coding : utf-8
# クラスの継承
# Coin -> Btc
class Coin:
   def __init__(self, name):
       self.name = name
   def show_name(self):
       print("name {0}".format(self.name))
class Btc(Coin):
   def __init__(self, name, price):
       super().__init__(name)
       self.price = price
   def show_coin_info(self):
       print("子供クラス {0} ({1})".format(self.name, self.price))
btc = Btc("ビットコイン", 1000000)
print(btc.name)
btc.show_name()
btc.show_coin_info()

画像5


ちゃんと継承できているのがわかるかと思います。
それから、親クラスのメソッドを上書きすることもできたりします。
これをメソッドのオーバーライドというので、用語として覚えておいてください。 


では(show_name() を)こちらのほうにコピーしてあげて、区別ができるように [子供] とつけてあげましょう。 

 #coding : utf-8
# クラスの継承
# Coin -> Btc
class Coin:
   def __init__(self, name):
       self.name = name
   def show_name(self):
       print("name {0}".format(self.name))
class Btc(Coin):
   def __init__(self,name,price):
       super().__init__(name)
       self.price = price
   def show_coin_info(self):
       print("子供クラス {0} ({1})".format(self.name, self.price))
   # override
   def show_name(self):
       print("[子供]  {0}".format(self.name))
btc = Btc('btc',1000000)
print(btc.name)
btc.show_name()
btc.show_coin_info()


ではこれで実行してみましょう。 

画像6


ちゃんと 結果が変わっているのがわかると思います。 


次はクラスの多重継承について見ていきましょう。 


前回見た継承なのですが、実は親クラスを複数持つことができます。 


あらかじめいくつかクラスを用意しておきました。 


ではクラス A、B があったとして、それらを継承した C を作ってみましょう。 


A、B を継承するには、こちらにカンマ区切りで書いてあげれば OK です。
では class C(A, B) としてあげます。 


とりあえず中身は空にしてあげたいと思います。
あとはちゃんと継承できているか確認してみましょう。 
C のインスタンスを作ってあげて、c.say_a()、c.say_b() を実行してみたいと思います。 

# クラスの多重継承
# A, B -> C
class A:
   def say_a(self):
       print("A!")
   def say_hi(self):
       print("hi! from A!")
class B:
   def say_b(self):
       print("B!")
   def say_hi(self):
       print("hi! from B!")
# class C(A, B):
class C(B, A):
   pass
c = C()
c.say_a()
c.say_b()
c.say_hi()


そうしてあげると

画像7

 
注意点:

ただ、多重継承で問題になるのが、クラス A、B で同じメソッドがあった場合です。

これは継承を指定するときの順番が影響していて、同じメソッドがあった場合は、先に指定したほうのメソッドが優先されます。 


多重継承はもっと奥が深いのですが、まずは基本としてこのあたりをおさえておいてください。

以上 よろしくお願いいたします








この記事が気に入ったらサポートをしてみませんか?