Python3 オブジェクト指向

Pythonは設計当初からオブジェクト指向言語です。そのため、Pythonでクラスとオブジェクトを作成するのは非常に簡単です。この章では、Pythonのオブジェクト指向プログラミングについて詳しく説明します。

これまでオブジェクト指向プログラミング言語に触れたことがない場合は、まずオブジェクト指向言語の基本的な特徴を理解し、頭の中でオブジェクト指向の基本的な概念を形成する必要があるかもしれません。そうすることで、Pythonのオブジェクト指向プログラミングをより簡単に学ぶことができます。

次に、オブジェクト指向の基本的な特徴を簡単に見ていきましょう。


オブジェクト指向技術の概要

  • クラス(Class):同じ属性とメソッドを持つオブジェクトの集合を記述するために使用します。その集合内の各オブジェクトが共通して持つ属性とメソッドを定義します。オブジェクトはクラスのインスタンスです。
  • メソッド:クラス内で定義された関数。
  • クラス変数:クラス変数は、インスタンス化されたすべてのオブジェクトで共有されます。クラス変数はクラス内かつ関数本体の外で定義されます。クラス変数は通常、インスタンス変数としては使用されません。
  • データメンバー:クラス変数またはインスタンス変数は、クラスおよびそのインスタンスオブジェクトに関連するデータを処理するために使用されます。
  • メソッドのオーバーライド:親クラスから継承したメソッドが子クラスのニーズを満たさない場合、それを書き換えることができます。このプロセスをメソッドのオーバーライド(override)と呼び、メソッドの書き換えとも呼びます。
  • ローカル変数:メソッド内で定義される変数で、現在のインスタンスにのみ作用します。
  • インスタンス変数:クラスの宣言では、属性は変数で表されます。このような変数をインスタンス変数と呼びます。インスタンス変数は self で修飾された変数です。
  • 継承:派生クラス(derived class)が基底クラス(base class)のフィールドとメソッドを継承することです。継承により、派生クラスのオブジェクトを基底クラスのオブジェクトとして扱うこともできます。例えば、Dog型のオブジェクトがAnimalクラスから派生する設計があります。これは「is-a」関係を模倣しています(例:DogはAnimalです)。
  • インスタンス化:クラスのインスタンスを作成すること、つまりクラスの具体的なオブジェクトを作成すること。
  • オブジェクト:クラスで定義されたデータ構造のインスタンスです。オブジェクトには、2つのデータメンバー(クラス変数とインスタンス変数)とメソッドが含まれます。

他のプログラミング言語と比較して、Pythonは可能な限り新しい構文と意味論を追加せずにクラス機構を導入しました。

Pythonのクラスは、オブジェクト指向プログラミングのすべての基本機能を提供します。クラスの継承機構は複数の基底クラスを許可し、派生クラスは基底クラスの任意のメソッドをオーバーライドでき、メソッド内で基底クラスの同名メソッドを呼び出すことができます。

オブジェクトは、任意の数および任意の型のデータを含むことができます。

クラス定義

構文は次のとおりです:

class ClassName: <statement-1> . . . <statement-N>

クラスをインスタンス化すると、その属性を使用できます。実際、クラスを作成した後、クラス名を使ってその属性にアクセスできます。

クラスオブジェクト

クラスオブジェクトは、属性参照とインスタンス化の2つの操作をサポートします。

属性参照は、Pythonのすべての属性参照と同じ標準構文を使用します:obj.name。

クラスオブジェクトを作成すると、クラス名前空間内のすべての名前が有効な属性名になります。したがって、クラス定義が次のようになっている場合:

例(Python 3.0+)

#!/usr/bin/python3 class MyClass: """簡単なクラスの例""" i = 12345 def f(self): return 'hello world' # クラスをインスタンス化 x = MyClass() # クラスの属性とメソッドにアクセス print("MyClass クラスの属性 i は:", x.i) print("MyClass クラスのメソッド f の出力は:", x.f())

