流暢的Python 第9章筆記 物件

2021-09-07 19:08:36 字數 4155 閱讀 3416

以乙個二元素向量物件為例

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)

<1.41421, 0.78540>

但是乙個重要的方法還是沒能實現,__hash__,這關乎到物件是否可以被存入字典進行高速讀取的屬性,實際上可以hash物件需要三個條件:

需要__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"))

print(demo.statmeth("hello"))

demo = demo()

print(demo.normal("hello"))

# (, 'hello')

# ('hello',)

# (<__main__.demo object at 0x000000000289f978>, 'hello')

兩個前導下劃線"__",乙個或者沒有後置下劃線的例項屬性(self.屬性名)為私有變數,會被存入__dict__中,且名稱被改寫為"_類名__屬性名",主要目的是防止類被繼承以後,子類例項的繼承屬性(未在子類中顯式的宣告)被錯誤的改寫。

注意,__dict__不僅僅儲存私有變數,例項屬性均存放在__dict__中(預設情況下)。

class

vector2d:

__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)

這部分的內容你在寫程式的時候肯定是處處都能用到的,而且會讓你的程式很簡潔。本章其實是第三章內容的拓展,詳細地介紹了標準庫順序容器的知識。乙個容器就是一些 特定同一型別 物件的集合。順序容器為程式設計師提供了控制元素儲存和訪問順序的能力。這種順序不依賴於元素的值,而是與元素加入容器時的位置相對應。所有...