☆☆ 新着記事 ☆☆

2019年7月26日金曜日

初めてPythonのクラスやメソッドを理解する為の説明

Pythonの基本を理解して、そろそろ小さなプログラムから脱皮したくなった人のための、Python 「クラス」、「インスタンス」や「メッソド」、また、これらの実際の「活用方法」の説明です。



◇ クラスの定義


1) クラスとは
Pythonではクラスの定義にclass文を使用します。class文を使った定義の仕方は以下のようになります。

class クラス名:

class ClassName():
 
class後にそのクラスの名前となるクラス名をつけて(大文字で始めるのが慣行)、最後に「:」を付けます。そのあとに一段落インデントを入れてクラス定義をしていきます。

class Test:
    pass  #何もしないクラスの場合はpassと記入する

2) クラス変数
クラスは、クラス内で定義されたメソッドに共有できる変数を持つことができます。
(詳細は、インスタンスと変数の後で説明)

「インスタンスを生成する(インスタンス化する)」、とは

1) インスタンスとは
Instanceとは、Classで記述した関数(メッソドという)などを実行するために生成するもの。

class Employee():
    pass
emp_1 = Employee()  #EmployeeというClassのemp_1 というインスタンス生成
emp_2 = Employee() #EmployeeというClassのemp_2 というインスタンス生成

print(emp_1)
> <__main__.Employee object at 0x0000000001E228D0>
print(emp_2)
> <__main__.Employee object at 0x0000000002856518>
Employee クラスの独立したオブジェクトがインスタンスとして、それぞれ生成された。

2) インスタンスと変数
インスタンスは、変数を属性としてもつことが出来る。 ここでは、ひとつずつ、マニュアルで属性値を与えた例を示しますが、コンストラクタを使うことで操作がもっと簡単になります。(後述)

emp_1 = Employee()
emp_1.first = 'Bruno'
emp_1.second = 'Mars'
emp_1.email = 'Bruno.Mars@test.com'
emp_1.pay = 4000

emp_2 = Employee()
emp_2.first = 'Charlie'
emp_2.second = 'Puth'
emp_2.email = 'Charlie.Puth@test.com'
emp_2.pay = 3000

print(emp_1.email)
>Bruno.Mars@test.com
print(emp_2.pay)
>3000
print('{} {}'.format(emp_1.first,emp_1.second))
>Bruno Mars


◇メソッドとは

メソッドとは、クラス内に定義された関数のことです。メソッドは定義されたクラスからしか呼び出すことが出来ないのも特徴。

class クラス名:
    def メソッド名(self):
        #メソッドの定義

メソッドは必ず1つ以上の引数を持ちます。また、引数のうち最初のものはselfという名前にすることになっています。メソッドを呼び出すには以下のようにします。

インスタンス.メソッド名()

class Test:
    def test_print(self):
        print('This is test')

test = Test()      #インスタンス生成
test.test_print()  #メソッド呼び出し
> This is test

◇ コンストラクタとデストラクタ (特殊関数)

メソッドの中でも、インスタンスが生成されるときに自動的に呼び出されるメソッドのことをコンストラクタと言います。デストラクタは、インスタンス消滅時に自動的に呼び出されるメソッドです。ただし、デストラクタは使わないことが、Python公式ドキュメントでも推奨されていないので、深堀りしない。

コンストラクタを定義するには「init」という名前のメソッドを作成します。

例)
class Test:
    def __init__(self, 引数1, 引数2, ….):
        #コンストラクタの定義

  例)
  Class Test():
         def __init__(self):
             print('Constructor is called!')
         def func(self):
              print('Function is called!')

  で、
  test_instance = Test()

  とインスタンスを生成すると、その時点で 
  print('Constructor is called!') が実行される。


例2)
インスタンスの例で、ここではコンストラクタを使用して、各インスタンスの変数に値を入れて見ます。

クラス Employee で、__init__ メソッドを使って、selfというインスタンスに、first, last,pay という引数を指定する記述が以下になります。


class Employee():
    def __init__(self, first,last,pay):
        self.first = first
        self.second = second
        self.pay = pay
        self.email = first + '.' + 'test.com'

    #Full Nameをprint outする関数を作成
    def  fullname(self):
        print('{} {}'.format(self.first, self.second))

メンバー変数を指定してみます。メンバー変数はインスタンス間をまたぎません。
emp_1 = Employee('Bruno','Mars',4000) 
emp_2 = Employee('Charlie','Puth',3000)
 

print(emp_1.email)
>Bruno.Mars@test.com
print(emp_2.pay)
>3000

♯Instanceを使って関数を呼び出し。fullname( )メソッドにemp2の属性を再記述する必要なし。

