以乙個二元素向量物件為例
import math
from array import array
class vector2d:
typecode = 'd'
def __init__(self, x, y):
self.x = float(x)
self.y = float(y)
def __iter__(self):
# 使得vector2d變成可迭代物件
# __iter__方法的實現使得本類可以被轉化為tuple在內的其他可迭代類
return (i for i in (self.x, self.y))
def __repr__(self):
class_name = type(self).__name__ # type(self): return '{}(,)'.format(class_name, *self)
def __str__(self):
return str(tuple(self))
def __eq__(self, other):
return tuple(self) == tuple(other)
def __abs__(self):
return math.hypot(self.x, self.y)
def __bool__(self):
return bool(abs(self))
def __bytes__(self):
"""將vector2d物件處理為二進位制序列,格式我們自定"""
# d:double型別陣列
return (bytes([ord(self.typecode)]) +
bytes(array(self.typecode, self)))
# —————備用析構方法——————
@classmethod # 類方法,cls表示類本身
def frombytes(cls, octets):
"""對應於上面的方法,這裡建立乙個新的析構函式,使用特定的二進位制序列構造vector2d類例項"""
typecode = chr(octets[0])
memv = memoryview(octets[1:]).cast(typecode)
return cls(*memv) # 類名(引數),可見,類方法常用作備用析構
# —格式化輸出—
def angle(self):
# math.atan(scope)輸入為tan值
# math.atan2(y, x)輸入為對應向量座標(起點為原點)
return math.atan2(self.y, self.x)
def __format__(self, fmt_spec=''):
"""格式化輸出,如果格式末尾為p則輸出極座標,
輸入其他格式為數字型格式,乙個輸入格式指定到兩個數上,如:.3ep"""
if fmt_spec.endswith('p'):
fmt_spec = fmt_spec[:-1]
coords = (abs(self), self.angle())
out_fmt = '<{}, {}>'
else:
coords = self
out_fmt = '({}, {})'
components = (format(c, fmt_spec) for c in coords)
return out_fmt.format(*components)
此時這個物件支援大部分python操作,
if __name__ == '__main__':
b = bytes(vector2d(3, 4))
print(vector2d.frombytes(b))
print(format(vector2d(1, 1), '.5fp'))
(3.0, 4.0)但是乙個重要的方法還是沒能實現,__hash__,這關乎到物件是否可以被存入字典進行高速讀取的屬性,實際上可以hash物件需要三個條件:<1.41421, 0.78540>
需要__hash__方法
需要__eq__方法(已經實現)
需要物件不可變 # 例項的雜湊值關乎查詢等使用方式,絕對不可以變化
也就是我們指定v.x=1(v為class例項)會報錯才行,這需要一些其他操作:
class vector2d:
typecode = 'd'
def __init__(self, x, y):
self.__x = float(x)
self.__y = float(y)
@property
def x(self):
return self.__x
@property
def y(self):
return self.__y
def __hash__(self):
return hash(self.x) ^ hash(self.y)
其他方法不需要修改,
v1 = vector2d(3, 4)v2 = vector2d(3.1, 4.2)
print(hash(v1), hash(v2))
# 7 384307168202284039
# —對比類方法和靜態方法—
class demo:
@classmethod
def klassmeth(*args):
return args
@ staticmethod
def statmeth(*args):
return args
def normal(*args):
return args
和例項方法不同,類方法第乙個引數永遠是類本身,所以常用於備用析構,靜態方法沒有預設的首位引數,測試如下:
print(demo.klassmeth("hello"))兩個前導下劃線"__",乙個或者沒有後置下劃線的例項屬性(self.屬性名)為私有變數,會被存入__dict__中,且名稱被改寫為"_類名__屬性名",主要目的是防止類被繼承以後,子類例項的繼承屬性(未在子類中顯式的宣告)被錯誤的改寫。print(demo.statmeth("hello"))
demo = demo()
print(demo.normal("hello"))
# (, 'hello')
# ('hello',)
# (<__main__.demo object at 0x000000000289f978>, 'hello')
注意,__dict__不僅僅儲存私有變數,例項屬性均存放在__dict__中(預設情況下)。
classvector2d:
__slots__ = ('
__x', '
__y'
) typecode = '
d'
類屬性__slots__為乙個儲存字串的可迭代物件,其中的各個字串是不同的例項屬性名,使用tuple是作者推薦的方式,因為可以保證資訊不被改動。使用它可以有效節約儲存空間,尤其是需要建立大量例項的時候(執行速度往往也更快)。
繼承會自動忽略__slot__屬性,所以子類需要顯式的定義它
定義了__slots__後,使用者不可以自行新增其他例項屬性,但是如果把__dict__儲存在__slots__中,就可以新增了,不過就完全沒意義了……
如果想要支援弱引用,需要手動將__weakref__新增進來,雖然自定義class預設存在__weakref__屬性,但是想要讓例項成為弱引用目標還是需要新增進來才可以。
例項呼叫的例項屬性時,如果屬性不存在,會去讀取同名的類屬性(例子中的typecode類屬性被self.typecode呼叫)
例項新建例項屬性時,如果已經存在同名的類屬性,不會改寫類屬性,而會對例項新建乙個例項屬性
C Primer 第9章筆記
9.1 順序容器概述 順序容器型別 forward list沒有size操作。9.2 容器庫概覽 一般來說,每個容器都定義在乙個與型別名相同的標頭檔案中,容器均定義為模板類。對容器可以儲存的元素型別的限制 如沒有預設建構函式的物件。容器操作 型別別名 建構函式 賦值與swap 大小 新增 刪除元素 ...
第9章 轉移指令的原理 筆記
p175 可以修改ip,或同事修改cs和ip的指令統稱為轉移指令。概括地講,轉移指令就是可以控制cpu執行記憶體中某處 的指令。8086cpu的轉移行為有以下幾類 只修改ip時,稱為段內轉移,比如 jmp ax 同時修改cs和ip時,稱為段間轉移,比如 jmp 1000 0 由於轉移指令對ip的修改...
C primer 學習筆記 第9章(1)
這部分的內容你在寫程式的時候肯定是處處都能用到的,而且會讓你的程式很簡潔。本章其實是第三章內容的拓展,詳細地介紹了標準庫順序容器的知識。乙個容器就是一些 特定同一型別 物件的集合。順序容器為程式設計師提供了控制元素儲存和訪問順序的能力。這種順序不依賴於元素的值,而是與元素加入容器時的位置相對應。所有...