Python オブジェクト指向


Python は最初からオブジェクト指向言語であり、そのため、Python でクラスやオブジェクトを作成するのは簡単です。この章では、Python によるオブジェクト指向プログラミングについて詳しく紹介します。

これまでオブジェクト指向プログラミング言語に触れたことがない場合は、まずオブジェクト指向言語のいくつかの基本的な機能を理解し、頭の中でオブジェクト指向の基本的な概念を形成する必要があるかもしれません。 Python でオブジェクト指向プログラミングをより簡単に学習できます。

次に、オブジェクト指向の基本的な特徴をいくつか簡単に理解しましょう。


オブジェクト指向技術の紹介

  • クラス (Class): 同じプロパティとメソッドを持つオブジェクトのコレクションを記述するために使用されます。コレクション内のすべてのオブジェクトに共通のプロパティとメソッドを定義します。オブジェクトはクラスのインスタンスです。

  • クラス変数: クラス変数は、インスタンス化されたオブジェクト全体で共通です。クラス変数はクラス内および関数本体の外で定義されます。クラス変数は通常、インスタンス変数としては使用されません。

  • データメンバー: クラス変数またはインスタンス変数は、クラスとそのインスタンスオブジェクトに関連するデータを処理するために使用されます。

  • メソッドの書き換え: 親クラスから継承されたメソッドがサブクラスのニーズを満たせない場合、このプロセスはメソッドのオーバーライドと呼ばれ、メソッドの書き換えとも呼ばれます。

  • インスタンス変数: メソッドで定義された変数は、現在のインスタンスのクラスにのみ作用します。

  • 継承: つまり、派生クラスは基本クラスのフィールドとメソッドを継承します。継承により、派生クラスのオブジェクトを基本クラス オブジェクトとして扱うこともできます。たとえば、次のような設計があります。Dog タイプのオブジェクトは、「is-a」関係 (たとえば、Dog is an Animal) をシミュレートする Animal クラスから派生します。

  • インスタンス化: クラスのインスタンス、クラスの特定のオブジェクトを作成します。

  • メソッド: クラスで定義された関数。

  • オブジェクト: クラスを通じて定義されたデータ構造のインスタンス。オブジェクトには 2 つのデータ メンバー (クラス変数とインスタンス変数) とメソッドが含まれます。


クラスを作成します

次の例のように、class ステートメントを使用して新しいクラスを作成し、コロンで終わります。 ClassName.__doc__ を通じて表示されます。

class_suite はクラスのメンバー、メソッド、データ属性で構成されます。

以下は簡単な Python クラスの例です:

class ClassName:
   '类的帮助信息'   #类文档字符串
   class_suite  #类体

    empCount 変数はクラス変数であり、その値はこのクラスのすべてのインスタンス間で共有されます。内部クラスまたは外部クラスで Employee.empCount を使用してアクセスできます。
  • 最初のメソッド __init__() メソッドは、クラスのコンストラクターまたは初期化メソッドと呼ばれる特別なメソッドです。このメソッドは、このクラスのインスタンスが作成されるときに呼び出されます
インスタンス オブジェクトを作成する

クラスのインスタンスを作成するには、クラスの名前を使用し、 __init__ メソッド経由で引数を受け取ります。

#!/usr/bin/python
# -*- coding: UTF-8 -*-

class Employee:
   '所有员工的基类'
   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

プロパティへのアクセス

ドット (.) を使用してオブジェクトのプロパティにアクセスできます。クラス変数にアクセスするには、次のクラスの名前を使用します:

"创建 Employee 类的第一个对象"
emp1 = Employee("Zara", 2000)
"创建 Employee 类的第二个对象"
emp2 = Employee("Manni", 5000)

完全な例:

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

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

#!/usr/bin/python
# -*- coding: UTF-8 -*-

class Employee:
   '所有员工的基类'
   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

"创建 Employee 类的第一个对象"
emp1 = Employee("Zara", 2000)
"创建 Employee 类的第二个对象"
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

次の関数を使用して属性にアクセスすることもできます:

    getattr(obj, name[,default]): オブジェクトの属性にアクセスします。
  • hasattr(obj,name) : 属性が存在するかどうかを確認します。
  • setattr(obj,name,value): 属性を設定します。プロパティが存在しない場合は、新しいプロパティが作成されます。

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

emp1.age = 7  # 添加一个 'age' 属性
emp1.age = 8  # 修改 'age' 属性
del emp1.age  # 删除 'age' 属性

