Python – Object Oriented

Advertisements

Pythonは存在した時からオブジェクト指向の言語でありました。 このため、クラスやオブジェクトを作成したり、使用したりすることは、実に簡単です。 この章では、Python のオブジェクト指向プログラミングサポートを使いこなすための手助けをします。

オブジェクト指向(OO)プログラミングの経験がない場合、基本的な概念を把握するために、それに関する入門コースや少なくともある種のチュートリアルを参照するとよいかもしれません。

しかしながら、ここでは、オブジェクト指向プログラミング (OOP) の簡単な紹介をします。 属性はデータ メンバー (クラス変数とインスタンス変数) とメソッドで、ドット表記でアクセスします。

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

  • Data member – クラスおよびそのオブジェクトに関連するデータを保持するクラス変数またはインスタンス変数。

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

  • Inheritance – あるクラスの特性をそこから派生する他のクラスへ移すこと。 たとえば、Circle クラスに属するオブジェクト obj は、Circle クラスのインスタンスです。

  • Instantiation – クラスのインスタンスの作成。

  • Method – クラス定義で定義されている特殊な関数。

  • Object – そのクラスによって定義されているデータ構造の固有のインスタンス。 オブジェクトは、データ メンバー (クラス変数とインスタンス変数) とメソッドの両方で構成されます。

  • Operator overloading – 特定の演算子に複数の関数を代入すること。 クラスの名前は、次のようにキーワード 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は、このクラスのすべてのインスタンスの間で値を共有するクラス変数である。

    • 最初のメソッド __init__() は、このクラスの新しいインスタンスを作成するときにPythonが呼び出すクラスコンストラクタまたは初期化メソッドと呼ばれる特別なメソッドです。 Python は self 引数をリストに追加します。

    Creating Instance Objects

    クラスのインスタンスを作成するには、クラス名を使ってクラスを呼び出し、その __init__ メソッドが受け付けるあらゆる引数に渡します。 クラス変数には、クラス名を使って次のようにアクセスします。

    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'

    Built-In Class Attributes

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

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

    • __doc__ – クラスドキュメント文字列、あるいは未定の場合ゼロです。

    • __name__ – クラス名.

    • __module__ – クラスが定義されているモジュール名.

    • __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>}

    オブジェクトの破棄(ガーベッジコレクション)

    Pythonは不要なオブジェクト(組み込み型またはクラスのインスタンス)を自動的に削除してメモリ領域を解放します。 Python が定期的に、もはや使用されていないメモリブロックを回収するプロセスは、ガベージコレクションと呼ばれています。

    Python のガベージコレクタはプログラムの実行中に動作し、オブジェクトの参照カウントがゼロに達するとトリガされます。 オブジェクトの参照カウントは、それを指すエイリアスの数が変わると変化します。

    オブジェクトの参照カウントは、それが新しい名前を割り当てられたり、コンテナ (リスト、タプル、または辞書) に配置されたときに増加します。 オブジェクトの参照カウントは、それが del で削除されたり、その参照が再割り当てされたり、その参照がスコープ外になると減少します。 オブジェクトの参照カウントが 0 になると、Python は自動的にそれを回収します。

    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.....

    二つのクラスとインスタンスの関係を確認するには issubclass() または isinstance() 関数を使用することができます。

    • issubclass(sub, sup) boolean 関数は与えられたサブクラス sub が本当にスーパークラス sup のサブクラスであれば真を返します。

    • isinstance(obj, Class) boolean 関数は obj が Class クラスのインスタンスであるか、Class のサブクラスのインスタンスであれば真を返す

    オーバーライドするメソッド

    あなたは常に親クラスをオーバーライドすることができます。

    Example

    #!/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. メソッド、説明 & サンプルコール
    1

    __init__ ( self )

    コンストラクタ(任意のオプション引数を持つ)

    サンプルコール: obj = className(args)

    2

    __del__( self )

    Destructor, delete an object

    Sample Call : del obj

    3

    __repr__( self )

    評価できる文字列表現

    Sample Call : repr(obj)

    4

    __str__( self )

    Printable string representation

    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)

    データ隠し

    オブジェクトの属性がクラス定義の外からは見えなかったり見えなかったりする場合があります。

    Example

    #!/usr/bin/pythonclass JustCounter: __secretCount = 0 def count(self): self.__secretCount += 1 print self.__secretCountcounter = JustCounter()counter.count()counter.count()print counter.__secretCount

    上記のコードを実行すると、次のような結果が得られます。 このような属性には object._className__attrName としてアクセスすることができます。 最後の行を次のように置き換えると、うまくいきます。

  • コメントを残す

    メールアドレスが公開されることはありません。