上記は新しいクラスインスタンスを作成し、そのオブジェクトをローカル変数 x に代入しました。x は空のオブジェクトです。

上記のプログラムを実行すると、出力結果は次のとおりです:

MyClass 类的属性 i 为: 12345
MyClass 类的方法 f 输出为: hello world

クラスには __init__() という名前の特別なメソッドがあります(コンストラクタ)、このメソッドはクラスのインスタンス化時に自動的に呼び出され、次のようになります:

def __init__(self): self.data = []

クラスが __init__() メソッドを定義すると、クラスのインスタンス化操作は自動的に __init__() メソッドを呼び出します。次のようにクラス MyClass をインスタンス化すると、対応する __init__() メソッドが呼び出されます:

x = MyClass()

もちろん、__init__() メソッドはパラメータを持つことができます。パラメータは __init__() を通じてクラスのインスタンス化操作に渡されます。例:

例(Python 3.0+)

#!/usr/bin/python3 class Complex: def __init__(self, realpart, imagpart): self.r = realpart self.i = imagpart x = Complex(3.0, -4.5) print(x.r, x.i) # 出力結果:3.0 -4.5

self はクラスのインスタンスを表し、クラス自体ではありません

クラスのメソッドと通常の関数の唯一の特別な違いは、追加の最初のパラメータ名、慣例によりその名前は self です。

class Test: def prt(self): print(self) print(self.__class__) t = Test() t.prt()

上記の例を実行すると、結果は次のとおりです:

<__main__.Test instance at 0x100771878>
__main__.Test

実行結果から明らかなように、self はクラスのインスタンスを表し、現在のオブジェクトのアドレスを表します。一方、self.class はクラスを指します。

self はPythonのキーワードではありません。これを サンプル に変更しても正常に実行できます:

class Test: def prt(サンプル): print(サンプル) print(サンプル.__class__) t = Test() t.prt()

上記の例を実行すると、結果は次のとおりです:

<__main__.Test instance at 0x100771878>
__main__.Test

Pythonでは、self はクラスのインスタンス(オブジェクト)自身を表すために使用される慣用的な名前です。これはインスタンスへの参照であり、クラスのメソッドがインスタンスの属性にアクセスして操作できるようにします。

クラスを定義し、その中でメソッドを定義する場合、最初のパラメータは通常 self と名付けられます。他の名前を使うこともできますが、コードの一貫性と可読性を保つために self を使用することを強くお勧めします。

例

class MyClass:
    def __init__(self, value):
        self.value = value

    def display_value(self):
        print(self.value)

# クラスのインスタンスを作成
obj = MyClass(42)

# インスタンスのメソッドを呼び出す
obj.display_value() # 42 を出力

上記の例では、self はクラスのインスタンスへの参照です。これは__init__コンストラクタでインスタンスの属性を初期化するために使用され、またdisplay_valueメソッドでインスタンスの属性にアクセスするために使用されます。self を使用することで、クラスのメソッド内でインスタンスの属性にアクセスして操作でき、クラスの動作を実現できます。


クラスのメソッド

クラス内部では、defキーワードを使用してメソッドを定義します。通常の関数定義とは異なり、クラスメソッドにはパラメータ self を含める必要があり、それが最初のパラメータです。self はクラスのインスタンスを表します。

例(Python 3.0+)

#!/usr/bin/python3 # クラス定義 class people: # 基本的な属性を定義 name = '' age = 0 # プライベート属性を定義。プライベート属性はクラス外部から直接アクセスできない __weight = 0 # コンストラクタを定義 def __init__(self,n,a,w): self.name = n self.age = a self.__weight = w def speak(self): print("%s は言う: 私は %d 歳です。" %(self.name,self.age)) # クラスをインスタンス化 p = people('サンプル',10,30) p.speak()

上記のプログラムを実行すると、出力結果は次のとおりです:

サンプル 说: 我 10 岁。

継承

Pythonはクラスの継承もサポートしています。ある言語が継承をサポートしていなければ、クラスには意味がありません。派生クラスの定義は次のとおりです:

