class Point:
'''This is a doc string'''
# 不需要 new 關鍵字
p = Point()
print(p) # <__main__.Point object at 0x01C5BD70>
print(p.__doc__) # This is a doc string
# 動態建立欄位
p.x = 3
p.y = 4
print('(%d, %d)' % (p.x, p.y)) # (3, 4)
import math
print(math.sqrt(p.x**2 + p.y**2)) # 5.0
__init__() 與 __str__()
當然也可以預先定義屬性(API),這裡的__init__() 就是 Java 的 constructor,並定義 __str__() 回傳的字串,也就是 Java 裡的 toString()。class Point:
'''This is a doc string'''
def __init__(self, x=0, y=0): # 可以給預設值,也可以不要
self.x = x
self.y = y
def __str__(self):
return 'Point (%d, %d)' % (self.x, self.y)
p = Point() # 使用預設值
print(p) # Point (0, 0)
p.x = 3
p.y = 4
print(p) # Point (3, 4)
print(Point(1, 2)) # Point (1, 2) 使用自訂值
物件特徵
和 Java 一樣,Python 物也是 pass by reference 與 mutable。class Point:
'''This is a doc string'''
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __str__(self):
return 'Point (%d, %d)' % (self.x, self.y)
p = Point()
# print(p.z) # 存取未定義的屬性會得到 AttributeError
print(hasattr(p, 'x')) # True
print(hasattr(p, 'z')) # False
# try-except
try:
z = p.z
except AttributeError:
z = 0
print(z) # 0
# 型別檢查
print(type(p)) # <class '__main__.Point'>
print(isinstance(p, Point)) # True
克隆
class Point:
'''This is a doc string'''
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __str__(self):
return 'Point (%d, %d)' % (self.x, self.y)
p = Point()
p2 = p
print(p is p2) # True
print(p == p2) # True
p.x = 5
print(p2) # Point (5, 0)
import copy
p3 = copy.copy(p) # 淺層複製
print(p is p3) # False,已經是不同物件(reference)
print(p == p3) # False,理論上應該是 True,但自訂物件預設的 == 是 is
p3.y = 10
print(p) # Point (5, 0)
print(p2) # Point (5, 0)
print(p3) # Point (5, 10)
p4 = copy.deepcopy(p) # 深層克隆
__eq__() 與 ==
透過自訂 __eq__() 來實做 == 的行為。class Point:
'''This is a doc string'''
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __str__(self):
return 'Point (%d, %d)' % (self.x, self.y)
def __eq__(self, other):
return (self.x, self.y) == (other.x, other.y)
p = Point()
import copy
p3 = copy.copy(p)
print(p is p3) # False
print(p == p3) # True,透過自訂 __eq__() 來實做 == 的行為,取代預設的 is
Class and instance attributes
class Point:
'''This is a doc string'''
original = 0 # class attribute
def __init__(self, x=0, y=0):
self.x = x # instance attributes
self.y = y
def __str__(self):
return 'Point (%d, %d)' % (self.x, self.y)
p = Point(3, 4)
print(p) # Point (3, 4)
print(Point.original)
Static and instance method
在 Python,method 可以同時是 static 與 instance。class Point:
'''This is a doc string'''
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __str__(self):
return 'Point (%d, %d)' % (self.x, self.y)
def print(self):
return self.__str__()
p = Point(3, 4)
print(Point.print(p)) # Point (3, 4) static 呼叫
print(p.print()) # Point (3, 4) instance 呼叫
運算子重載 Operator overloading
只要 class 定義了 __add__(),就可以對 object 使用 +。class Point:
'''This is a doc string'''
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __str__(self):
return 'Point (%d, %d)' % (self.x, self.y)
def __add__(self, other):
return Point(self.x + other.x, self.y + other.y)
p1 = Point(3, 4)
p2 = Point(2, 1)
print(p1) # Point (3, 4)
print(p2) # Point (2, 1)
print(p1 + p2) # Point (5, 5)
還有其他運算子重載可以定義(__sub__、__mul__、__mod__等),當然前提是情境必須「合適」。上面的重載是算術運算子,也可以重載比較運算子,前提也是情境必須「合適」。
甚至可以針對不同型別進行運算。
class Point:
'''This is a doc string'''
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __str__(self):
return 'Point (%d, %d)' % (self.x, self.y)
def __add__(self, other):
if isinstance(other, Point):
return Point(self.x + other.x, self.y + other.y)
else:
return Point(self.x + other, self.y)
def __radd__(self, other):
return Point(self.x, self.y + other)
p1 = Point(3, 4)
p2 = Point(2, 1)
print(p1) # Point (3, 4)
print(p2) # Point (2, 1)
print(p1 + p2) # Point (5, 5) 呼叫 __add__
print(p1 + 3) # Point (6, 4) 呼叫 __add__
print(5 + p1) # Point (3, 9) 呼叫 __radd__
甚至只要 class 定義了 __add__(),也就是支援 +,其他使用 + 的函式都可以用了,例如 sum()。print(sum([Point(1, 2), Point(2, 3), Point(3, 4)])) # Point (6, 9)
繼承
目前只知道 method 有繼承下來,但 attribute 沒有,也不知道可不可以存取 super class 的 attribute。class Point3D(Point):
def __init__(self, x=0, y=0, z=0):
self.x = x
self.y = y
self.z = z
p2 = Point3D(3, 4, 5)
print(p2) # Point (3, 4)
Debug or Reflection
可以使用 vars()、getattr() 與 setattr() 檢視或操作物件屬性。p = Point(3, 4)
print(vars(p)) #{'x': 3, 'y': 4} dict of attributes and values
print(getattr(p, 'x')) # 3
setattr(p, 'x', 5)
print(getattr(p, 'x')) # 5
------
---
沒有留言:
張貼留言