1. 程式人生 > >《Python高階程式設計》(四)魔術方法

《Python高階程式設計》(四)魔術方法

魔術方法

定義

被設計用於過載Python的操作符或內建方法。可通過__語法定義

可用的魔術方法

建立與銷燬:__init__方法
  • 注意:__init__方法並沒有建立新物件(建立由__new__完成),僅為建立後的物件提供初始化資料
建立與銷燬:__new__方法
  • __new__方法實際上在__init__方法之前執行,用於建立類的例項
  • __new__方法用於是靜態的
    • 大多數類無需定義__new__方法。其內建實現依據足夠
    • 案例:
        class MyClass(object):
            def __new__(cls, *args, **kwargs):
                instance = super(MyClass, cls).__new__(cls, *args, **kwargs)
                #pass
                return instance
建立與銷燬:__del__方法
  • 在物件被銷燬時呼叫;無論物件以何種方式銷燬都會觸發__del__方法執行
  • 案例
    class Xon(object):
        def __del__(self):
            print "AUUUUUUUUUUUUUUUUUU"

    print Xon()   #Xon建立物件,但並沒有賦值給變數,因此python直譯器不會保留該物件
    print "abc"   #記憶體操作導致垃圾回收器遍歷表,找到Xon物件並刪除它
    ===>
    <__main__.Xon object at 0x017CBA50> AUUUUUUUUUUUUUUUUUU
    abc
型別轉換:strunicode、__bytes__方法
  • python中存在多個用於將複雜物件轉換為簡單物件或常用資料型別的魔術方法
  • python2中使用__unicode__方法,在物件傳遞給unicode的建構函式時被呼叫
  • python3中使用__bytes__方法,在物件傳遞給bytes的建構函式時被呼叫
  • 案例:python2中格式化unicode物件時首先嚐試__unicode__方法:
class Which(object):
	def __str__(self):
		return 'string'
	def __unicode__(self):
		return u'unicode'

print u'this %s was used' % Which()
print 'this %s was used' % Which()
====>
this unicode was used
this string was used
型別轉換:__bool__方法 物件需要界定True或False
  • python2中:命名為__nonzero__
  • python3中:命名為__bool__
型別轉換:intfloat、__complex__方法
  • python2擁有單獨的Long型別,因此具有__long__方法
比較:二元相等性:__eq__方法
  • 兩個物件使用==操作符進行比較時被呼叫
  • 案例:
class Myclass(object):
	def __eq__(self, other):
		print "The following are being tested for equivalence:\n %r\n %r " % (self, other)
		return self is other
c1 = Myclass()
c2 = Myclass()
print c1 == c2
===>
False
The following are being tested for equivalence:
 <__main__.Myclass object at 0x0184ABF0>
 <__main__.Myclass object at 0x018528B0>
False
比較 二元相等性 __ne__方法:與__eq__方法功能相反
比較 相對比較:ltlegt、__ge__方法
  • 這些方法內建了用於排序物件的sorted函式
比較 相對比較:__cmp__方法:為物件定義相對比較的舊有方式。
比較 操作符過載
  • 二元操作符:普通方法、取反方法、即席方法
  • 除法:
    • python3中對兩個int型別資料做除法返回float型別的資料
    • python2中可以通過匯入:from future import division來可選python3的特徵
一元操作符 pos(與+匹配) neg(與-匹配) invert(與~匹配)
  • 案例:
class ReversibleString(object):
	def __init__(self,s):
		self.s = s
	def __invert__(self):
		return type(self)(self.s[::-1])
	def __repr__(self):  #用於演示目的的自定義repr,因為輸出時提供記憶體地址沒有用處
		return 'ReversibleString: %s' % self.s
	def __str__(self):
		return self.s
rs = ReversibleString('The quick brown fox jumped over the lazy dogs.')
print ~rs #.sgod yzal eht revo depmuj xof nworb kciuq ehT
比較 過載常見方法
  • __len__方法
  • 案例:
class Timespan(object):
	def __int__(self, hours=0, minutes=0, seconds=0):
		self.hours = hours
		self.minutes = minutes
		self.seconds = seconds
	def __len__(self):
		return (self.hours * 3500) + (self.minutes * 60) + self.seconds

ts = Timespan(hours=2, minutes=30, seconds=1)
print len(ts)
__repr__方法:任何物件都可以定義__repr__方法
  • 物件的repr方法用於確定該物件在python互動終端中的顯示方式。在大多數情況下,一個物件的類以及其記憶體地址並不是希望獲得的值。
  • 定義repr方法可以讓物件稱為更有用的代表值
  • 對比:repr和str:一個物件的repr供程式設計師閱讀,而str的用途更廣泛,供人閱讀
  • 案例:
class Timespan(object):
    def __init__(self, hours=0, minutes=1, seconds=2):
        self.hours = hours
        self.minutes = minutes
        self.seconds = seconds

    def __len__(self):
        return (self.hours * 3500) + (self.minutes * 60) + self.seconds

    def __repr__(self):
        return 'Timespan(hours=%s,minutes=%d,seconds=%d' % (self.hours, self.minutes, self.seconds)

print Timespan()
print Timespan(hours=2, minutes=30, seconds=0)
__hash__方法:作用是通過數字化表示式唯一標識物件
  • 當一個物件傳遞給雜湊函式時,呼叫其__hash__方法,其返回整型值,通常是物件id
__format__方法:可以根據python的格式化規範來格式化不同種類的物件;任何物件都能提供__format__方法
  • 案例:
from datetime import datetime

class MyDate(datetime):
	def __format__(self, sepc_str):
		if not sepc_str:
			spec_str = '%Y-%m-%d %H:%M:%S'
		return self.strftime(spec_str)
md = MyDate(2012,4,21,11)
print '{0}'.format(md)
  • instancecheck__和__subclasscheck
  • __abs__方法和__round__方法
集合
  • __contains__方法:對錶達式求值時被呼叫,如果needle在集合中,則返回True,否則返回False
from datetime import date
class DateRangge(object):
    def __init__(self, start, end):
        self.start = start
        self.end = end

    def __contains__(self, needle):
        return self.start <= needle <= self.end


dr = DateRangge(date(2015, 1, 1), date(2015, 12, 31))
print date(2015, 4, 21) in dr  # True
print date(2012, 1, 1) in dr  # False
其他魔術方法
- __iter__和__next__實現迭代協議
- __enter__和__exit__實現上下文管理