class DerivedClassName(BaseClassName): <statement-1> . . . <statement-N>

サブクラス(派生クラス DerivedClassName)は、親クラス(基底クラス BaseClassName)の属性とメソッドを継承します。

BaseClassName(例の中の基底クラス名)は、派生クラスの定義と同じスコープ内にある必要があります。クラスのほかに、式を使うこともできます。基底クラスが別のモジュールで定義されている場合、これは非常に便利です:

class DerivedClassName(modname.BaseClassName):

例(Python 3.0+)

#!/usr/bin/python3 # クラス定義 class people: # 基本的な属性を定義 name = '' age = 0 # プライベート属性を定義。プライベート属性はクラス外部から直接アクセスできない __weight = 0 # コンストラクタを定義 def __init__(self,n,a,w): self.name = n self.age = a self.__weight = w def speak(self): print("%s は言う: 私は %d 歳です。" %(self.name,self.age)) # 単一継承の例 class student(people): grade = '' def __init__(self,n,a,w,g): # 親クラスのコンストラクタを呼び出す people.__init__(self,n,a,w) self.grade = g # 親クラスのメソッドをオーバーライド def speak(self): print("%s は言う: 私は %d 歳になりました。%d 年生です。"%(self.name,self.age,self.grade)) s = student('ken',10,60,3) s.speak()

上記のプログラムを実行すると、出力結果は次のとおりです:

ken 说: 我 10 岁了,我在读 3 年级

多重継承

Pythonも限定的に多重継承をサポートしています。多重継承のクラス定義は次の例のようになります:

class DerivedClassName(Base1, Base2, Base3): <statement-1> . . . <statement-N>

括弧内の親クラスの順序に注意する必要があります。親クラスに同じメソッド名があり、子クラスで使用する際に指定しない場合、Pythonは左から右に検索します。つまり、メソッドが子クラスで見つからない場合、左から右に親クラスにメソッドが含まれているかどうかを探します。

例(Python 3.0+)

#!/usr/bin/python3 # クラス定義 class people: # 基本属性を定義 name = '' age = 0 # プライベート属性を定義。プライベート属性はクラス外部から直接アクセスできない __weight = 0 # コンストラクタを定義 def __init__(self,n,a,w): self.name = n self.age = a self.__weight = w def speak(self): print("%s は言う: 私は %d 歳です。" %(self.name,self.age)) # 単一継承の例 class student(people): grade = '' def __init__(self,n,a,w,g): # 親クラスのコンストラクタを呼び出す people.__init__(self,n,a,w) self.grade = g # 親クラスのメソッドをオーバーライド def speak(self): print("%s は言う: 私は %d 歳になりました。%d 年生です"%(self.name,self.age,self.grade)) # 別のクラス、多重継承の前準備 class speaker(): topic = '' name = '' def __init__(self,n,t): self.name = n self.topic = t def speak(self): print("私は %s です。演説家で、私の講演テーマは %s です"%(self.name,self.topic)) # 多重継承 class sample(speaker,student): a ='' def __init__(self,n,a,w,g,t): student.__init__(self,n,a,w,g) speaker.__init__(self,n,t) test = sample("Tim",25,80,4,"Python") test.speak() # メソッド名が同じ場合、デフォルトで呼び出されるのは括弧内の引数位置が前にある親クラスのメソッド

上記のプログラムを実行すると、出力結果は次のとおりです:

我叫 Tim,我是一个演说家,我演讲的主题是 Python

メソッドのオーバーライド

親クラスのメソッドの機能がニーズを満たさない場合、子クラスで親クラスのメソッドをオーバーライドできます。例は次のとおりです。

例(Python 3.0+)

#!/usr/bin/python3 class Parent: # 親クラスを定義 def myMethod(self): print ('親クラスのメソッドを呼び出す') class Child(Parent): # 子クラスを定義 def myMethod(self): print ('子クラスのメソッドを呼び出す') c = Child() # 子クラスのインスタンス c.myMethod() # 子クラスがオーバーライドしたメソッドを呼び出す super(Child,c).myMethod() # 子クラスのオブジェクトで、親クラスで既にオーバーライドされたメソッドを呼び出す

