Python面向對象之魔術方法

  娜米與戀愛小秘書們最近整理了一套Python學習教程,有需要的小夥伴,記得關註娜米與戀愛小秘書們頭條號,私信【學習】即可免費領取一套Python學習教程哦

  __str__

  改變對象的字符串顯示。可以理解為使用print函數列印一個對象時,會自動調用對象的__str__方法

  class Student: def __init__(self, name, age): self.name = name self.age = age # 定義對象的字符串表示 def __str__(self): return self.name s1 = Student(‘張三’, 24)print(s1) # 會調用s1的__str__方法

  __repr__

  在python解釋器環境下,會默認顯示對象的repr表示。

  >>> class Student:… def __init__(self, name, age):… self.name = name… self.age = age… def __repr__(self):… return self.name… >>> s1 = Student(‘張三’, 24)>>> s1張三

  總結:

  str函數或者print函數調用的是obj.__str__()

  repr函數或者交互式解釋器調用的是obj.__repr__()

  注意:

  如果__str__沒有被定義,那麼就會使用__repr__來代替輸出。

  __str__和__repr__方法的返回值都必須是字符串。

  __format__

  class Student: def __init__(self, name, age): self.name = name self.age = age __format_dict = { ‘n-a’: ‘名字是:{obj.name}-年齡是:{obj.age}’, # 名字是:lqz-年齡是:18 ‘n:a’: ‘名字是:{obj.name}:年齡是:{obj.age}’, # 名字是:lqz:年齡是:18 ‘n/a’: ‘名字是:{obj.name}/年齡是:{obj.age}’, # 名字是:/年齡是:18 } def __format__(self, format_spec): if not format_spec or format_spec not in self.__format_dict: format_spec = ‘n-a’ fmt = self.__format_dict[format_spec] print(fmt) #{obj.name}:{obj.age} return fmt.format(obj=self)s1 = Student(‘lqz’, 24)ret = format(s1, ‘n/a’)print(ret) # lqz/24

  __del__

  析構方法,當對象在記憶體中被釋放時,自動觸發執行。

  註:此方法一般無須定義,因為Python是一門高級語言,資訊工程師在使用時無需關心記憶體的分配和釋放,因為此工作都是交給Python解釋器來執行,所以析構函數的調用是由解釋器在進行垃圾回收時自動觸發執行的。

  class A: def __del__(self): print(‘刪除了…’)a = A()print(a) # del a # 刪除了…print(a) # NameError: name ‘a’ is not defined

  __dict__和__slots__

  Python中的類,都會從object裡繼承一個__dict__屬性,這個屬性中存放著類的屬性和方法對應的鍵值對。一個類實例化之後,這個類的實例也具有這麼一個__dict__屬性。但是二者並不相同。

  class A: some = 1 def __init__(self, num): self.num = numa = A(10)print(a.__dict__) # {‘num’: 10}a.age = 10print(a.__dict__) # {‘num’: 10, ‘age’: 10}

  從上面的例子可以看出來,實例隻保存實例的屬性和方法,類的屬性和方法它是不保存的。正是由於類和實例有__dict__屬性,所以類和實例可以在運行過程動態添加屬性和方法。

  但是由於每實例化一個類都要分配一個__dict__變量,容易浪費記憶體。因此在Python中有一個內置的__slots__屬性。當一個類設置了__slots__屬性後,這個類的__dict__屬性就不存在了(同理,該類的實例也不存在__dict__屬性),如此一來,設置了__slots__屬性的類的屬性,只能是預先設定好的。

  當你定義__slots__後,__slots__就會為實例使用一種更加緊湊的內部表示。實例通過一個很小的固定大小的小型數組來構建的,而不是為每個實例都定義一個__dict__字典,在__slots__中列出的屬性名在內部被映射到這個數組的特定索引上。使用__slots__帶來的副作用是我們沒有辦法給實例添加任何新的屬性了。

  注意:盡管__slots__看起來是個非常有用的特性,但是除非你十分確切的知道要使用它,否則盡量不要使用它。例如定義了__slots__屬性的類就不支持多繼承。__slots__通常都是作為一種優化工具來使用。–摘自《Python Cookbook》8.4

  class A: __slots__ = [‘name’, ‘age’] a1 = A()# print(a1.__dict__) # AttributeError: ‘A’ object has no attribute ‘__dict__’a1.name = ‘張三’a1.age = 24# a1.hobby = ‘泡妞’ # AttributeError: ‘A’ object has no attribute ‘hobby’print(a1.__slots__)

  注意事項:

  __slots__的很多特性都依賴於普通的基於字典的實現。

  另外,定義了__slots__後的類不再 支持一些普通類特性了,例如多繼承。大多數情況下,你應該隻在那些經常被使用到的用作數據結構的類上定義__slots__,例如在程序中需要創建某個類的幾百萬個實例對象 。

  關於__slots__的一個常見錯誤是它可以作為一個封裝工具來防止用戶給實例增加新的屬性。盡管使用__slots__可以達到這樣的目的,但是這個並不是它的初衷。它更多的是用來作為一個記憶體優化工具。

  __item__系列

  class Foo: def __init__(self, name): self.name = name def __getitem__(self, item): print(self.__dict__[item]) def __setitem__(self, key, value): print(‘obj[key]=lqz賦值時,執行我’) self.__dict__[key] = value def __delitem__(self, key): print(‘del obj[key]時,執行我’) self.__dict__.pop(key) def __delattr__(self, item): print(‘del obj.key時,執行我’) self.__dict__.pop(item)f1 = Foo(‘sb’)print(f1.__dict__)f1[‘age’] = 18f1.hobby = ‘泡妞’del f1.hobbydel f1[‘age’]f1[‘name’] = ‘lqz’print(f1.__dict__)

  __init__

  使用Python寫面向對象的代碼的時候我們都會習慣性寫一個 __init__ 方法,__init__ 方法通常用在初始化一個類實例的時候。例如:

  class Person: def __init__(self, name, age): self.name = name self.age = age def __str__(self): return ‘‘.format(self.name, self.age)p1 = Person(‘張三’, 24)print(p1)

  上面是__init__最普通的用法了。但是__init__其實不是實例化一個類的時候第一個被調用的方法。當使用 Persion(name, age) 來實例化一個類時,最先被調用的方法其實是 __new__ 方法。

  __new__

  其實__init__是在類實例被創建之後調用的,它完成的是類實例的初始化操作,而 __new__方法正是創建這個類實例的方法

  class Person: def __new__(cls, *args, **kwargs): print(‘調用__new__,創建類實例’) return super().__new__(Person) def __init__(self, name, age): print(‘調用__init__,初始化實例’) self.name = name self.age = age def __str__(self): return ‘‘.format(self.name, self.age)p1 = Person(‘張三’, 24)print(p1)

  輸出:

  調用__new__,創建類實例調用__init__,初始化實例

  __new__方法在類定義中不是必須寫的,如果沒定義的話默認會調用object.__new__去創建一個對象(因為創建類的時候默認繼承的就是object)。

  如果我們在類中定義了__new__方法,就是重寫了默認的__new__方法,我們可以借此自定義創建對象的行為。

  舉個例子:

  重寫類的__new__方法來實現單例模式。

  class Singleton: # 重寫__new__方法,實現每一次實例化的時候,返回同一個instance對象 def __new__(cls, *args, **kw): if not hasattr(cls, ‘_instance’): cls._instance = super().__new__(Singleton) return cls._instance def __init__(self, name, age): self.name = name self.age = ages1 = Singleton(‘張三’, 24)s2 = Singleton(‘李四’, 20)print(s1, s2) # 這兩實例都一樣print(s1.name, s2.name)

  __call__

  __call__ 方法的執行是由對象後加括號觸發的,即:對象()。擁有此方法的對象可以像函數一樣被調用。

  class Person: def __init__(self, name, age): self.name = name self.age = age def __call__(self, *args, **kwargs): print(‘調用對象的__call__方法’)a = Person(‘張三’, 24) # 類Person可調用a() # 對象a可以調用

  注意:

  __new__、__init__、__call__等方法都不是必須寫的。

  __doc__

  定義類的描述資訊。注意該資訊無法被繼承。

  class A: “””我是A類的描述資訊””” passprint(A.__doc__)

  __iter__和__next__

  如果一個對象擁有了__iter__和__next__方法,那這個對象就是可迭代對象

  class A: def __init__(self, start, stop=None): if not stop: start, stop = 0, start self.start = start self.stop = stop def __iter__(self): return self def __next__(self): if self.start >= self.stop: raise StopIteration n = self.start self.start += 1 return na = A(1, 5)from collections import Iteratorprint(isinstance(a, Iterator))for i in A(1, 5): print(i)for i in A(5): print(i)aaa=A(1)print(next(aaa))print(next(aaa)) #拋異常

  __enter__和__exit__

  一個對象如果實現了__enter__和___exit__方法,那麼這個對象就支持上下文管理協議,即with語句

  class A: def __enter__(self): print(‘進入with語句塊時執行此方法,此方法如果有返回值會賦值給as聲明的變量’) return ‘oo’ def __exit__(self, exc_type, exc_val, exc_tb): print(‘退出with代碼塊時執行此方法’) print(‘1’, exc_type) print(‘2’, exc_val) print(‘3’, exc_tb)with A() as f: print(‘進入with語句塊’) # with語句中代碼塊出現異常,則with後的代碼都無法執行。 # raise AttributeError(‘sb’) print(f) #f列印出ooprint(‘嘿嘿嘿’)

  上下文管理協議適用於那些進入和退出之後自動執行一些代碼的場景,例如文件、網路連接、資料庫連接或使用鎖的編碼場景等。

  __len__

  擁有__len__方法的對象支持len(obj)操作。

  class A: def __init__(self): self.x = 1 self.y = 2 def __len__(self): return len(self.__dict__)a = A()print(len(a))

  __hash__

  擁有__hash__方法的對象支持hash(obj)操作。

  class A: def __init__(self): self.x = 1 self.x = 2 def __hash__(self): return hash(str(self.x) + str(self.x))a = A()print(hash(a))

  __eq__

  擁有__eq__方法的對象支持相等的比較操作

  class A: def __init__(self,x,y): self.x = x self.y = y def __eq__(self,obj): # 列印出比較的第二個對象的x值 print(obj.x) if self.x +self.y == obj.x+obj.y: return True else: return Falsea = A(1,2)b = A(2,1)print(a == b)

點圖聯繫 戀愛小秘書 娜米 大數據帶你脫單

單身優質女會員:

男生單身優質會員:

單身聯誼活動:

不知道如何找適合的對象?歡迎追蹤娜米,與戀愛小秘書免費一對一諮詢!

配對成功的關鍵:參加實體交友活動

erose主題派對與戀愛小秘書創辦人娜米表示:「透過各種有趣的實體活動,不僅能親眼真實見到異性,也能在活動進行中讓大家很輕鬆自然的認識彼此、聊天互動,能更快速的找到適合的對象。」

結合大數據用心篩選 + 客製化條件配對

戀愛小秘書團隊已經成功替4000位以上的未婚男女配對成功,這個驚人成果背後的秘密在於「高度客製化服務」,跟每位客戶深度訪談,瞭解客戶真正的特質及需求,從「契合度」提高速配率。

訪談結果結合專屬的人格分析測驗與數據配對分析,精緻化的操作,締造高速配率!

除此之外,戀愛小秘書團隊還會定期追蹤客戶的後續狀況,目的是希望協助客戶發展長期且穩定的伴侶關係。

實名認證防造假!隱私保護最安心!

採用「實名認證」的制度,不僅是把關顧客的身份,避免已婚人士或動機不單純者的加入,更對客戶資料嚴格保密,讓客戶們能在安全且有隱私的狀況下認識另一半。

多元有趣的主題活動,豐富你的社交生活

戀愛小秘書團隊每個月都會規劃豐富多元的實體活動,從戶外踏青、娛樂遊戲、手作、料理課程到桌遊活動,希望客戶們能從歡樂的氣氛中認識彼此。

透過實體活動讓大家先有初步的接觸,然後再為會員們做「客製化」的約會安排。

另外針對想提升自身魅力的客戶,也有投資理財、形象穿搭等講座可供選擇。

追求脫單,先勇敢跨出你的第一步

許多單身者為了心中理想的對象條件,在還沒認識新朋友時,就先限制了自己。建議以認識新朋友的心態,積極參與活動,並適當的設限,才能真正為自己帶來戀愛的機會!勇敢跨出第一步吧!

♡ 現在就和戀愛小秘書娜米聊聊吧Line ID:@datenami

♡ 追蹤娜米的臉書粉絲團

延伸閱讀:

在你最愛的平台追蹤娜米

脫單秘笈

戀愛數字

男女會員

戀愛金句

時事觀察

生活圖文

諮詢服務

會員活動

活動分享

教學影片

服務介紹

留言互動

教學影片

生活圖文

留言互動

教學影片

服務介紹

留言互動