Python-オブジェクト指向
前のページ次のページ
Python は、その存在以来、オブジェクト指向言語でした。このため、クラスとオブジェクトの作成と使用は非常に簡単です。この章は、Python のオブジェクト指向プログラミング サポートを使用するエキスパートになるのに役立ちます。
オブジェクト指向 (OO) プログラミングの経験がない場合は、基本的な概念を把握するために、オブジェクト指向 (OO) プログラミングの入門コースまたは少なくとも何らかのチュートリアルを参照することをお勧めします。
ただし、ここでは、オブジェクト指向プログラミング (OOP) を簡単に紹介して、迅速に説明します −
OOP 用語の概要
-
クラス - クラスの任意のオブジェクトを特徴付ける一連の属性を定義する、オブジェクトのユーザー定義のプロトタイプ。属性はデータ メンバー (クラス変数とインスタンス変数) とメソッドであり、ドット表記でアクセスします。
-
クラス変数 - クラスのすべてのインスタンスによって共有される変数。クラス変数はクラス内で定義されますが、クラスのメソッドの外側では定義されません。クラス変数は、インスタンス変数ほど頻繁には使用されません。
-
データ メンバー − クラスとそのオブジェクトに関連付けられたデータを保持するクラス変数またはインスタンス変数。
-
関数のオーバーロード - 特定の機能への複数の動作の割り当て。実行される操作は、関連するオブジェクトまたは引数のタイプによって異なります。
-
インスタンス変数 − メソッド内で定義され、クラスの現在のインスタンスのみに属する変数。
-
継承 − クラスの特性を、そこから派生した他のクラスに移すこと。
-
インスタンス − 特定のクラスの個々のオブジェクト。たとえば、Circle クラスに属するオブジェクト obj は、Circle クラスのインスタンスです。
-
インスタンス化 − クラスのインスタンスの作成。
-
方法 − クラス定義で定義される特別な種類の関数。
-
オブジェクト − クラスによって定義されたデータ構造の一意のインスタンス。オブジェクトは、データ メンバー (クラス変数とインスタンス変数) とメソッドの両方で構成されます。
-
演算子のオーバーロード − 特定の演算子への複数の機能の割り当て。
クラスの作成
クラス ステートメントは、新しいクラス定義を作成します。クラスの名前は、キーワード class の直後に続きます 次のようにコロンが続きます −
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):
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
-
変数 empCount このクラスのすべてのインスタンス間で値が共有されるクラス変数です。これは Employee.empCount としてアクセスできます クラス内またはクラス外から。
-
最初のメソッド __init__() このクラスの新しいインスタンスを作成するときに Python が呼び出す、クラス コンストラクターまたは初期化メソッドと呼ばれる特別なメソッドです。
-
各メソッドの最初の引数が self であることを除いて、通常の関数のように他のクラス メソッドを宣言します。 . Python は self を追加します あなたのためのリストへの引数。メソッドを呼び出すときに含める必要はありません。
インスタンス オブジェクトの作成
クラスのインスタンスを作成するには、クラス名を使用してクラスを呼び出し、その __init__ に任意の引数を渡します メソッドは受け入れます。
"This would create first object of Employee class"
emp1 = Employee("Zara", 2000)
"This would create second object of Employee class"
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
def displayEmployee(self):
print "Name : ", self.name, ", Salary: ", self.salary
"This would create first object of Employee class"
emp1 = Employee("Zara", 2000)
"This would create second object of Employee class"
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, name[, default]) − オブジェクトの属性にアクセスします。
-
hasattr(obj,name) − 属性が存在するかどうかを確認します。
-
setattr(obj,name,value) − 属性を設定します。属性が存在しない場合は作成されます。
-
delattr(obj, name) − 属性を削除します。
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__ - クラス ドキュメント文字列または定義されていない場合はなし。
-
__name__ − クラス名。
-
__モジュール__ − クラスが定義されているモジュール名。この属性は、対話モードでは「__main__」です。
-
__拠点__ − 基本クラス リストでの出現順に、基本クラスを含む空のタプル。
上記のクラスについて、これらすべての属性にアクセスしてみましょう −
ライブデモ
#!/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(sub, sup) 指定されたサブクラス sub の場合、ブール関数は true を返します 実際、スーパークラス sup のサブクラスです .
-
isinstance(obj, クラス) obj の場合、ブール関数は true を返します クラス Class のインスタンスです または Class のサブクラスのインスタンスです
メソッドのオーバーライド
親クラスのメソッドはいつでもオーバーライドできます。親のメソッドをオーバーライドする理由の 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
基本オーバーロード メソッド
次の表に、独自のクラスでオーバーライドできる一般的な機能をいくつか示します −
| Sr.No. | メソッド、説明、サンプル呼び出し |
|---|---|
| 1 | __init__ (自己 [,args...]) コンストラクター (任意の引数付き) サンプル呼び出し:obj =className(args) |
| 2 | __del__(自己) デストラクタ、オブジェクトを削除します サンプル呼び出し:del obj |
| 3 | __repr__(自己) 評価可能な文字列表現 サンプル呼び出し:repr(obj) |
| 4 | __str__(自己) 印刷可能な文字列表現 サンプル呼び出し:str(obj) |
| 5 | __cmp__ (自己, 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)
データ隠蔽
オブジェクトの属性は、クラス定義の外で見える場合と見えない場合があります。 2 つのアンダースコアのプレフィックスを付けて属性に名前を付ける必要があり、それらの属性は部外者に直接表示されません。
例
ライブデモ
#!/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
Python