print(emp_2.fullname() #()を付けることで、属性ではなく関数を呼びだし。
>Charlie Puth

#Class名を使って関数を呼び出し。fullname( )メソッドにemp2の属性を再記述する必要あり。

print( Employee.fullname(emp_2) )
>Charlie Puth


(挙動の解説)
*コンストラクタである__init__() で、このように第一属性として self を定義すると、emp_1が読まれた際に、Employee()にパスされて、selfとして理解されて、各属性が self(emp_1) = first ,self(emp_1) = secondと解釈される。 したがって、

self.first = firstは、emp_1.first = と記述していることと同じになる。


*emp_1 や emp_2 は、Employeeというクラスで定義されているので、このEmployee()クラスで定義されているメソッド fullname()を利用することができる。

 *   def  fullname(self): に引数 selfの記述をしないで、以下のprint outを実行した場合、
print(emp_2.fullname())
TypeError: fullname() takes 0 positional arguments but 1 was given
という、「引数が1つしか与えられていない」といいうエラーになる。

それは、emp_2.fullname() で、fullname()に引数を与えていないように見えるが、実際には、emp_2というインスタンスが自動的に引数としてfullname()に渡されているので、selfで受け取る必要があるから。



クラス変数
(クラスとは、ちょっと書きましたが)クラス変数は、クラス内で記述されたメソッドで共有できる変数です。インスタンス間で同じ値を参照します。

class Employee():

    raise_amount = 1.04  # クラス変数の定義

    def __init__(self, first,last,pay):
        self.first = first
        self.second = second
        self.pay = pay
        self.email = first + '.' + 'test.com'

    def  fullname(self):
        print('{} {}'.format(self.first, self.second))

    def  apply_raise(self):
        self.pay = int (self.pay * self.raise_amount)

   #クラス変数を各メソッド内で参照する場合にも、self. や、クラス名そのもの Employee.変数
    を明記して、Employee.raise_amount と記述する必要がある。これらの記述を明示しない
    と、「raise_amountは定義されていない」というエラーになる。


emp_1 = Employee('Bruno','Mars',4000)
emp_2 = Employee('Charlie','Puth',3000)


print(emp_1.pay)
>4000
emp_1.apply_raise()
print(emp_1)
>4160

*(解説)
クラス変数を使用する際にインスタンス名、又はクラス名を明示しなければならない理由。
print(Employee.raise_amount)
>1.04
print(emp_1.raise_amount)
>1.04
print(emp_2.raise_amount)、
>1.04

クラス変数は、最初、インスタンスに引数が定義されていないかチェック。なければクラスで定義されいないかチェックする挙動となります。

この例では、
最初、emp_1 の属性を参照
print(emp_1.__dict__)
{'first': 'Bruno', 'second': 'Mars', 'pay': 4000, 'email': 'Bruno.test.com'}

raise_amountが定義されていないので、Classの属性を参照。
print(Employee.__dict__)

{'__module__': '__main__', 'raise_amount': 1.04, '__init__': <function Employee.__init__ at 0x0000000002F026A8>, 'fullname': <function Employee.fullname at 0x0000000002F02730>, 'apply_raise': <function Employee.apply_raise at 0x0000000002F027B8>, '__dict__': <attribute '__dict__' of 'Employee' objects>, '__weakref__': <attribute '__weakref__' of 'Employee' objects>, '__doc__': None}

で、変数の値を参照することができる。


コンストラクタとは逆に、インスタンスが不要になり削除される時に呼ばれるメソッドをデストラクタと言います。デストラクタは「del」という名前のメソッドで定義されます。

class Test:
    def __init__(self):
        print('コンストラクタが呼ばれました')
    def __del__(self):
        print('デストラクタが呼ばれました')

test = Test()  #インスタンスを生成
del test      #インスタンスを削除

実行結果

コンストラクタが呼ばれました
 デストラクタが呼ばれました

◇ 継承
Pythonのクラスも他のクラスを継承し、拡張することができます。クラスを継承する場合はクラス文に親となるクラスを指定します。親のクラスのメソッドを呼び出す場合はsuper()を使います。

class Test( ):
    def __init__(self, num):
        self.num = num;
    def print_num(self):
        print('引数で渡された数字は{}です。'.format(self.num))

class Test2(Test):  #Testクラスを継承
    def print_test2_info(self):
        print('このクラスはTestクラスを継承しています。')
        super().print_num()  #親クラスのprint_num()を呼び出す

test = Test2(10)
test.print_test2_info()

実行結果

このクラスはTestクラスを継承しています。
 引数で渡された数字は10です。

参考)
https://www.youtube.com/watch?v=ZDa-Z5JzLYM

0 件のコメント:

コメントを投稿