摘要:自定義向量類型從自定義向量類型入手寫出符合風格的對象,這離不開特殊方法的支持。將對象定為不可變的通過使用兩個前導下劃線。程序員約定使用一個下劃線前綴編寫受保護的屬性即,他們認為應該使用命名約定來避免意外覆蓋屬性。
導語:本文章記錄了本人在學習Python基礎之面向對象篇的重點知識及個人心得,打算入門Python的朋友們可以來一起學習并交流。
本文重點:
1、掌握編寫Pythonic code背后常用的特殊方法;一、自定義具有Python風格的類
2、掌握可擴展的格式化輸出方法;
3、了解可散列對象的設置以及節省內存的__slots__對象。
自定義的向量類需要支持基本的輸出,迭代,求模。
1、自定義向量類型從自定義向量類型入手寫出符合Python風格的對象,這離不開特殊方法的支持。
我們期望的自定義向量類型應支持的基本功能:
構造,__init__
輸出,__repr__和__str__
迭代,__iter__
求模,__abs__
轉化為字節序列,__bytes__
代碼實現如下:
import math from array import array class Vector2d: typecode="d" def __init__(self,x,y): self.x=float(x) self.y=float(y) def __str__(self): return str(tuple(self)) def __iter__(self): return (i for i in (self.x,self.y)) def __repr__(self): classname=type(self).__name__ s="{}({},{})".format(classname,*self) return s def __abs__(self): return math.hypot(self.x,self.y) def __bytes__(self): return (bytes(self.typecode,encoding="utf-8")+ bytes(array(self.typecode,self)))2、使用一個類方法實現備選構造方法
我們能將實例轉化為字節序列,那么也應構造一個將實例轉化為字節序列的方法。
@classmethod def frombytes(cls,seqs): typecode=chr(seqs[0]) memv=memoryview(seqs[1:]).cast(typecode) return cls(*memv)
memoryview是泛化和去數學化的數組。
3、classmethod和staticmethod兩個裝飾器classmethod:定義操作類而不是操作實例的方法,類方法的第一個參數是類本身而不是實例。最常見的用途是定義備選構造方法(返回cls(*))
staticmethod:是普通的函數,只是碰巧在類的定義體中,而不是在模塊層定義。
二、格式化顯示 1、擴展內置的format函數通過改寫format背后的__format__可以寫出可擴展的格式。
實例1:實現format對向量類的處理
def __format__(self,fmt_spec=""): components=(format(v,fmt_spec)for v in self) return "({},{})".format(*components)
實例2:通過尾部自定義格式代碼p實現將直角坐標向量轉化為極坐標向量。
def __format__(self,fmt_spec=""): if fmt_spec[-1]=="p": coord=(abs(self),self.angle()) spec=fmt_spec[:-1] components=(format(v,spec)for v in coord) outer="<{},{}>" else: coord=self components = (format(v, fmt_spec) for v in self) outer = "({},{})" return outer.format(*components)
本段代碼的重點在于判斷格式中是否存在自定義格式符p,并進行對應的格式處理。
三、將對象變為可散列的目前的向量是不可散列的,而可散列對象需要滿足:
(1)支持hash()函數,并且通過hash()得到的散列值是不變的; (2)支持通過__eq__()方法來檢測相等性; (3)若a==b為真,則hash(a)=hash(b)也為真。
所以我們需要把對象定為不可變,然后自定義__hash__。
1、將對象定為不可變的通過使用兩個前導下劃線。將屬性標記為私有的。
@property def x(self): return self.__x @property def y(self): return self.__y2、自定義__hash__()
使用異或運算符實現。
def __hash__(self): return hash(self.x)^hash(self.y)四、其它 1、只讀屬性的設置
私有屬性的設置只是避免修改方法意外訪問不應更改的值,而無法防止有意的改動。
通過__dict__屬性可以查詢Python如何存儲向量的屬性名,然后只要編寫a._Vector2d__x=5這樣的代碼就會惡意賦值。
Python程序員約定使用一個下劃線前綴編寫“受保護”的屬性即self._x,他們認為應該使用命名約定來避免意外覆蓋屬性。
2、利用__slots__節省內存默認情況下,Python在各個實例中名為__dict__的字典中儲存實例屬性,相應地會消耗大量內存。
通過__slots__類屬性,并讓解釋器把實例屬性存儲在元組中,可以節省大量內存。
class Vector2d: __slots__ = ("__x","__y") typecode="d" #其他方法實現省略
使用__slots__應注意的問題:
__slots__無法從超類繼承而來,每個子類都需要定義__slots__屬性;
實例只能擁有__slots__中列出的屬性,除非把"__dict__"加入到__slots__中(這樣做就失去了節省內存的初衷)
如果不把"weakref__"加入__slots__,實例就不能作為弱引用的目標。
當處理的實例規模較小時,禁止創建動態屬性或不支持弱引用是比較好的選擇。
3、覆蓋類屬性通過創建子類可以把繼承自父類的實例屬性覆蓋掉。
class Shortvector2d(Vector2d): typecode = "f" #其它方法實現省略
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/41262.html
摘要:如果需要在二元運算符周圍做換行操作,例如和,那么需要將換行操作放在前面,這條規則源于數學,數學家同意在二元運算符之前換行以可提高可讀性,比較以下兩個例子。在二元運算符之前換行可以讓代碼更加具有可讀性,所鼓勵這種方式。 原文地址:How to Write Beautiful Python Code With PEP 8 作者:Jasmine Finer 翻譯:howie6879 ...
摘要:本篇繼續學習之路,實現更多的特殊方法以讓自定義類的行為跟真正的對象一樣。之所以要讓向量不可變,是因為我們在計算向量的哈希值時需要用到和的哈希值,如果這兩個值可變,那向量的哈希值就能隨時變化,這將不是一個可散列的對象。 《流暢的Python》筆記。本篇是面向對象慣用方法的第二篇。前一篇講的是內置對象的結構和行為,本篇則是自定義對象。本篇繼續Python學習之路20,實現更多的特殊方法以讓...
摘要:以便于用戶理解的方式返回對象的字符串表示形式。函數會調用函數,對來說,輸出的是一個有序對。此外,還有用于支持內置的構造函數的方法。可散列實現了方法,使用推薦的異或運算符計算實例屬性的散列值私有屬性最好用命名規則來實現這種方式有好有壞 絕對不要使用兩個前導下劃線,這是很煩人的自私行為。——Ian Bicking 對象表示形式 repr() 以便于開發者理解的方式返回對象的字符串表示形式...
摘要:一基本的序列協議首先,需要就維向量和二維向量的顯示模的計算等差異重新調整。假設維向量最多能處理維向量,訪問向量分量的代碼實現如下若傳入的參數在備選分量中可進行后續處理判斷分量的位置索引是否超出實例的邊界不支持非法的分量訪問,拋出。 導語:本文章記錄了本人在學習Python基礎之面向對象篇的重點知識及個人心得,打算入門Python的朋友們可以來一起學習并交流。 本文重點: 1、了解協議的...
摘要:函數建立函數在中,規定了一種定義函數的格式,下面的舉例就是一個函數,以這個函數為例來說明定義函數的格式和調用函數的方法。返回值所謂返回值,就是函數向調用函數的地方返回的數據。 函數 建立函數 在Python中,規定了一種定義函數的格式,下面的舉例就是一個函數,以這個函數為例來說明定義函數的格式和調用函數的方法。 def add_function(a, b): #冒號必須 c = ...
閱讀 3199·2021-09-29 09:34
閱讀 3551·2021-09-10 10:51
閱讀 1948·2021-09-10 10:50
閱讀 6731·2021-08-12 13:31
閱讀 3000·2019-08-30 15:54
閱讀 1560·2019-08-30 15:44
閱讀 1430·2019-08-29 12:26
閱讀 2654·2019-08-26 18:36