Python/クラス

Pythonのクラスについて学ぶことで、自分自身のデータ型を定義して、その型に基づいて作成されたオブジェクトにアクセスする方法を学ぶことができます。 このチュートリアルでは、Pythonでクラスを定義する方法、クラスオブジェクトとインスタンスオブジェクトの違い、クラス変数とインスタンス変数、メソッド、継承、プライベート変数とメソッド、プロパティ、抽象基底クラスなどのトピックについて説明します。
Pythonのクラスは、オブジェクト指向プログラミングにおける基本的な概念の一つで、データと関数をまとめて扱うことができます。
クラスは、プログラム内でオブジェクトを作成するための設計図のようなものです。クラスには、そのオブジェクトが持つ属性(データ)や振る舞い(メソッド)が定義されています。クラスを定義することで、同じような性質を持ったオブジェクトを簡単に作成することができます。
クラスの中で定義されたデータは、クラス変数とインスタンス変数の2種類があります。クラス変数は、そのクラスが持つデータであり、全てのインスタンスで共有されます。インスタンス変数は、オブジェクトごとに異なる値を持つデータであり、各インスタンスごとに独立しています。
メソッドは、オブジェクトの振る舞いを定義するための関数です。クラスに定義されたメソッドは、インスタンスを通じて呼び出すことができます。
クラスは、継承を使って他のクラスを拡張することができます。継承することで、既存のクラスの機能を再利用し、新たな機能を追加することができます。
また、Pythonにはプライベート変数やプロパティ、抽象基底クラスなど、クラスをより強力にするための機能があります。これらの機能を使うことで、より柔軟で安全なコードを書くことができます。
Pythonでは class キーワードを使用してクラスを定義します。基本的な構文は以下の通りです。
クラス名は、PascalCase で書かれた単語である必要があります。クラスの本体には、変数や関数を定義することができます。
以下の例では、Person というクラスを定義しています。このクラスには、名前と年齢のインスタンス変数、およびそれらを設定するための __init__ メソッドが含まれています。
このクラスを使うと、以下のようにして Person のインスタンスを作成することができます。
クラス定義によって作成されたオブジェクトには、2つの種類があります。1つはクラスオブジェクトであり、もう1つはインスタンスオブジェクトです。
クラスオブジェクトは、クラス定義に基づいて作成され、クラス変数にアクセスするために使用されます。
この場合は、MyClass がクラスオブジェクトです。
インスタンスオブジェクトは、クラスから作成された各オブジェクトのことを指します。それぞれのインスタンスは、独自の状態を保持できます。
この場合は、my_object1とmy_object2 がインスタンスオブジェクトです。
クラス変数はクラス内で定義され、すべてのインスタンスで共有される変数です。インスタンス変数は、各インスタンスごとに異なる値を持つ変数です。
以下は、クラス変数とインスタンス変数を定義する例です。
上記の例では、class_variableはクラス変数、instance_variableはインスタンス変数です。class_variableはクラス内で定義され、インスタンス作成前に定義されます。instance_variableは、__init__メソッド内で初期化されるため、インスタンスが作成されるたびに異なる値が割り当てられます。
以下は、クラス変数とインスタンス変数をアクセスする例です。
上記の例では、my_instanceはMyClassのインスタンスであり、class_variableとinstance_variableにアクセスしています。MyClass.class_variableを変更すると、MyClassのすべてのインスタンスが新しい値を持つようになります。
Pythonにおけるメソッドとは、オブジェクトが持つ関数のことです。メソッドは、クラス内に定義された関数であり、オブジェクトに対して呼び出されることが前提となっています。 メソッドは、インスタンスメソッド、クラスメソッド、スタティックメソッド、特殊メソッドなど、種類によって様々な特徴を持っています。 インスタンスメソッドは、そのオブジェクトに対して呼び出され、クラスメソッドは、そのクラスに対して呼び出されます。 スタティックメソッドは、オブジェクトやクラスに関係なく、独立して呼び出されます。 特殊メソッドは、Pythonが提供する特別な機能を持つメソッドであり、例えば、__init__や__str__などがあります。
インスタンスメソッドは、クラスのインスタンスによって呼び出されます。第1引数は必ず self で、それを使ってインスタンスの属性にアクセスできます。
このコードは、インスタンスメソッドの例です。 instance_methodは、selfを最初の引数として受け取り、その引数はメソッドが呼び出されたインスタンス自体を指します。このインスタンスを介して、メソッドはオブジェクトの状態を変更することができます。引数arg1とarg2は、メソッドに渡され、メソッドの処理に使用されます。
上記のコードは、MyClassのインスタンスobjを作成し、instance_methodを呼び出しています。 instance_methodは、 objがインスタンスであるため、selfとして自分自身を参照し、 "Called instance_method with hello and world"という文字列を出力します。
クラスメソッドは、クラス自体によって呼び出されます。第1引数は必ず cls で、それを使ってクラスの属性にアクセスできます。
上記のコードは、MyClass というクラスを定義し、その中に class_var というクラス変数を定義し、class_method というクラスメソッドを定義しています。
class_method は、@classmethod デコレータで修飾されており、第一引数が cls というクラスオブジェクトであることが示されています。クラスメソッドは、クラス自身を第一引数として受け取るため、クラス変数にアクセスしたい場合は、cls.class_var のようにしてアクセスすることができます。
このクラスメソッドは、arg という引数を受け取り、cls.arg にその値を代入し、cls.arg と cls.class_var を用いてメッセージを出力するという動作をします。
最後の行では、class_method をクラス名で呼び出しています。class_method がクラスメソッドであるため、第一引数にはクラスオブジェクト MyClass が自動的に渡されます。
スタティックメソッドは、クラス自体やインスタンスから呼び出すことができます。スタティックメソッドは self や cls が必要ないため、第1引数を定義しません。
この例では、@staticmethod デコレータが使われています。このデコレータを使うことで、メソッドがスタティックメソッドであることを明示的に示すことができます。
スタティックメソッドはクラスに属していますが、インスタンスには属していないため、引数に self や cls を必要としません。そのため、スタティックメソッドは通常、インスタンス変数を使用する必要がない場合に使用されます。
上記の例では、@staticmethod を使って static_method メソッドを定義しています。このメソッドは arg という引数を受け取り、"Called static_method with {arg}" というメッセージを出力します。
最後の行では、MyClass.static_method("hello") というコードを実行することで、static_method メソッドを呼び出しています。この結果、"Called static_method with hello" というメッセージが出力されます。
特殊メソッドは、Pythonによって予約されたメソッドで、オブジェクトの様々な振る舞いを定義することができます。特殊メソッドは、名前が __ で始まり、終わります。
例えば、__init__() は、オブジェクトが作成されるときに自動的に呼び出されるメソッドで、インスタンス変数の初期化などの処理を行います。
このコードは、MyClassという名前のクラスを定義し、__init__という特殊メソッドを使ってインスタンスを初期化しています。 __init__メソッドは、クラスがインスタンス化される際に自動的に呼び出されます。このメソッドは、インスタンスの属性を初期化するのに使用されます。 上記の例では、MyClassのインスタンスを作成し、"hello"という値をarg1に、"world"という値をarg2に割り当て、__init__メソッドが呼び出されたことを示す出力が表示されます。
継承とは、既存のクラスを基に新しいクラスを作り出すことで、既存のクラスの機能を引き継ぎながら、新たな機能を追加することができます。
スーパークラスは、継承元のクラスのことを指します。スーパークラスの定義は、通常のクラス定義と同じように行います。
以下の例では、Person というクラスをスーパークラスとして定義しています。
このスーパークラス Person は、name と age の属性を持ち、say_hello() メソッドを定義しています。
サブクラスは、スーパークラスを継承して新たなクラスを作り出すことができます。サブクラスは、新たに追加する属性やメソッドを定義することができます。
以下の例では、Student というクラスを、スーパークラスである Person を継承して定義しています。
このサブクラス Student は、Person クラスを継承して、grade の属性を追加し、say_hello() メソッドをオーバーライドしています。
サブクラスでスーパークラスのメソッドを再定義することをオーバーライドと呼びます。サブクラスで同名のメソッドを定義することで、スーパークラスのメソッドを上書きすることができます。
上記の例では、Student クラスで say_hello() メソッドを再定義し、出力内容を変更しています。
サブクラスでスーパークラスのメソッドを呼び出すには、super() 関数を使用します。super() 関数を呼び出すことで、スーパークラスのメソッドを呼び出すことができます。
上記の例では、Student クラスの __init__() メソッドで、super() 関数を使用して、スーパークラスの __init__() メソッドを呼び出しています。 これにより、Person クラスで定義した name と age の属性を、Student クラスでも使用することができます。
Python では、複数のクラスを同時に継承することができます。これを多重継承と呼びます。多重継承では、カンマで区切って複数のスーパークラスを指定します。 以下の例では、Person クラスというスーパークラスを継承し、さらに、Swimmer というクラスも同時に継承しています。
上記の例では、Swimmer クラスを定義して、swim() メソッドを持たせています。 そして、SwimmingStudent クラスで Person クラスと Swimmer クラスの両方を継承しています。 さらに、SwimmingStudent クラスで swim() メソッドをオーバーライドして、Swimmer クラスで定義した swim() メソッドと異なる動作をするようにしています。 最後に、SwimmingStudent クラスのインスタンスを作成して、swim() メソッドを呼び出した結果、Swimmer クラスで定義した swim() メソッドではなく、SwimmingStudent クラスでオーバーライドした swim() メソッドが呼び出されることが確認できます。
プライベート変数やメソッドとは、クラスの外から直接アクセスできないようにするために用意されたものです。Pythonでは、アンダースコア(_)で始まる変数名やメソッド名を定義することで、プライベート変数やメソッドを作成することができます。
プライベート変数を定義する場合、変数名の先頭にアンダースコアを付けます。以下の例では、Person クラスにプライベート変数 _password を定義しています。
同様に、プライベートメソッドを定義する場合も、メソッド名の先頭にアンダースコアを付けます。上記の例では、Person クラスにプライベートメソッド _show_password() を定義しています。
プライベート変数やメソッドは、クラスの外から直接アクセスすることができません。しかし、アクセスする方法が用意されています。
プライベート変数にアクセスする場合、変数名の前にアンダースコアを付けます。以下の例では、Person クラスのインスタンス p から、プライベート変数 _password にアクセスしています。
ただし、この方法は推奨されていません。Pythonでは、アンダースコアで始まる変数やメソッドは、外部から直接アクセスしないことが慣例となっています。プライベート変数やメソッドにアクセスする場合は、公開されているインターフェースを通じて行うようにしましょう。
プライベートメソッドにアクセスする場合、同様にメソッド名の前にアンダースコアを付けます。以下の例では、Person クラスのインスタンス p から、プライベートメソッートメソッド _show_password() にアクセスしています。
同様に、クラス内で定義された公開メソッドを通じて、プライベート変数やメソッドにアクセスすることもできます。
以下の例では、Person クラスに公開メソッド get_password() を定義し、それを通じてプライベート変数 _password にアクセスしています。
このように、Pythonでは、プライベート変数やメソッドを定義することで、クラスの外からの直接アクセスを制限することができます。 ただし、アクセスするための手段は用意されているため、必要な場合には適切に利用するようにしましょう。
プロパティとは、クラスの外からもアクセスできるようにしたい変数を指します。 しかし、変数に直接アクセスすると不適切な値が設定される可能性があるため、アクセス時に特定の処理を実行する必要があります。 このような場合に、プロパティを使います。
Pythonでは、プロパティを定義するには property ビルトイン関数を使用します。プロパティを定義するには、以下のような方法があります。
getter関数のみを定義する場合、以下のように @property デコレータを使用して、getter関数にアクセスすることができます。
このように定義することで、インスタンスから以下のようにして name や age にアクセスすることができます。
getter関数とsetter関数の両方を定義する場合、以下のように @property デコレータと @<property名>.setter デコレータを使用して、getter関数とsetter関数にアクセスすることができます。
このように定義することで、インスタンスから以下のようにして name や age にアクセスし、変更することができます。
プロパティにアクセスする場合、通常のインスタンス変数と同様に、以下のようにしてアクセスします。
また、setter関数を定義している場合、以下のようにしてプロパティの値を変更することができます。
プロパティを使用することで、クラスの外部からもインスタンス変数にアクセスできるようになり、getter関数やsetter関数を使用することで、変数の値に対して特定の処理を行うことができます。 これにより、クラスのカプセル化が実現され、安全で信頼性の高いコードを作成することができます。
__getattr__ と __setattr__ は Python の特殊メソッドで、オブジェクトの属性に対するアクセスをカスタマイズすることができます。
__getattr__ メソッドは、インスタンスの属性が未定義の場合に呼び出されます。通常の属性アクセスが失敗した場合に呼び出され、属性名を引数に取り、属性の値を返すように実装することができます。このメソッドを使用することで、動的な属性アクセスをサポートすることができます。
例えば、以下のようなクラス DynamicObject を考えます。
このクラスは、未定義の属性にアクセスした場合に、属性名と "is not defined." の文字列を連結したものを返します。
一方、__setattr__ メソッドは、属性に値を代入する際に呼び出されます。通常の属性代入が行われた後に、属性名と代入された値を引数に取り、任意の処理を実行することができます。このメソッドを使用することで、属性代入時のチェックや変換処理を実装することができます。
例えば、以下のようなクラス PositiveNumber を考えます。
このクラスは、属性に代入される値が負数である場合に、 ValueError を発生させます。
Pythonでは、クラス変数とインスタンス変数をプライベート化することができます。プライベート変数は、クラスの外から直接アクセスすることができなくなり、情報の隠蔽や保護に役立ちます。
クラス変数とインスタンス変数をプライベート化するには、変数名の前にアンダースコア2つ(__)をつけます。例えば、以下のように定義します。
これにより、MyClass の外からは __private_class_var や __private_instance_var に直接アクセスできなくなります。ただし、Pythonでは名前修飾という仕組みがあり、アンダースコア2つを付けることで、クラス外からアクセスできなくするだけで、実際にはアクセス可能な変数として存在します。
プライベート変数にアクセスするためには、アンダースコア1つ(_)を変数名の前に付けることでアクセスできます。例えば、以下のようにします。
上記の例では、get_private_class_var() メソッドと get_private_instance_var() メソッドを定義し、それぞれでプライベート変数にアクセスする方法を示しています。
プライベート変数はクラスの外からアクセスできないようになっていますが、名前修飾を使用することで、直接アクセスすることができます。 ただし、名前修飾を使うことでアクセスできるようになっているため、注意が必要です。 プライベート変数は、クラス内部でしか使用しない変数であることを明確にし、情報を保護するために使用することが望ましいです。
抽象基底クラスは、インスタンス化できない抽象的なクラスで、共通のインターフェースを定義することができます。 具体的な実装は、抽象基底クラスを継承したサブクラスで行います。 Pythonでは、抽象基底クラスを作成するために abc モジュールを使用します。
抽象基底クラスを定義するには、abc.ABC クラスを継承する必要があります。また、抽象メソッドを定義するには @abstractmethod デコレータを使用します。
以下は、抽象基底クラスの定義例です。
上記の例では、MyABC という抽象基底クラスを定義しています。このクラスには、do_something という抽象メソッドが定義されています。
抽象基底クラスを継承するサブクラスを定義する場合、@abstractmethod で定義されたメソッドを実装する必要があります。また、抽象基底クラスを継承することで、共通のインターフェースを持つことができます。
以下は、抽象基底クラスを継承したクラスの定義例です。
上記の例では、MyClass というクラスを定義し、MyABC を継承しています。MyABC に定義された do_something メソッドを実装し、処理を行っています。
以上が、Pythonでの抽象基底クラスの定義方法、抽象基底クラスを継承したクラスの定義方法です。 抽象基底クラスを使用することで、共通のインターフェースを持つクラスを実装し、コードの再利用性を高めることができます。
Ruby#ユーザー定義クラスをPython3に移植しました。