Python 3.5.1でクラスを試す

クラスのサンプル

  • Pythonのクラスは、PHPと異なりメソッドの第1引数に毎回selfと書く必要があったりするようです。
  • メソッドやクラス変数のprotected, privateなどのアクセス権はPythonには無いようです。
  • 参考: Python チュートリアル クラス
# -*- encoding: utf-8 -*-
import inspect, sys

class Example:
    test = None

    # コンストラクタ
    def __init__(self):
        self.test = 'hoge'
        print(sys._getframe().f_code.co_name)
        print()

    # デストラクタ
    def __del__(self):
        print(sys._getframe().f_code.co_name)
        print()

    # with文の始め
    def __enter__(self):
        print(sys._getframe().f_code.co_name)
        print()
        # with ~ as 変数にインスタンスを格納する際に必要
        return self

    # with文の終わり
    def __exit__(self, exc_type, exc_value, traceback):
        print(exc_type, exc_value, traceback)
        print(sys._getframe().f_code.co_name)
        print()

    # ジェネレータ
    def __iter__(self):
        print(sys._getframe().f_code.co_name)
        for i in range(10):
            yield i

    # クラスのインスタンスオブジェクトのメソッド
    # 第1引数に`self`
    def instance_method(self, *params):
        print(self.test)
        print(params)
        print(sys._getframe().f_code.co_name)
        print()

    # クラスメソッド
    @classmethod
    def class_methos(*params):
        print(params)
        print(sys._getframe().f_code.co_name)
        print()

    # スタティックメソッド
    @staticmethod
    def static_method(*params):
        print(params)
        print(sys._getframe().f_code.co_name)
        print()

インスタンス生成で __init__ が呼ばれる

    # コンストラクタ
    def __init__(self):
        self.test = 'hoge'
        print(sys._getframe().f_code.co_name)
        print()
  • 実行した場合
e = Example() # __init__ が出力される

with文で __enter__, __exit__ が呼ばれる

    # with文の始め
    def __enter__(self):
        print(sys._getframe().f_code.co_name)
        print()
        # with ~ as 変数にインスタンスを格納する際に必要
        return self

    # with文の終わり
    def __exit__(self, exc_type, exc_value, traceback):
        print(exc_type, exc_value, traceback)
        print(sys._getframe().f_code.co_name)
        print()
  • 実行した場合
with e as instance: # __enter__ が出力される
    print(instance) # __enter__ で self を return していないと None
# with文が終了すると __exit__ が出力される
  • これは、ファイルを開くときなどの形ですね。
with open('text.txt') as f:
    for line in f:
        pass

for文で __iter__ が呼ばれる

    # ジェネレータ
    def __iter__(self):
        print(sys._getframe().f_code.co_name)
        for i in range(10):
            yield i
  • 実行した場合
print(', '.join([str(i) for i in e]))
print()

# __iter__ が出力され、
# __iter__ からの結果をリスト化し', 'でjoinして 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 を出力
  • 参考:

クラスのインスタンスオブジェクトのメソッド(インスタンス変数へアクセス可)

直接も呼べますが、インスタンス変数へはアクセス出来ません

    # クラスのインスタンスオブジェクトのメソッド
    # 第1引数に`self`
    def instance_method(self, *params):
        print(self.test)
        print(params)
        print(sys._getframe().f_code.co_name)
        print()
  • 実行した場合
e.instance_method(inspect.getouterframes(inspect.currentframe())[0].lineno)

# hoge # __init__ で代入した値を出力
# (74,) # 行番号
# instance_method

クラスメソッド(インスタンス変数へはアクセス出来ない)

インスタンスからも呼べますが、インスタンス変数へはアクセス出来ません

    # クラスメソッド
    @classmethod
    def class_methos(*params):
        print(params)
        print(sys._getframe().f_code.co_name)
        print()
  • 実行した場合
Example.class_methos(inspect.getouterframes(inspect.currentframe())[0].lineno)

# (<class '__main__.Example'>, 78) # 行番号は第2引数に渡されている
# class_methos
  • 参考:

スタティックメソッド(インスタンス変数へはアクセス出来ない)

インスタンスからも呼べますが、インスタンス変数へはアクセス出来ません

    # スタティックメソッド
    @staticmethod
    def static_method(*params):
        print(params)
        print(sys._getframe().f_code.co_name)
        print()
  • 実行した場合
Example.static_method(inspect.getouterframes(inspect.currentframe())[0].lineno)

# (82,) # 行番号
# static_method

スクリプト終了で __del__ が呼ばれる

    # デストラクタ
    def __del__(self):
        print(sys._getframe().f_code.co_name)
        print()
  • 実行した場合
# スクリプト終了直前に __del__ が出力される
  • ガーベージコレクト任せになってしまい任意のタイミングに処理されるかどうかわからないため、__enter__, __exit__によるwith文の方が扱いやすいようです。

メソッド名はどのように確認する?

PHPだと__FUNCTION__で確認できるメソッド名は、Pythonだとsys._getframe().f_code.co_nameで確認できるようです。

  • 参考:

行番号はどのように確認する?

PHPだと__LINE__で確認できる行番号は、Pythonだとinspect.getouterframes(inspect.currentframe())[0].linenoで確認できるようですが、バージョンによって少し異なるようです。今回はPython 3.5.1です。

  • 参考: