Object-oriented-python-building-blocks
オブジェクト指向Python-ビルディングブロック
この章では、オブジェクト指向の用語とプログラミングの概念について詳しく説明します。クラスはインスタンスの単なるファクトリです。 このファクトリには、インスタンスの作成方法を説明する設計図が含まれています。 インスタンスまたはオブジェクトは、クラスから構築されます。 ほとんどの場合、1つのクラスのインスタンスを複数持つことができます。 すべてのインスタンスには属性のセットがあり、これらの属性はクラスで定義されるため、特定のクラスのすべてのインスタンスは同じ属性を持つことが期待されます。
クラスバンドル:動作と状態
クラスを使用すると、オブジェクトの動作と状態をまとめることができます。 より良い理解のために次の図を観察してください-
クラスバンドルを議論するとき、次の点は注目に値する-
- *動作*という言葉は*機能*と同じです–それは何かをする(または動作を実装する)コードの一部です
- state という単語は variables と同じです。クラス内の値を保存する場所です。
- クラスの動作と状態を一緒にアサートすると、クラスが関数と変数をパッケージ化することを意味します。
クラスにはメソッドと属性があります
Pythonでは、メソッドを作成するとクラスの動作が定義されます。 メソッドという語は、クラス内で定義される関数に与えられるOOP名です。 まとめると-
- クラス関数-メソッドの同義語です
- クラス変数-名前属性の同義語です
- クラス-正確な動作を持つインスタンスの青写真。
- Object -クラスのインスタンスの1つで、クラスで定義された機能を実行します。
- タイプ-インスタンスが属するクラスを示します
- 属性-任意のオブジェクト値:object.attribute
- メソッド-クラスで定義された「呼び出し可能な属性」
たとえば、次のコードの一部を観察します-
var = “Hello, John”
print( type (var)) # ‘str’> or <class 'str'>
print(var.upper()) # upper() method is called, HELLO, JOHN
作成とインスタンス化
次のコードは、最初のクラスを作成してからそのインスタンスを作成する方法を示しています。
class MyClass(object):
pass
# Create first instance of MyClass
this_obj = MyClass()
print(this_obj)
# Another instance of MyClass
that_obj = MyClass()
print (that_obj)
ここでは、 MyClass というクラスを作成しましたが、これはタスクを実行しません。 MyClass クラスの引数 object にはクラスの継承が含まれ、後の章で説明します。 上記のコードの pass は、このブロックが空、つまり空のクラス定義であることを示しています。
- MyClass()クラスのインスタンス *this_obj を作成し、次のように出力します。
<__main__.MyClass object at 0x03B08E10>
<__main__.MyClass object at 0x0369D390>
ここでは、* MyClass。*のインスタンスを作成しました。16進コードは、オブジェクトが保存されているアドレスを参照します。 別のインスタンスが別のアドレスを指している。
ここで、クラス* MyClass()*内に1つの変数を定義し、次のコードに示すように、そのクラスのインスタンスから変数を取得しましょう-
class MyClass(object):
var = 9
# Create first instance of MyClass
this_obj = MyClass()
print(this_obj.var)
# Another instance of MyClass
that_obj = MyClass()
print (that_obj.var)
出力
上記のコードを実行すると、次の出力を確認できます-
9
9
インスタンスはインスタンス化されるクラスを知っているため、インスタンスの属性を要求すると、インスタンスは属性とクラスを探します。 これは*属性ルックアップ*と呼ばれます。
インスタンスメソッド
クラスで定義された関数は method と呼ばれます。インスタンスメソッドは、呼び出すためにインスタンスを必要とし、デコレータを必要としません。 インスタンスメソッドを作成する場合、最初のパラメーターは常に* self。*です。他の名前で(self)を呼び出すこともできますが、命名規則なのでselfを使用することをお勧めします。
class MyClass(object):
var = 9
def firstM(self):
print("hello, World")
obj = MyClass()
print(obj.var)
obj.firstM()
出力
上記のコードを実行すると、次の出力を確認できます-
9
hello, World
上記のプログラムでは、引数としてselfを使用してメソッドを定義していることに注意してください。 ただし、メソッドに引数を宣言していないため、メソッドを呼び出すことはできません。
class MyClass(object):
def firstM(self):
print("hello, World")
print(self)
obj = MyClass()
obj.firstM()
print(obj)
出力
上記のコードを実行すると、次の出力を確認できます-
hello, World
<__main__.MyClass object at 0x036A8E10>
<__main__.MyClass object at 0x036A8E10>
カプセル化
カプセル化は、OOPの基本の1つです。 OOPを使用すると、オブジェクトの内部作業の複雑さを隠すことができます。これは、次の方法で開発者に有利です-
- 内部を知らなくてもオブジェクトを使用することを単純化し、理解しやすくします。
- 変更は簡単に管理できます。
オブジェクト指向プログラミングは、カプセル化に大きく依存しています。 カプセル化と抽象化(データ隠蔽とも呼ばれます)という用語は、同義語としてよく使用されます。 カプセル化によって抽象化が実現されるため、これらはほぼ同義語です。
カプセル化は、オブジェクトの一部のコンポーネントへのアクセスを制限するメカニズムを提供します。これは、オブジェクトの内部表現がオブジェクト定義の外部から見えないことを意味します。 このデータへのアクセスは通常、 Getters および Setters という特別な方法で実現されます。
このデータはインスタンス属性に保存され、クラス外のどこからでも操作できます。 セキュリティで保護するには、インスタンスメソッドを使用してのみそのデータにアクセスする必要があります。 直接アクセスを許可しないでください。
class MyClass(object):
def setAge(self, num):
self.age = num
def getAge(self):
return self.age
zack = MyClass()
zack.setAge(45)
print(zack.getAge())
zack.setAge("Fourty Five")
print(zack.getAge())
出力
上記のコードを実行すると、次の出力を確認できます-
45
Fourty Five
データは、例外処理構造を使用して、正しく有効な場合にのみ保存する必要があります。 上記のように、setAge()メソッドへのユーザー入力に制限はありません。 文字列、数字、リストのいずれかです。 そのため、上記のコードをチェックして、保存されていることを確認する必要があります。
class MyClass(object):
def setAge(self, num):
self.age = num
def getAge(self):
return self.age
zack = MyClass()
zack.setAge(45)
print(zack.getAge())
zack.setAge("Fourty Five")
print(zack.getAge())
Initコンストラクター
initメソッドは、クラスのオブジェクトがインスタンス化されるとすぐに暗黙的に呼び出されます。これにより、オブジェクトが初期化されます。
x = MyClass()
上記のコード行は、新しいインスタンスを作成し、このオブジェクトをローカル変数xに割り当てます。
インスタンス化操作、つまり*クラスオブジェクトの呼び出し*は、空のオブジェクトを作成します。 多くのクラスは、特定の初期状態にカスタマイズされたインスタンスを持つオブジェクトを作成するのが好きです。 したがって、クラスは、示されているように「init()」という名前の特別なメソッドを定義できます-
def __init__(self):
self.data = []
Pythonは、インスタンス化中にinitを呼び出して、クラスのインスタンス化時に発生する追加属性を定義します。この属性は、オブジェクトの開始値を設定したり、インスタンス化に必要なルーチンを実行したりします。 したがって、この例では、新しい初期化されたインスタンスを取得することができます-
x = MyClass()
init()メソッドは、柔軟性を高めるために単一または複数の引数を持つことができます。 initは、インスタンスの属性を初期化するため、初期化の略です。 クラスのコンストラクターと呼ばれます。
class myclass(object):
def __init__(self,aaa, bbb):
self.a = aaa
self.b = bbb
x = myclass(4.5, 3)
print(x.a, x.b)
出力
4.5 3
クラス属性
クラスで定義された属性は「クラス属性」と呼ばれ、関数で定義された属性は「インスタンス属性」と呼ばれます。 これらの属性はクラスのプロパティであり、特定のインスタンスのプロパティではないため、定義中、これらの属性にはselfのプレフィックスが付きません。
クラスの属性(className.attributeName)およびクラスのインスタンス(inst.attributeName)からクラス属性にアクセスできます。 そのため、インスタンスは、インスタンス属性とクラス属性の両方にアクセスできます。
>>> class myclass():
age = 21
>>> myclass.age
21
>>> x = myclass()
>>> x.age
21
>>>
クラス属性は、カプセル化を解除するのに適したメソッドではありませんが、インスタンス内でオーバーライドできます。
Pythonには属性のルックアップパスがあります。 最初はクラス内で定義されたメソッドであり、次にその上のクラスです。
>>> class myclass(object):
classy = 'class value'
>>> dd = myclass()
>>> print (dd.classy) # This should return the string 'class value'
class value
>>>
>>> dd.classy = "Instance Value"
>>> print(dd.classy) # Return the string "Instance Value"
Instance Value
>>>
>>> # This will delete the value set for 'dd.classy' in the instance.
>>> del dd.classy
>>> >>> # Since the overriding attribute was deleted, this will print 'class
value'.
>>> print(dd.classy)
class value
>>>
インスタンスddの「classy」クラス属性をオーバーライドしています。 オーバーライドされると、Pythonインタープリターはオーバーライドされた値を読み取ります。 しかし、新しい値が「del」で削除されると、オーバーライドされた値はインスタンスに存在しなくなるため、ルックアップは上記のレベルを超えてクラスから取得します。
クラスおよびインスタンスデータの操作
このセクションでは、クラスデータがインスタンスデータにどのように関連するかを理解しましょう。 クラスまたはインスタンスにデータを保存できます。 クラスを設計するとき、どのデータがインスタンスに属し、どのデータをクラス全体に格納するかを決定します。
インスタンスはクラスデータにアクセスできます。 複数のインスタンスを作成した場合、これらのインスタンスは個々の属性値とクラスデータ全体にアクセスできます。
したがって、クラスデータは、すべてのインスタンス間で共有されるデータです。 より良いアンダーサンディングのために以下のコードを観察してください-
class InstanceCounter(object):
count = 0 # class attribute, will be accessible to all instances
def __init__(self, val):
self.val = val
InstanceCounter.count +=1 # Increment the value of class attribute, accessible through class name
# In above line, class ('InstanceCounter') act as an object
def set_val(self, newval):
self.val = newval
def get_val(self):
return self.val
def get_count(self):
return InstanceCounter.count
a = InstanceCounter(9)
b = InstanceCounter(18)
c = InstanceCounter(27)
for obj in (a, b, c):
print ('val of obj: %s' %(obj.get_val())) # Initialized value ( 9, 18, 27)
print ('count: %s' %(obj.get_count())) # always 3
出力
val of obj: 9
count: 3
val of obj: 18
count: 3
val of obj: 27
count: 3
つまり、クラス属性はクラスのすべてのインスタンスで同じですが、インスタンス属性は各インスタンスに固有です。 2つの異なるインスタンスに対して、2つの異なるインスタンス属性があります。
class myClass:
class_attribute = 99
def class_method(self):
self.instance_attribute = 'I am instance attribute'
print (myClass.__dict__)
出力
上記のコードを実行すると、次の出力を確認できます-
{'__module__': '__main__', 'class_attribute': 99, 'class_method': , '__dict__': , '__weakref__': , '__doc__': None}
インスタンス属性 myClass .dict のように-
>>> a = myClass()
>>> a.class_method()
>>> print(a.__dict__)
{'instance_attribute': 'I am instance attribute'}