Contents
Pythonオブジェクト指向
Pythonは誕生して以来、オブジェクト指向言語です。このため、クラスとオブジェクトの作成と使用は非常に簡単です。この章では、Pythonのオブジェクト指向プログラミングについて理解をしていきます。
オブジェクト指向(OO)プログラミングに関する以前の経験がない場合は、その入門コースまたは入門チュートリアルを参照して、基本的な概念を把握してください。
ここではまずオブジェクト指向プログラミング(OOP)を理解します
OOP用語の概要
- クラス:任意のオブジェクトを特徴付ける一連の属性を定義するオブジェクトのユーザー定義プロトタイプ。例えば人間というクラスがあれば、人間の中には太郎や花子がいるくらいの感覚です
- クラス変数:すべてのインスタンス間で共通した値をもつ変数です。クラス変数はインスタンスを生成することなく参照することができます。
- データメンバー:クラスおよびそのオブジェクトに関連付けられたデータを保持するクラス変数またはインスタンス変数。つまり変数
- 関数のオーバーロード:特定の関数に複数の動作を割り当てる。実行される操作は、関連するオブジェクトまたは引数のタイプによって異なります。
- インスタンス変数:メソッド内で定義され、クラスの現在のインスタンスにのみ属する変数。
- 継承:クラスの特性をそれから派生した他のクラスに移す。
- インスタンス: 特定のクラスの個々のオブジェクト。例えばCircleクラスに属するオブジェクトobjは、Circleクラスのインスタンスです。
- インスタンス化:クラスのインスタンスの作成。
- メソッド:クラス定義で定義される特別な種類の関数。
- オブジェクト:クラスによって定義されたデータ構造の一意のインスタンス。オブジェクトは、データメンバー(クラス変数とインスタンス変数)とメソッドの両方を含みます。
- 演算子のオーバーロード:特定の演算子に複数の関数を割り当てる。
クラスの作成
クラスステートメントで、新しいクラス定義を作成します。
class ClassName: 'Optional class documentation string' class_suite
- クラスにはドキュメンテーション文字列があり、ClassName .__ doc__でアクセスできます。
- class_suiteは、クラスメンバー、データ属性と機能を定義するすべてのコンポーネントの文で構成されています。
例
以下は、簡単なPythonクラスの例です。
class Employee: 'Common base class for all employees' empCount = 0 def __init__(self, name, salary): #ここで関数を宣言 defを使う self.name = name #名前を拾ってくる self.salary = salary #給料を Employee.empCount += 1 #従業員のカウント def displayCount(self):#ここで関数を宣言 defを使う print "Total Employee %d" % Employee.empCount def displayEmployee(self):#ここで関数を宣言 defを使う print "Name : ", self.name, ", Salary: ", self.salary
- 変数empCountは、このクラスのすべてのインスタンスで値が共有されるクラス変数です。これは、クラス内またはクラス外からEmployee.empCountとしてアクセスできます。
- 最初のメソッド__init __()は特別なメソッドです。これは、このクラスの新しいインスタンスを作成するときにPythonが呼び出すクラスコンストラクタまたは初期化メソッドと呼ばれます。
- 各メソッドの最初の引数がselfであることを除いて、通常の関数のような他のクラスメソッドを宣言します。Pythonはself引数をリストに追加します。メソッドを呼び出すときに含める必要はありません。
インスタンスオブジェクトの作成
クラスのインスタンスを作成するには、クラス名を使用してクラスを呼び出し、__init__メソッドが受け入れる引数を渡します。
"最初のエンプロイクラス" emp1 = Employee("Zara", 2000) "次のエンプロイクラス" emp2 = Employee("Manni", 5000)
属性へのアクセス
オブジェクトのドット演算子を使用してオブジェクトの属性にアクセスします。クラス変数は、次のようにクラス名を使用してアクセスされます。
emp1.displayEmployee() emp2.displayEmployee() print "Total Employee %d" % Employee.empCount
コンセプトをまとめる と
#!/usr/bin/python class Employee: 'Common base class for all employees' empCount = 0 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print "Total Employee %d" % Employee.empCount #
%d | 符号つき 10 進整 |
def displayEmployee(self): print "Name : ", self.name, ", Salary: ", self.salary "最初のエンプロイクラス" emp1 = Employee("Zara", 2000) "次のエンプロイクラス" emp2 = Employee("Manni", 5000) emp1.displayEmployee() emp2.displayEmployee() print "Total Employee %d" % Employee.empCount
上記のコードを実行すると、次の結果が生成されます。
Name : Zara ,Salary: 2000 Name : Manni ,Salary: 5000 Total Employee 2
クラスやオブジェクトの属性は、いつでも追加、削除、変更できます。
emp1.age = 7 # Add an 'age' attribute. emp1.age = 8 # Modify 'age' attribute. del emp1.age # Delete 'age' attribute.
属性にアクセスするために通常のステートメントを使用する代わりに、次の機能を使用できます。
- GETATTR(OBJ、名[、デフォルト]) :オブジェクトの属性にアクセスします。
- hasattr(OBJ、名):属性が存在するかどうかをチェックします。
- SETATTR(OBJ、名前、値):属性を設定します。属性が存在しない場合は作成されます。
- delattr(OBJ、名):属性を削除します。
hasattr(emp1, 'age') # Returns true if 'age' attribute exists getattr(emp1, 'age') # Returns value of 'age' attribute setattr(emp1, 'age', 8) # Set attribute 'age' at 8 delattr(empl, 'age') # Delete attribute 'age'
組み込みクラス属性
すべてのPythonクラスは組み込みの属性を継承しており、他の属性と同様にドット演算子を使用してアクセスできます。
- __dict__:クラスの名前空間を含む辞書。
- __doc__:クラスのドキュメント文字列または未定義の場合はnone。
- __name__:クラス名。
- __module__:クラスが定義されているモジュール名。この属性は、対話モードでは “__main__”です。
- __bases__:基底クラスを含む、おそらく空のタプル。基底クラスリストでの出現の順序。
上記のクラスでは、これらのすべての属性にアクセスしようとします。
#!/usr/bin/python class Employee: 'Common base class for all employees' empCount = 0 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print "Total Employee %d" % Employee.empCount def displayEmployee(self): print "Name : ", self.name, ", Salary: ", self.salary print "Employee.__doc__:", Employee.__doc__ print "Employee.__name__:", Employee.__name__ print "Employee.__module__:", Employee.__module__ print "Employee.__bases__:", Employee.__bases__ print "Employee.__dict__:", Employee.__dict__
上記のコードを実行すると、次の結果が生成されます。
Employee.__doc__: Common base class for all employees Employee.__name__: Employee Employee.__module__: __main__ Employee.__bases__: () Employee.__dict__: {'__module__': '__main__', 'displayCount': <function displayCount at 0xb7c84994>, 'empCount': 2, 'displayEmployee': <function displayEmployee at 0xb7c8441c>, '__doc__': 'Common base class for all employees', '__init__': <function __init__ at 0xb7c846bc>}
オブジェクトの破棄(ガベージコレクション)
Pythonは不要なオブジェクト(組み込み型やクラスインスタンス)を自動的に削除してメモリ空間を解放します。Pythonが定期的に使用していないメモリブロックを定期的に再利用するプロセスをガベージコレクションと呼びます。
Pythonのガベージコレクタは、プログラムの実行中に実行され、オブジェクトの参照カウントがゼロになるとトリガされます。オブジェクトの参照カウントは、それを指す別名の数が変化すると変化します。
オブジェクトの参照カウントは、新しい名前が割り当てられたり、コンテナ(リスト、タプル、または辞書)に配置されると増加します。オブジェクトの参照カウントがdelで削除されたり、その参照が再割り当てされたり、その参照が有効範囲外になったりすると、オブジェクトの参照カウントは減少します。オブジェクトの参照カウントがゼロになると、Pythonはそれを自動的に収集します。
a = 40 # Create object <40> b = a # Increase ref. count of <40> c = [b] # Increase ref. count of <40> del a # Decrease ref. count of <40> b = 100 # Decrease ref. count of <40> c[0] = -1 # Decrease ref. count of <40>
ガベージコレクタが孤立したインスタンスを破棄し、その領域を再利用するとき、通常は気付かないでしょう。しかし、クラスは、デストラクタと呼ばれる特別なメソッド__del __()を実装できます。デストラクタは、インスタンスが破棄されるときに呼び出されます。このメソッドは、インスタンスによって使用される非メモリリソースをクリーンアップするために使用されます。
例
この__del __()デストラクタは、破壊しようとしているインスタンスのクラス名を出力します。
#!/usr/bin/python class Point: def __init__( self, x=0, y=0): self.x = x self.y = y def __del__(self): class_name = self.__class__.__name__ print class_name, "destroyed" pt1 = Point() pt2 = pt1 pt3 = pt1 print id(pt1), id(pt2), id(pt3) # prints the ids of the obejcts del pt1 del pt2 del pt3
上記のコードが実行されると、次の結果が生成されます。
3083401324 3083401324 3083401324 Point destroyed
注意:理想的には、クラスを別々のファイルで定義し、import文を使用してメインプログラムファイルにインポートするのが理想的です。
クラス継承
最初から始めるのではなく、新しいクラス名の後のカッコ内に親クラスをリストすることによって、既存のクラスからクラスを派生させてクラスを作成することができます。
子クラスはその親クラスの属性を継承し、それらの属性は子クラスで定義されているかのように使用できます。子クラスは、親からのデータメンバーおよびメソッドをオーバーライドすることもできます。
構文
派生クラスは親クラスと同じように宣言されます。ただし、継承元の基本クラスのリストは、クラス名の後に指定されます。
class SubClassName (ParentClass1[, ParentClass2, ...]): 'Optional class documentation string' class_suite
例
#!/usr/bin/python class Parent: # define parent class parentAttr = 100 def __init__(self): print "Calling parent constructor" def parentMethod(self): print 'Calling parent method' def setAttr(self, attr): Parent.parentAttr = attr def getAttr(self): print "Parent attribute :", Parent.parentAttr class Child(Parent): # define child class def __init__(self): print "Calling child constructor" def childMethod(self): print 'Calling child method' c = Child() # instance of child c.childMethod() # child calls its method c.parentMethod() # calls parent's method c.setAttr(200) # again call parent's method c.getAttr() # again call parent's method
上記のコードを実行すると、次の結果が生成されます。
Calling child constructor Calling child method Calling parent method Parent attribute : 200
同様に、次のように複数の親クラスからクラスを駆動することができます。
class A: # define your class A ..... class B: # define your class B ..... class C(A, B): # subclass of A and B .....
issubclass()またはisinstance()関数を使用して、2つのクラスおよびインスタンスの関係をチェックできます。
- issubclass(サブ、SUP)所与のサブクラス場合ブール関数は真を返すサブ実際スーパークラスのサブクラスであるSUP。
- でisinstance(OBJ、クラス)場合ブール関数は真を返すobjがクラスのインスタンスであり、クラスまたはクラスのサブクラスのインスタンスであります
メソッドのオーバーライド
親クラスのメソッドはいつでもオーバーライドできます。親のメソッドをオーバーライドする理由の1つは、サブクラスで特別な機能や異なる機能が必要な場合があるからです。
例
#!/usr/bin/python class Parent: # define parent class def myMethod(self): print 'Calling parent method' class Child(Parent): # define child class def myMethod(self): print 'Calling child method' c = Child() # instance of child c.myMethod() # child calls overridden method
上記のコードを実行すると、次の結果が生成されます。
Calling child method
ベースオーバーロードのメソッド
次の表は、独自のクラスでオーバーライドできるいくつかの一般的な機能を示しています。
SN | 方法、説明、サンプルコール |
---|---|
1 | __init__(self [、args …]) コンストラクタ(オプション引数付き) サンプル呼び出し:obj = className(args) |
2 | __del __(self) デストラクタ、オブジェクトを削除する サンプルコール:del obj |
3 | __repr __(self) 評価可能な文字列表現 サンプル呼び出し:repr(obj) |
4 | __str __(self) 印刷可能な文字列表現 サンプル呼び出し:str(obj) |
5 | __cmp__(self、x) オブジェクトの比較 サンプルコール:cmp(obj、x) |
演算子のオーバーロード
2次元ベクトルを表すVectorクラスを作成したとします。プラス演算子を使用して追加するとどうなりますか?ほとんどの場合、Pythonはあなたに叫ぶでしょう。
しかし、クラス内で__add__メソッドを定義してベクトルを加算すると、プラス演算子は期待通りに動作します。
例
#!/usr/bin/python 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)
データ非表示
オブジェクトの属性は、クラス定義の外側に表示される場合と表示されない場合があります。二重アンダースコアの接頭辞を持つ属性に名前を付ける必要があります。これらの属性は、外部から直接見ることはできません。
例
#!/usr/bin/python class JustCounter: __secretCount = 0 def count(self): self.__secretCount += 1 print self.__secretCount counter = JustCounter() counter.count() counter.count() print counter.__secretCount
上記のコードを実行すると、次の結果が生成されます。
1 2 Traceback (most recent call last): File "test.py", line 12, in <module> print counter.__secretCount AttributeError: JustCounter instance has no attribute '__secretCount'
Pythonはクラス名を含むように内部的に名前を変更することによってそれらのメンバーを保護します。object._className__attrNameなどの属性にアクセスできます。
......................... print counter._JustCounter__secretCount
上記のコードを実行すると、次の結果が生成されます。
1 2 2
次のページ②