Python組み込みクラス属性

  • __dict__: クラスの属性(クラスのデータ属性で構成される辞書を含む)

  • __doc__: クラスのドキュメント文字列

  • __name__: クラス名

  • __module__: クラスが定義されているモジュール (クラスの完全名は '__main__.className'、クラスがインポートされたモジュール mymod にある場合、className.__module__ は等しい) mymod へ)

  • __bases__: クラスのすべての親クラス コンポーネント要素 (すべての親クラスで構成されるタプルを含む)

Python 組み込みクラス属性の呼び出し例は次のとおりです:

hasattr(emp1, 'age')    # 如果存在 'age' 属性返回 True。
getattr(emp1, 'age')    # 返回 'age' 属性的值
setattr(emp1, 'age', 8) # 添加属性 'age' 值为 8
delattr(empl, 'age')    # 删除属性 'age'

上記のコードを実行します出力結果は次のとおりです。

#!/usr/bin/python
# -*- coding: UTF-8 -*-

class Employee:
   '所有员工的基类'
   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__

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

Java 言語と同様、Python は参照カウントと呼ばれる単純な手法を使用してメモリ内のオブジェクトを追跡します。

Python は内部的に、使用中の各オブジェクトが持つ参照の数を記録します。


リファレンスカウンターと呼ばれる内部追跡変数。

オブジェクトが作成されると、オブジェクトが不要になると参照カウントが作成されます。 つまり、このオブジェクトの参照カウントが 0 になると、ガベージ コレクションされます。しかし、リサイクルは「すぐに」できるわけではありません。 インタプリタは、適切なタイミングで、ガベージ オブジェクトによって占有されているメモリ領域を再利用します。

Employee.__doc__: 所有员工的基类
Employee.__name__: Employee
Employee.__module__: __main__
Employee.__bases__: ()
Employee.__dict__: {'__module__': '__main__', 'displayCount': <function displayCount at 0x10a939c80>, 'empCount': 0, 'displayEmployee': <function displayEmployee at 0x10a93caa0>, '__doc__': '\xe6\x89\x80\xe6\x9c\x89\xe5\x91\x98\xe5\xb7\xa5\xe7\x9a\x84\xe5\x9f\xba\xe7\xb1\xbb', '__init__': <function __init__ at 0x10a939578>}

ガベージ コレクション メカニズムは、参照カウントが 0 のオブジェクトを対象とするだけでなく、循環参照も処理できます。循環参照は、2 つのオブジェクトが相互に参照しているが、他の変数がそれらを参照していない場合に発生します。この場合、参照カウントだけでは十分ではありません。 Python のガベージ コレクターは、実際には参照カウンターと循環ガベージ コレクターです。参照カウントに加えて、ガベージ コレクターは、大量に割り当てられたオブジェクト (および参照カウントによって破棄されていないオブジェクト) も調べます。 この場合、インタプリタは一時停止し、参照されていないループをクリーンアップしようとします。

Instance

Destructor __del__、__del__ は、オブジェクトが使用されなくなったときに呼び出されます。

a = 40      # 创建对象  <40>
b = a       # 增加引用, <40> 的计数
c = [b]     # 增加引用.  <40> 的计数

del a       # 减少引用 <40> 的计数
b = 100     # 减少引用 <40> 的计数
c[0] = -1   # 减少引用 <40> 的计数

上記の例の結果は次のとおりです。

#!/usr/bin/python
# -*- coding: UTF-8 -*-

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, "销毁"

pt1 = Point()
pt2 = pt1
pt3 = pt1
print id(pt1), id(pt2), id(pt3) # 打印对象的id
del pt1
del pt2
del pt3

注: 通常、クラスは別のファイルで定義する必要があります。

クラスの継承

オブジェクト指向プログラミングによってもたらされる主な利点の 1 つはコードの再利用であり、この再利用を実現する方法の 1 つは継承メカニズムを使用することです。 。継承は、クラス間のタイプとサブタイプの関係として完全に理解できます。

注意事項: 継承構文 class 派生クラス名 (基底クラス名): //... 基底クラス名は、クラス定義時にタプルに指定されます。の。

Python の継承のいくつかの機能:

  • 1: 継承では、基本クラスの構築 (__init__() メソッド) は自動的に呼び出されず、その派生クラスの構築で具体的に呼び出す必要があります。

  • 2: 基本クラスのメソッドを呼び出すときは、基本クラスのクラス名のプレフィックスを追加し、self パラメーター変数を渡す必要があります。クラス内で通常の関数を呼び出すのとは異なり、self パラメーターを渡す必要はありません

  • 3: Python は、派生クラスで対応するメソッドが見つからない場合、常に最初に対応する型のメソッドを検索します。基本クラスを 1 つずつ検索します。 (最初にこのクラスで呼び出しメソッドを探し、見つからない場合は基本クラスで探します)。

継承タプルに複数のクラスがリストされている場合、それを「多重継承」と呼びます。