super() 関数親クラス(スーパークラス)のメソッドを呼び出すために使用します。

上記のプログラムを実行すると、出力結果は次のとおりです:

サブクラスのメソッドを呼び出す
親クラスのメソッドを呼び出す

詳細ドキュメント:

Python 子クラスが親クラスのコンストラクタを継承する説明


クラスの属性とメソッド

クラスのプライベート属性

__private_attrs:2つのアンダースコアで始まり、その属性をプライベートと宣言し、クラスの外部で使用または直接アクセスできません。クラス内部のメソッドで使用する場合self.__private_attrs。

クラスのメソッド

クラスの内部では、def キーワードを使用してメソッドを定義します。一般的な関数定義とは異なり、クラスメソッドはパラメータを含む必要があります。self,かつ最初のパラメータである必要があり、selfクラスのインスタンスを表します。

selfの名前は固定されておらず、使用することもできますthis,しかしやはり慣例に従って使用するのが最善ですself。

クラスのプライベートメソッド

__private_method:2つのアンダースコアで始まり、そのメソッドをプライベートメソッドと宣言します。クラスの内部でのみ呼び出せ、クラスの外部からは呼び出せません。self.__private_methods。

例

クラスのプライベート属性の例は次のとおりです:

例(Python 3.0+)

#!/usr/bin/python3 class JustCounter: __secretCount = 0 # プライベート変数 publicCount = 0 # 公開変数 def count(self): self.__secretCount += 1 self.publicCount += 1 print (self.__secretCount) counter = JustCounter() counter.count() counter.count() print (counter.publicCount) print (counter.__secretCount) # エラー:インスタンスはプライベート変数にアクセスできない

上記のプログラムを実行すると、出力結果は次のとおりです:

1
2
2
Traceback (most recent call last):
  File "test.py", line 16, in <module>
    print (counter.__secretCount)  # 报错,实例不能访问私有变量
AttributeError: 'JustCounter' object has no attribute '__secretCount'

クラスのプライベートメソッドの例は次のとおりです:

例(Python 3.0+)

#!/usr/bin/python3 class Site: def __init__(self, name, url): self.name = name # public self.__url = url # private def who(self): print('name : ', self.name) print('url : ', self.__url) def __foo(self): # プライベートメソッド print('これはプライベートメソッドです') def foo(self): # パブリックメソッド print('これはパブリックメソッドです') self.__foo() x = Site('サンプル', 'www.example.com') x.who() # 正常に出力 x.foo() # 正常に出力 x.__foo() # エラー

上記の例の実行結果:

クラスの特殊メソッド:

  • __init__ :コンストラクタ、オブジェクト生成時に呼び出される
  • __del__ :デストラクタ、オブジェクト解放時に使用される
  • __repr__ :表示(プリント)、変換
  • __setitem__ :インデックスに従って代入
  • __getitem__:インデックスに従って値を取得
  • __len__:長さを取得
  • __cmp__:比較演算
  • __call__:関数呼び出し
  • __add__:加算演算
  • __sub__:減算演算
  • __mul__:乗算演算
  • __truediv__:除算演算
  • __mod__:剰余演算
  • __pow__:累乗

演算子オーバーロード

Python も演算子オーバーロードをサポートしています。クラスの特殊メソッドをオーバーロードできます。例は次のとおりです。

例(Python 3.0+)

#!/usr/bin/python3 class Vector: def __init__(self, a, b): self.a = a self.b = b def __str__(self): return 'Vector (%d, %d)' % (self.a, self.b) def __add__(self,other): return Vector(self.a + other.a, self.b + other.b) v1 = Vector(2,10) v2 = Vector(5,-2) print (v1 + v2)

上記のコードを実行した結果は次のとおりです:

Vector(7,8)
その他の拡張