Python – オブジェクト指向

Advertisements

Pythonは存在していたときからオブジェクト指向の言語でした。 そのため、クラスやオブジェクトの作成や使用はとても簡単です。

もしあなたがオブジェクト指向プログラミングの経験がないのであれば、基本的な概念を理解するために、オブジェクト指向の入門コースや、少なくともチュートリアルを参照するとよいでしょう。

しかし、ここでは、オブジェクト指向プログラミング (OOP) の小さな紹介をします。

Overview of OOP Terminology

  • クラス – ユーザー定義のオブジェクトのプロトタイプで、そのクラスのオブジェクトを特徴づける一連の属性を定義します。 属性とは、データ メンバー (クラス変数とインスタンス変数) とメソッドのことで、ドット記法でアクセスします。

  • クラス変数 – クラスのすべてのインスタンスで共有される変数です。 クラス変数は、クラスの中で定義されますが、クラスのメソッドの外で定義されます。

  • データ メンバー – クラスとそのオブジェクトに関連するデータを保持するクラス変数またはインスタンス変数

  • 関数のオーバーロード – 特定の関数に複数の動作を割り当てること。 実行される操作は、関係するオブジェクトや引数のタイプによって異なります。

  • インスタンス変数 – メソッドの内部で定義され、クラスの現在のインスタンスにのみ属する変数。

  • 継承 – あるクラスの特性を、そのクラスから派生した他のクラスに移すこと。

  • インスタンス – あるクラスの個々のオブジェクト。 例えば、Circleというクラスに属するオブジェクトobjは、Circleというクラスのインスタンスです。

  • インスタンス – クラスのインスタンスを作成すること。

  • メソッド – クラス定義で定義された特別な種類の関数。

  • オブジェクト – クラスで定義されたデータ構造の固有のインスタンス。

  • 演算子のオーバーロード – 特定の演算子に複数の関数を割り当てること

クラスの作成

class ステートメントは、新しいクラス定義を作成します。 クラスの名前は、キーワード class の直後に、次のようにコロンが続きます –

class ClassName: 'Optional class documentation string' class_suite
  • クラスにはドキュメント文字列があり、ClassName.__doc__.

  • class_suite は、クラス メンバー、データ属性、および関数を定義するすべてのコンポーネント ステートメントで構成されます。

Example

以下はシンプルな 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 は、このクラスのすべてのインスタンスで値が共有されるクラス変数です。

  • 最初の __init__() メソッドは、クラス コンストラクタまたは初期化メソッドと呼ばれる特別なメソッドで、このクラスの新しいインスタンスを作成するときに 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)

属性へのアクセス

オブジェクトの属性にアクセスするには、ドット演算子 with object を使用します。

emp1.displayEmployee()emp2.displayEmployee()print "Total Employee %d" % Employee.empCount

さて、これらの概念をまとめると

#!/usr/bin/pythonclass 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: 2000Name : Manni ,Salary: 5000Total Employee 2

クラスの属性を追加、削除、変更することができます。 クラスやオブジェクトの属性をいつでも追加、削除、変更することができます –

emp1.age = 7 # Add an 'age' attribute.emp1.age = 8 # Modify 'age' attribute.del emp1.age # Delete 'age' attribute.

通常のステートメントを使用して属性にアクセスする代わりに、以下の関数を使用することができます –

  • getattr(obj, name) – オブジェクトの属性にアクセスします。

  • The hasattr(obj,name) – 属性が存在するかどうかをチェックします。

  • The setattr(obj,name,value) – 属性を設定します。

  • the delattr(obj, name) – 属性を削除します。

hasattr(emp1, 'age') # Returns true if 'age' attribute existsgetattr(emp1, 'age') # Returns value of 'age' attributesetattr(emp1, 'age', 8) # Set attribute 'age' at 8delattr(empl, 'age') # Delete attribute 'age'

クラスの組み込み属性

すべての Python クラスは以下の組み込み属性を保持しており、他の属性と同様にドット演算子を使用してアクセスすることができます –

  • __dict__ – クラスの名前空間を含む辞書。

  • __doc__ – クラスのドキュメント文字列、または未定義の場合はなし。

  • __name__ – クラスの名前。

  • __module__ – クラスが定義されているモジュール名。 この属性は、インタラクティブ モードでは “__main__” です。

  • __bases__ – ベース クラス リストでの出現順に、ベース クラスを含む空のタプルです。

上記のクラスについて、これらすべての属性にアクセスしてみましょう –

#!/usr/bin/pythonclass 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.salaryprint "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 employeesEmployee.__name__: EmployeeEmployee.__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>}

Destroying Objects (Garbage Collection)

Pythonはメモリ空間を解放するために、不要なオブジェクト(組み込み型やクラスインスタンス)を自動的に削除します。

Pythonのガベージコレクタはプログラムの実行中に実行され、オブジェクトの参照カウントがゼロになったときに起動されます。

オブジェクトの参照数は、そのオブジェクトを指すエイリアスの数が変わると変化します。

