Python3-python-classes-objects

提供:Dev Guides
移動先:案内検索

Python 3-オブジェクト指向

Pythonは、存在して以来オブジェクト指向言語でした。 このため、クラスとオブジェクトの作成と使用は非常に簡単です。 この章は、Pythonのオブジェクト指向プログラミングサポートの使用に関する専門家になるのに役立ちます。

オブジェクト指向(OO)プログラミングの経験がない場合は、入門コースまたは少なくとも何らかのチュートリアルを参照して、基本的な概念を把握してください。

しかし、ここではあなたを助けるためにオブジェクト指向プログラミング(OOP)の小さな紹介です-

OOP用語の概要

  • クラス-クラスのオブジェクトを特徴付ける一連の属性を定義するオブジェクトのユーザー定義プロトタイプ。 属性は、データメンバー(クラス変数とインスタンス変数)とメソッドであり、ドット表記でアクセスします。
  • クラス変数-クラスのすべてのインスタンスで共有される変数。 クラス変数はクラス内で定義されますが、クラスのメソッドの外部で定義されます。 クラス変数は、インスタンス変数ほど頻繁には使用されません。
  • データメンバー-クラスとそのオブジェクトに関連付けられたデータを保持するクラス変数またはインスタンス変数。
  • 関数のオーバーロード-特定の関数への複数の動作の割り当て。 実行される操作は、関連するオブジェクトまたは引数のタイプによって異なります。
  • インスタンス変数-メソッド内で定義され、クラスの現在のインスタンスにのみ属する変数。
  • 継承-クラスの特性を、それから派生した他のクラスに転送します。
  • インスタンス-特定のクラスの個々のオブジェクト。 たとえば、クラスCircleに属するオブジェクトobjは、クラスCircleのインスタンスです。
  • インスタンス-クラスのインスタンスの作成。
  • メソッド-クラス定義で定義されている特別な種類の関数。
  • オブジェクト-クラスによって定義されるデータ構造の一意のインスタンス。 オブジェクトは、データメンバー(クラス変数とインスタンス変数)とメソッドの両方で構成されます。
  • 演算子のオーバーロード-特定の演算子への複数の関数の割り当て。

クラスを作成する

_class_ステートメントは、新しいクラス定義を作成します。 クラスの名前は、キーワード_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_は、値がこのクラスのaのすべてのインスタンス間で共有されるクラス変数です。 これは、クラス内またはクラス外から_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/python3

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.salary = 7000  # Add an 'salary' attribute.
emp1.name = 'xyz'  # Modify 'age' attribute.
del emp1.salary  # Delete 'age' attribute.

通常のステートメントを使用して属性にアクセスする代わりに、次の機能を使用できます-

  • * getattr(obj、name [、default])*-オブジェクトの属性にアクセスします。
  • * hasattr(obj、name)*-属性が存在するかどうかを確認します。
  • * setattr(obj、name、value)*-属性を設定します。 属性が存在しない場合、作成されます。
  • * delattr(obj、name)*-属性を削除します。
hasattr(emp1, 'salary')    # Returns true if 'salary' attribute exists
getattr(emp1, 'salary')    # Returns value of 'salary' attribute
setattr(emp1, 'salary', 7000) # Set attribute 'salary' at 7000
delattr(emp1, 'salary')    # Delete attribute 'salary'

組み込みクラスの属性

すべてのPythonクラスは組み込みの属性を追跡し続け、他の属性と同様にドット演算子を使用してアクセスできます-

  • dict -クラスの名前空間を含む辞書。
  • doc -クラスのドキュメント文字列または未定義の場合はなし。
  • name -クラス名。
  • module -クラスが定義されているモジュール名。 この属性は、対話モードでは「main」です。
  • bases -基本クラスリストに出現する順序で、基本クラスを含む空の可能性のあるタプル。

上記のクラスの場合、これらすべての属性にアクセスしてみましょう-

#!/usr/bin/python3

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)

emp1 = Employee("Zara", 2000)
emp2 = Employee("Manni", 5000)
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__: (<class 'object'>,)
Employee.__dict__: {
   'displayCount': <function Employee.displayCount at 0x0160D2B8>,
   '__module__': '__main__', '__doc__': 'Common base class for all employees',
   'empCount': 2, '__init__':
   <function Employee.__init__ at 0x0124F810>, 'displayEmployee':
   <function Employee.displayEmployee at 0x0160D300>,
   '__weakref__':
   <attribute '__weakref__' of 'Employee' objects>, '__dict__':
   <attribute '__dict__' of 'Employee' objects>
}

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

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

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

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

a = 40      # Create object 
b = a       # Increase ref. count  of 
c = [b]     # Increase ref. count  of 

del a       # Decrease ref. count  of 
b = 100     # Decrease ref. count  of 
c[0] = -1   # Decrease ref. count  of

通常、ガベージコレクターが孤立したインスタンスを破棄し、そのスペースを再利用することに気付かないでしょう。 ただし、クラスは、インスタンスが破棄されようとしているときに呼び出されるデストラクタと呼ばれる特別なメソッド_ del()_を実装できます。 このメソッドは、インスタンスで使用されているメモリ以外のリソースをクリーンアップするために使用される場合があります。

このdel()デストラクタは、破棄されようとしているインスタンスのクラス名を出力します-

#!/usr/bin/python3

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

上記のコードが実行されると、次の結果が生成されます-

140338326963984 140338326963984 140338326963984
Point destroyed

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

上記の例では、Pointクラスの定義が_point.py_に含まれており、その中に他の実行可能コードがないと想定しています。

#!/usr/bin/python3
import point

p1 = point.Point()

クラスの継承

ゼロから始める代わりに、新しいクラス名の後に括弧で親クラスをリストすることにより、既存のクラスから派生することにより、クラスを作成できます。

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

構文

派生クラスは、親クラスのように宣言されます。ただし、継承する基本クラスのリストは、クラス名の後に指定されます-

class SubClassName (ParentClass1[, ParentClass2, ...]):
   'Optional class documentation string'
   class_suite

#!/usr/bin/python3

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

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

issubclass()またはisinstance()関数を使用して、2つのクラスとインスタンスの関係を確認できます。

  • * issubclass(s​​ub、sup)ブール関数は、指定されたサブクラス *sub が実際にスーパークラス sup のサブクラスである場合、Trueを返します。
  • _obj_がクラス_Class_のインスタンスであるか、クラスのサブクラスのインスタンスである場合、* isinstance(obj、Class)*ブール関数はTrueを返します。

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

親クラスのメソッドはいつでもオーバーライドできます。 親のメソッドをオーバーライドする理由の1つは、サブクラスで特別な機能または異なる機能が必要になる場合があることです。

#!/usr/bin/python3

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. Method, Description & Sample Call
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/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)

データ隠蔽

オブジェクトの属性は、クラス定義の外部で表示される場合と表示されない場合があります。 属性に二重アンダースコアプレフィックスを付ける必要があります。これらの属性は部外者には直接表示されません。

#!/usr/bin/python3

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