1. 程式人生 > >《零基礎入門學習Python》(43)魔法方法:算術運算(2)

《零基礎入門學習Python》(43)魔法方法:算術運算(2)

前言:

上節課我們介紹了很多關於計算的魔法方法,當你的物件進行了相關的算術操作的時候,自然而然就會觸發相應的魔法方法,一旦你重寫了這些魔法方法,那麼Python就會根據你的意圖進行計算。

通過對相關的魔法方法進行重寫,可以讓Python根據你的意圖執行程式。

這裡我們就讓加變成減

>>> class int(int):
	def __add__(self,other):
		return int.__sub__(self,other)

	
>>> a=int('5')
>>> a
5
>>> b=int('3')
>>> a+b
2

知識點—— [擴充套件閱讀] Python 魔法方法詳解

1.反運算  __radd__(self, other)	(與上方相同,當左運算元不支援相應的操作時被呼叫)
>>> class Nint(int):
	def __radd__(self,other):
		return int.__sub__(self,other)

	
>>> a=Nint(5)
>>> b=Nint(6)
>>> a+b
11
>>> 1+b #因為找不到1的add方法,所以就找到b的add方法,然後就觸發b的radd方法,然後執行了一個sub方法用6-1
#self指定是b,other指的是self方法
5
2._rsub__(self, other)	(與上方相同,當左運算元不支援相應的操作時被呼叫)
>>> class Nint(int):
	def __rsub__(self,other):
		return int.__sub__(self,other)

	
>>> a=Nint(5)
>>> 3-a#和上一個程式碼同理
2
#改成熟悉的順序。。。。
class Nint(int):
	def __rsub__(self,other):
		return int.__sub__(other,self)
3.__iadd__(self, other)	定義賦值加法的行為:+=#操作同上

其他相關的魔法方法很多的相似,我就不在這列出來了,需要更多的魔法方法去開始給的連結處檢視

測試題:

0.物件相加(a+b),如果a物件有__add__方法,請問b物件的__radd__會被呼叫嘛?

答:不會!

>>> class Nint(int):
	def __radd__(self,other):
		print("__radd__被呼叫")
		return int.__add__(self,other)

	
>>> a=Nint(5)
>>> b=Nint(3)
>>> a+b
8
>>> 1+b
__radd__被呼叫
4

1.python什麼時候會呼叫到煩運算的魔法方法?

答:例如a+b,如果a物件的__add__方法沒有實現或者不支援相應的操作,那麼Python就會自動呼叫b的__radd__方法。

2.請問如何在繼承的類中呼叫基類的方法?

答:使用super()這個BIF函式。

>>> class Derived(Base):
	def meth(self):
		super(Derived,self).meth()

3.如果我要繼承的基類是動態的(有時是A,有時是B),我應該如何部署我的程式碼,以便基類可以隨意改變?

答:你可以先為基類定義一個別名,在類定義的時候,使用別名代替你要繼承的基類。如此,當你想要改變基類的時候,只需要修改給別名賦值的那個語句即可。順便說一下,當你的資源是視情況而定的時候,這個小技巧很管用。

BaseAlias = BaseClass#為基類取別名

class Derived(BaseClass):
	def meth(self):
		BaseAlias.meth(self)#通過別名訪問基類
.........

4.嘗試自己舉一個例子說明如何使用類的靜態方法

答:類的靜態屬性很簡單,在類中直接定義的變數(self)就是靜態屬性。引用的靜態屬性使用“類名.屬性名”的形式。

#類的靜態屬性使用
>>> class C:
	count = 0
	def __init__(self):
		C.count = C.count+1
	def getCount(self):
		return C.count

5. 嘗試自己舉例說明如何使用類的靜態方法,並指出使用類的靜態方法有何有點和需要注意的地方?(一定要自己先動手再看答案哦^_^)

答:靜態方法是類的特殊方法,靜態方法只需要在普通方法的前邊加上 @staticmethod 修飾符即可。

>>> class C:
        @staticmethod  # 該修飾符表示 static() 是靜態方法
        def static(arg1, arg2, arg3):
                print(arg1, arg2, arg3, arg1 + arg2 + arg3)

        def nostatic(self):
                print("I'm the f**king normal method!")

                
>>> c1=C()
>>> c2=C()
>>> c1.static is C.static
True
>>> c1.nostatic is C.nostatic
False
>>> c1.static
<function C.static at 0x03FAAC00>
>>> c2.static
<function C.static at 0x03FAAC00>
>>> C.static
<function C.static at 0x03FAAC00>
# 普通方法每個例項物件都擁有獨立的一個,開銷較大
>>> c1.nostatic
<bound method C.nostatic of <__main__.C object at 0x03F96470>>
>>> c2.nostatic
<bound method C.nostatic of <__main__.C object at 0x03F96910>>
>>> C.nostatic
<function C.nostatic at 0x03FAAC48>

使用的時候需要注意的地方:靜態方法並不需要 self 引數,因此即使是使用物件去訪問,self 引數也不會傳進去。

>>> c1.static(1, 2, 3)
1 2 3 6
>>> C.static(1, 2, 3)
1 2 3 6

動動手

0. 定義一個類,當例項化該類的時候,自動判斷傳入了多少個引數,並顯示出來。z

答:其實很容易啦,檢查下大家之前的知識點有沒有記牢固而已。

class C:
        def __init__(self, *args):
                if not args:
                        print("並沒有傳入引數")
                else:
                        print("傳入了 %d 個引數,分別是:" % len(args), end='')
                        for each in args:
                                print(each, end=' ')

 1. 定義一個單詞(Word)類繼承自字串,重寫比較操作符(參考自學:Python 魔法方法詳解),當兩個 Word 類物件進行比較時,根據單詞的長度來進行比較大小。

加分要求:例項化時如果傳入的是帶空格的字串,則取第一個空格前的單詞作為引數。

答:加分要求可以通過過載 __new__ 方法來實現(因為字串是不可變型別),通過重寫 __gt__、__lt__、__ge__、__le__ 方法來定義 Word 類在比較操作中的表現。

注意,我們沒有定義 __eq__ 和 __ne__ 方法。這是因為將會產生一些怪異不符合邏輯的結果(比如 Word('FishC') 會等於 Word('Apple'))

class Word(str):
'''儲存單詞的類,定義比較單詞的幾種方法'''

    def __new__(cls, word):
        # 注意我們必須要用到 __new__ 方法,因為 str 是不可變型別
        # 所以我們必須在建立的時候將它初始化
        if ' ' in word:
            print "Value contains spaces. Truncating to first space."
            word = word[:word.index(' ')] #單詞是第一個空格之前的所有字元
        return str.__new__(cls, word)

    def __gt__(self, other):
        return len(self) > len(other)
    def __lt__(self, other):
        return len(self) < len(other)
    def __ge__(self, other):
        return len(self) >= len(other)
    def __le__(self, other):
        return len(self) <= len(other)