Python(オブジェクト指向)
class A:
pass
a=A()
isinstance(a,A)
isinstance(a,int)
a.x=1
a.x += 10
a.b=10
Pythonでクラス定義を行う場合、クラス名は大文字から書くようにしましょう。
上記では空のAというクラスを定義し、それをクラス変数aに代入することでアクセスしています。
クラスはintやfloatと同じように新たな型として判別可能になるのでisinstance()で真偽値を確認することができます。
また、グローバル変数と同様にPythonではクラス内に変数を容易に追加してアクセスすることができるようになりますが、カプセル化されておらず、エラーの元にもなりやすいので、基本的にクラス内の変数を直接書き換えることはしないようにしましょう。
class B:
#name = "default"
def __init__(self,name="default"):
self.name = name
print("initialized!",self.name)
def set_name(self,name):
self.name = name
def get_name(self):
return f"My name is {self.name}"
B()
b=B("James")
b.get_name()
__init__(self,name="default")はコンストラクタと呼ばれる、クラスが呼び出されたと同時に初期化、生成されるものを定義したメソッドになります。
また、クラス内変数は直接書き換えるのではなく、set、getのように内部関数からアクセスすることで他からは変更することができない安全なものとして扱うことができます(カプセル化)
# 非オブジェクト指向
_stack = []
def push(x):
_stack.append(x)
def pop():
return _stack.pop()
def clear_stack():
_stack.clear()
def stack_depth():
return len(_stack)
# オブジェクト指向的アプローチ
class Stack:
def __init__(self):
self._stack = []
def push(self,x):
self._stack.append(x)
def pop(self):
return self._stack.pop()
def clear(self):
self._stack.clear()
def depth(self):
return len(self._stack)
# 間違った設計のオブジェクト指向的アプローチ
class WrongStack:
_stack = [] # このリストがすべてのインスタンスで共有されてしまう
def push(self,x):
self._stack.append(x)
def pop(self):
return self._stack.pop()
def clear(self):
self._stack.clear()
def depth(self):
return len(self._stack)
def test(stk1,stk2):
stk1.push("stk1-1")
stk2.push("stk2-1")
stk1.push("stk1-2")
stk1.push("stk1-3")
stk2.push("stk2-2")
print("stk1.depth() is",stk1.depth())
print("stk2.depth() is",stk2.depth())
print("stk1.pop() --->",stk1.pop())
print("stk1.pop() --->",stk1.pop())
print("stk1.pop() --->",stk1.pop())
print("stk2.pop() --->",stk2.pop())
print("stk2.pop() --->",stk2.pop())
test(Stack(),Stack())
test(WrongStack(),WrongStack())
では、逆ポーランド記法で利用していたスタックをオブジェクト指向的アプローチでクラス定義すると上記のようになりますが、間違った設計をした場合、複数のクラス変数を定義するとクラス内変数が共有されてしまい、同様のクラスから生成されたものからアクセスすると思っていた挙動とは違う働きをしてしまう場合があるので、クラス内変数はコンストラクタ内で定義するようにしましょう。