オブジェクトの参照数は、新しい名前が割り当てられたり、コンテナ(リスト、タプル、辞書)に入れられたりすると増えます。 オブジェクトの参照カウントが減少するのは、delで削除されたとき、その参照が再割り当てされたとき、またはその参照がスコープ外になったときです。

a = 40 # Create object <40>b = a # Increase ref. count of <40> c = # Increase ref. count of <40> del a # Decrease ref. count of <40>b = 100 # Decrease ref. count of <40> c = -1 # Decrease ref. count of <40> 

通常、ガベージコレクタが孤児となったインスタンスを破壊し、そのスペースを取り戻しても気づくことはありません。 しかし、クラスはデストラクタと呼ばれる特別なメソッド __del__() を実装することができ、このメソッドはインスタンスが破壊されようとしているときに呼び出されます。 このメソッドは、インスタンスが使用する非メモリリソースをクリーンアップするために使用されるかもしれません。

この __del__() デストラクタは、破壊されようとしているインスタンスのクラス名を表示します –

#!/usr/bin/pythonclass 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 = pt1pt3 = pt1print id(pt1), id(pt2), id(pt3) # prints the ids of the obejctsdel pt1del pt2del pt3

上記のコードを実行すると、次のような結果が得られます。

3083401324 3083401324 3083401324Point destroyed

注意 – 理想的には、別のファイルでクラスを定義し、importステートメントを使用してメインのプログラムファイルでそれらをインポートする必要があります。

クラスの継承

ゼロから始めるのではなく、新しいクラス名の後に親クラスを括弧内に記載することで、既存のクラスから派生させてクラスを作成することができます。

子クラスは親クラスの属性を継承し、子クラスで定義されたかのようにそれらの属性を使用することができます。 また、子クラスは親クラスのデータメンバーやメソッドをオーバーライドすることができます。

構文

派生クラスは親クラスと同様に宣言されます。

class SubClassName (ParentClass1): 'Optional class documentation string' class_suite

Example

#!/usr/bin/pythonclass 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.parentAttrclass Child(Parent): # define child class def __init__(self): print "Calling child constructor" def childMethod(self): print 'Calling child method'c = Child() # instance of childc.childMethod() # child calls its methodc.parentMethod() # calls parent's methodc.setAttr(200) # again call parent's methodc.getAttr() # again call parent's method

上記のコードを実行すると、次のような結果が得られます

Calling child constructorCalling child methodCalling parent methodParent attribute : 200

同様に、複数の親クラスからクラスを派生させることができます。

class A: # define your class A.....class B: # define your class B.....class C(A, B): # subclass of A and B.....

2つのクラスやインスタンスの関係を調べるには、 issubclass() や isinstance() 関数を使用します。

  • issubclass(sub, sup)ブール関数は、与えられたサブクラスsubが確かにスーパークラスsupのサブクラスである場合、trueを返します。

  • isinstance(obj, Class)ブール関数は、objがクラスClassのインスタンスである場合、またはClassのサブクラスのインスタンスである場合にtrueを返します

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

常に親クラスのメソッドをオーバーライドすることができます。 親クラスのメソッドをオーバーライドする理由のひとつは、サブクラスに特別な機能や異なる機能を求めることができるからです。

#!/usr/bin/pythonclass 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 childc.myMethod() # child calls overridden method

上記のコードを実行すると、次のような結果になります。

Calling child method

Base Overloading Methods

以下の表は、自分のクラスでオーバーライドできる一般的な機能の一覧です –

Sr.No. Method, Description & Sample Call
1

__init__ ( self )

コンストラクタ(任意のオプション引数付き)

Sample Call : obj = className(args)

2

__del__( self )

デストラクタ、オブジェクトを削除します

Sample Call : del obj

3

__repr__( self )

評価される文字列表現

サンプルコール : repr(obj)

4

__str__( self )

印刷可能な文字列表現

Sample Call : str(obj)

5

__cmp__ ( self, x )

オブジェクトの比較

Sample Call : cmp(obj, x)

オーバーロード演算子

2次元のベクトルを表現するためにVectorクラスを作成したとしましょう。 ほとんどの場合、Pythonに怒られます。

しかし、ベクトルの加算を実行するためにクラス内で __add__ メソッドを定義すれば、プラス演算子は期待通りの動作をします –

#!/usr/bin/pythonclass 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/pythonclass JustCounter: __secretCount = 0 def count(self): self.__secretCount += 1 print self.__secretCountcounter = JustCounter()counter.count()counter.count()print counter.__secretCount

上記のコードを実行すると、次のような結果になります –

12Traceback (most recent call last): File "test.py", line 12, in <module> print counter.__secretCountAttributeError: JustCounter instance has no attribute '__secretCount'

Pythonは内部的にクラス名を含むように名前を変更することで、これらのメンバーを保護します。 このような属性には、object._className__attrNameとしてアクセスできます。

.........................print counter._JustCounter__secretCount

上記のコードを実行すると、次のような結果が得られます。

コメントする

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です