構文:

派生クラスの宣言は、親クラスと同様に、以下に示すように、クラス名の後に継承された基本クラスのリストが続きます:

3083401324 3083401324 3083401324
Point 销毁

インスタンス:

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

上記のコードの実行結果は次のとおりです。

#!/usr/bin/python
# -*- coding: UTF-8 -*-

class Parent:        # 定义父类
   parentAttr = 100
   def __init__(self):
      print "调用父类构造函数"

   def parentMethod(self):
      print '调用父类方法'

   def setAttr(self, attr):
      Parent.parentAttr = attr

   def getAttr(self):
      print "父类属性 :", Parent.parentAttr

class Child(Parent): # 定义子类
   def __init__(self):
      print "调用子类构造方法"

   def childMethod(self):
      print '调用子类方法 child method'

c = Child()          # 实例化子类
c.childMethod()      # 调用子类的方法
c.parentMethod()     # 调用父类方法
c.setAttr(200)       # 再次调用父类的方法
c.getAttr()          # 再次调用父类的方法

複数のクラスを継承できます

调用子类构造方法
调用子类方法 child method
调用父类方法
父类属性 : 200

issubclass() または isinstance() メソッドを使用して検出できます。

  • issubclass() - クラスがサブクラスであるか、別のクラスの子孫であるかを判断するブール関数。構文: issubclass(sub,sup)

  • isinstance(obj, Class) ブール関数 (obj が Class クラスの場合)インスタンス オブジェクトまたは Class サブクラスのインスタンス オブジェクトに対して true を返します。


メソッドの書き換え

親クラスのメソッドの機能がニーズを満たせない場合は、サブクラスで親クラスのメソッドを書き換えることができます:

インスタンス:

class A:        # 定义类 A
.....

class B:         # 定义类 B
.....

class C(A, B):   # 继承类 A 和 B
.....

上記のコードを実行した出力結果は次のとおりです:

#!/usr/bin/python
# -*- coding: UTF-8 -*-

class Parent:        # 定义父类
   def myMethod(self):
      print '调用父类方法'

class Child(Parent): # 定义子类
   def myMethod(self):
      print '调用子类方法'

c = Child()          # 子类实例
c.myMethod()         # 子类调用重写方法

基本的なオーバーロードされたメソッド

次の表は、独自のクラスでオーバーライドできるいくつかの一般的な関数をリストしています:

4 オブジェクトの比較
シリアル番号メソッド、説明、簡単な呼び出し
1 __init__ ( self [,args...] )
Constructor
単純なメソッド呼び出し: obj = className(args)
2__del__( self )
Destructorメソッド、オブジェクトの削除
単純な呼び出しメソッド: dell obj
3__repr__( self )
インタプリタが読み取れる形式に変換
単純な呼び出しメソッド: repr(obj)
簡単な呼び出しメソッド: cmp(obj, x)


演算子のオーバーロード

Python は演算子のオーバーロードもサポートしています。例は次のとおりです:

调用子类方法

上記のコードの実行結果は次のとおりです:

#!/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

クラスの属性とメソッド

クラスのプライベート属性

__private_attrs: 2 つのアンダースコアで始まり、プロパティをプライベートとして宣言し、クラス外で使用したり直接アクセスしたりすることはできません。クラス self.__private_attrs 内のメソッドで使用される場合。

クラスのメソッド

クラス内では、defキーワードを使用してクラスのメソッドを定義できます。一般的な関数定義とは異なり、クラスメソッドにはパラメータselfが含まれている必要があり、それが最初のパラメータです

。クラスのメソッド

__private_method: 2 つのアンダースコアで始まるメソッドはプライベート メソッドとして宣言され、クラス外から呼び出すことはできません。クラス名を含むように名前を変更して、クラス内で

Vector(7,8)
Python の

self.__private_methods

インスタンスを呼び出す:

#!/usr/bin/python
# -*- coding: UTF-8 -*-

class JustCounter:
	__secretCount = 0  # 私有变量
	publicCount = 0    # 公开变量

	def count(self):
		self.__secretCount += 1
		self.publicCount += 1
		print self.__secretCount

counter = JustCounter()
counter.count()
counter.count()
print counter.publicCount
print counter.__secretCount  # 报错,实例不能访问私有变量

Python では、インスタンス化されたクラスがプライベート データにアクセスすることはできませんが、object を使用して属性にアクセスできます。 _className__attrName 、上記のコードの最後の行を次のコードに置き換えます:

1
2
2
Traceback (most recent call last):
  File "test.py", line 17, in <module>
    print counter.__secretCount  # 报错,实例不能访问私有变量
AttributeError: JustCounter instance has no attribute '__secretCount'

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

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