Python魔法方法(二)

類的表示

使用字符串來表示類是一個相當有用的特性。在Python中有一些內建方法可以返回類的表示,相對應的,也有一系列魔法方法可以用來自定義在使用這些內建函數時類的行爲。

  • __str__(self)

定義對類的實例調用 str() 時的行爲。

  • __repr__(self)

定義對類的實例調用 repr() 時的行爲。 str() 和 repr() 最主要的差別在於“目標用戶”。 repr() 的作用是產生機器可讀的輸出(大部分情況下,其輸出可以作爲有效的Python代碼),而 str() 則產生人類可讀的輸出。

  • __unicode__(self)

定義對類的實例調用 unicode() 時的行爲。 unicode() 和 str() 很像,只是它返回unicode字符串。注意,如果調用者試圖調用 str() 而你的類只實現了 __unicode__() ,那麼類將不能正常工作。所有你應該總是定義 __str__() ,以防有些人沒有閒情雅緻來使用unicode。

  • __format__(self)

定義當類的實例用於新式字符串格式化時的行爲,例如, “Hello, 0:abc!”.format(a) 會導致調用 a.__format__(“abc”) 。當定義你自己的數值類型或字符串類型時,你可能想提供某些特殊的格式化選項,這種情況下這個魔法方法會非常有用。

  • __hash__(self)

定義對類的實例調用 hash() 時的行爲。它必須返回一個整數,其結果會被用於字典中鍵的快速比較。同時注意一點,實現這個魔法方法通常也需要實現 __eq__ ,並且遵守如下的規則: a == b 意味着 hash(a) == hash(b)。

  • __nonzero__(self)

定義對類的實例調用 bool() 時的行爲,根據你自己對類的設計,針對不同的實例,這個魔法方法應該相應地返回True或False。

  • __dir__(self)

定義對類的實例調用 dir() 時的行爲,這個方法應該向調用者返回一個屬性列表。一般來說,沒必要自己實現 __dir__ 。但是如果你重定義了 __getattr__ 或者 __getattribute__ (下個部分會介紹),乃至使用動態生成的屬性,以實現類的交互式使用,那麼這個魔法方法是必不可少的。

到這裏,我們基本上已經結束了魔法方法指南中無聊並且例子匱乏的部分。既然我們已經介紹了較爲基礎的魔法方法,是時候涉及更高級的內容了

訪問控制

很多從其他語言轉向Python的人都抱怨Python的類缺少真正意義上的封裝(即沒辦法定義私有屬性然後使用公有的getter和setter)。然而事實並非如此。實際上Python不是通過顯式定義的字段和方法修改器,而是通過魔法方法實現了一系列的封裝。

  • __getattr__(self, name)

當用戶試圖訪問一個根本不存在(或者暫時不存在)的屬性時,你可以通過這個魔法方法來定義類的行爲。這個可以用於捕捉錯誤的拼寫並且給出指引,使用廢棄屬性時給出警告(如果你願意,仍然可以計算並且返回該屬性),以及靈活地處理AttributeError。只有當試圖訪問不存在的屬性時它纔會被調用,所以這不能算是一個真正的封裝的辦法。

  • __setattr__(self, name, value)

和 __getattr__ 不同, __setattr__ 可以用於真正意義上的封裝。它允許你自定義某個屬性的賦值行爲,不管這個屬性存在與否,也就是說你可以對任意屬性的任何變化都定義自己的規則。然後,一定要小心使用 __setattr__ ,這個列表最後的例子中會有所展示。

  • __delattr__(self, name)

這個魔法方法和 __setattr__ 幾乎相同,只不過它是用於處理刪除屬性時的行爲。和 _setattr__ 一樣,使用它時也需要多加小心,防止產生無限遞歸(在 __delattr__ 的實現中調用 del self.name 會導致無限遞歸)。

  • __getattribute__(self, name)

\_\_getattribute\_\_ 看起來和上面那些方法很合得來,但是最好不要使用它。 __getattribute__ 只能用於新式類。在最新版的Python中所有的類都是新式類,在老版Python中你可以通過繼承 object 來創建新式類。 __getattribute__ 允許你自定義屬性被訪問時的行爲,它也同樣可能遇到無限遞歸問題(通過調用基類的 __getattribute__ 來避免)。 __getattribute__ 基本上可以替代 __getattr__ 。只有當它被實現,並且顯式地被調用,或者產生 AttributeError 時它才被使用。 這個魔法方法可以被使用(畢竟,選擇權在你自己),我不推薦你使用它,因爲它的使用範圍相對有限(通常我們想要在賦值時進行特殊操作,而不是取值時),而且實現這個方法很容易出現Bug。

自定義這些控制屬性訪問的魔法方法很容易導致問題,考慮下面這個例子:

def __setattr__(self, name. value):
    self.name = value
    # 因爲每次屬性幅值都要調用 __setattr__(),所以這裏的實現會導致遞歸
    # 這裏的調用實際上是 self.__setattr('name', value)。因爲這個方法一直
    # 在調用自己,因此遞歸將持續進行,直到程序崩潰

def __setattr__(self, name, value):
    self.__dict\_\_[name] = value # 使用 __dict__ 進行賦值
    # 定義自定義行爲

再次重申,Python的魔法方法十分強大,能力越強責任越大,瞭解如何正確的使用魔法方法更加重要。

到這裏,我們對Python中自定義屬性存取控制有了什麼樣的印象?它並不適合輕度的使用。實際上,它有些過分強大,而且違反直覺。然而它之所以存在,是因爲一個更大的原則:Python不指望讓杜絕壞事發生,而是想辦法讓做壞事變得困難。自由是至高無上的權利,你真的可以隨心所欲。下面的例子展示了實際應用中某些特殊的屬性訪問方法(注意我們之所以使用 super 是因爲不是所有的類都有 __dict__ 屬性):

class AccessCounter(object):
    ''' 一個包含了一個值並且實現了訪問計數器的類
    每次值的變化都會導致計數器自增'''

    def __init__(self, val):
        super().__setattr__('counter', 0)
        super().__setattr__('value', val)

    def __setattr__(self, name, value):
        if name == 'value':
            super().__setattr__('counter', self.counter + 1)
        # 使計數器自增變成不可避免
        # 如果你想阻止其他屬性的賦值行爲
        # 產生 AttributeError(name) 就可以了

            super().__setattr__(name, value)

    def __delattr__(self, name):
        if name == 'value':
            super().__setattr__('counter', self.counter + 1)
            super().__delattr__(name)



if __name__ == '__main__':
    ins = AccessCounter(val=10)
    ins.value = 1
    ins.value = 1
    ins.value = 1
    ins.value = 1
    print(ins.counter)
    print(ins.value)
    del ins.value
    print(ins.counter)
    
    
輸出:
4
1
5

自定義序列

有許多辦法可以讓你的Python類表現得像是內建序列類型(字典,元組,列表,字符串等)。這些魔法方式是目前爲止我最喜歡的。它們給了你難以置信的控制能力,可以讓你的類與一系列的全局函數完美結合。在瞭解激動人心的內容之前,首先你需要掌握一些預備知識。

預備知識

既然講到創建自己的序列類型,就不得不說一說協議了。協議類似某些語言中的接口,裏面包含的是一些必須實現的方法。在Python中,協議完全是非正式的,也不需要顯式的聲明,事實上,它們更像是一種參考標準。

爲什麼我們要講協議?因爲在Python中實現自定義容器類型需要用到一些協議。首先,不可變容器類型有如下協議:想實現一個不可變容器,你需要定義 __len__ 和 __getitem__ (後面會具體說明)。可變容器的協議除了上面提到的兩個方法之外,還需要定義 __setitem__ 和 __delitem__ 。最後,如果你想讓你的對象可以迭代,你需要定義 __iter__ ,這個方法返回一個迭代器。迭代器必須遵守迭代器協議,需要定義 __iter__ (返回它自己)和 next 方法。

容器背後的魔法方法

__len__(self)

返回容器的長度,可變和不可變類型都需要實現。

__getitem__(self, key)

定義對容器中某一項使用 self[key] 的方式進行讀取操作時的行爲。這也是可變和不可變容器類型都需要實現的一個方法。它應該在鍵的類型錯誤式產生 TypeError 異常,同時在沒有與鍵值相匹配的內容時產生 KeyError 異常。

__setitem__(self, key)

定義對容器中某一項使用 self[key] 的方式進行賦值操作時的行爲。它是可變容器類型必須實現的一個方法,同樣應該在合適的時候產生 KeyError 和 TypeError 異常。

__iter__(self, key)

它應該返回當前容器的一個迭代器。迭代器以一連串內容的形式返回,最常見的是使用 iter() 函數調用,以及在類似 for x in container: 的循環中被調用。迭代器是他們自己的對象,需要定義 __iter__ 方法並在其中返回自己。

__reversed__(self)

定義了對容器使用 reversed() 內建函數時的行爲。它應該返回一個反轉之後的序列。當你的序列類是有序時,類似列表和元組,再實現這個方法,

__contains__(self, item)

__contains__ 定義了使用 in 和 not in 進行成員測試時類的行爲。你可能好奇爲什麼這個方法不是序列協議的一部分,原因是,如果 __contains__ 沒有定義,Python就會迭代整個序列,如果找到了需要的一項就返回 True 。

__missing__(self ,key)

__missing__ 在字典的子類中使用,它定義了當試圖訪問一個字典中不存在的鍵時的行爲(目前爲止是指字典的實例,例如我有一個字典 d , “george” 不是字典中的一個鍵,當試圖訪問 d[“george’] 時就會調用 d.__missing__(“george”) )。

一個例子

讓我們來看一個實現了一些函數式結構的列表,可能在其他語言中這種結構更常見(例如Haskell):

class FunctionalList:
    '''一個列表的封裝類,實現了一些額外的函數式
    方法,例如head, tail, init, last, drop和take。'''

    def __init__(self, values=None):
        if values is None:
            self.values = []
        else:
            self.values = values

    def __len__(self):
        return len(self.values)

    def __getitem__(self, key):
        # 如果鍵的類型或值不合法,列表會返回異常
        return self.values[key]

    def __setitem__(self, key, value):
        self.values[key] = value

    def __delitem__(self, key):
        del self.values[key]

    def __iter__(self):
        return iter(self.values)

    def __reversed__(self):
        return reversed(self.values)

    def append(self, value):
        self.values.append(value)

    def head(self):
        # 取得第一個元素
        return self.values[0]

    def tail(self):
        # 取得除第一個元素外的所有元素
        return self.values[1:]

    def init(self):
        # 取得除最後一個元素外的所有元素
        return self.values[:-1]

    def last(self):
        # 取得最後一個元素
        return self.values[-1]

    def drop(self, n):
        # 取得除前n個元素外的所有元素
        return self.values[n:]

    def take(self, n):
        # 取得前n個元素
        return self.values[:n]

就是這些,一個(微不足道的)有用的例子,向你展示瞭如何實現自己的序列。當然啦,自定義序列有更大的用處,而且絕大部分都在標準庫中實現了(Python是自帶電池的,記得嗎?),像 Counter , OrderedDict 和 NamedTuple 。

反射

你可以通過定義魔法方法來控制用於反射的內建函數 isinstance 和 issubclass 的行爲。下面是對應的魔法方法:

  • __instancecheck__(self, instance)

檢查一個實例是否是你定義的類的一個實例(例如 isinstance(instance, class) )。

  • __subclasscheck__(self, subclass)

檢查一個類是否是你定義的類的子類(例如 issubclass(subclass, class) )。

這幾個魔法方法的適用範圍看起來有些窄,事實也正是如此。我不會在反射魔法方法上花費太多時間,因爲相比其他魔法方法它們顯得不是很重要。但是它們展示了在Python中進行面向對象編程(或者總體上使用Python進行編程)時很重要的一點:不管做什麼事情,都會有一個簡單方法,不管它常用不常用。這些魔法方法可能看起來沒那麼有用,但是當你真正需要用到它們的時候,你會感到很幸運,因爲它們還在那兒。

抽象基類

參考: https://docs.python.org/zh-cn/3.7/library/abc.html

可調用的對象

你可能已經知道了,在Python中,函數是一等的對象。這意味着它們可以像其他任何對象一樣被傳遞到函數和方法中,這是一個十分強大的特性。

Python中一個特殊的魔法方法允許你自己類的對象表現得像是函數,然後你就可以“調用”它們,把它們傳遞到使用函數做參數的函數中,等等等等。這是另一個強大而且方便的特性,讓使用Python編程變得更加幸福。

  • __call__(self, [args…])

允許類的一個實例像函數那樣被調用。本質上這代表了 x() 和 x.__call__() 是相同的。注意 __call__ 可以有多個參數,這代表你可以像定義其他任何函數一樣,定義 __call__ ,喜歡用多少參數就用多少。

__call__ 在某些需要經常改變狀態的類的實例中顯得特別有用。“調用”這個實例來改變它的狀態,是一種更加符合直覺,也更加優雅的方法。一個表示平面上實體的類是一個不錯的例子:

class Entity:
    '''表示一個實體的類,調用它的實例
    可以更新實體的位置'''

    def __init__(self, size, x, y):
        self.x, self.y = x, y
        self.size = size

    def __call__(self, x, y):
        '''改變實體的位置'''
        self.x, self.y = x, y

if __name__ == '__main__':
    e = Entity(1, 2, 2)
    e(4, 5)
    print(e.x)

上下文管理器

在Python 2.5中引入了一個全新的關鍵詞,隨之而來的是一種新的代碼複用方法—— with 聲明。上下文管理的概念在Python中並不是全新引入的(之前它作爲標準庫的一部分實現),直到PEP 343被接受,它才成爲一種一級的語言結構。可能你已經見過這種寫法了:

with open('foo.txt') as bar:
    # 使用bar進行某些操作

當對象使用 with 聲明創建時,上下文管理器允許類做一些設置和清理工作。上下文管理器的行爲由下面兩個魔法方法所定義:

  • __enter__(self)

定義使用 with 聲明創建的語句塊最開始上下文管理器應該做些什麼。注意 __enter__ 的返回值會賦給 with 聲明的目標,也就是 as 之後的東西。

  • __exit__(self, exception_type, exception_value, traceback)

定義當 with 聲明語句塊執行完畢(或終止)時上下文管理器的行爲。它可以用來處理異常,進行清理,或者做其他應該在語句塊結束之後立刻執行的工作。如果語句塊順利執行, exception_type , exception_value 和 traceback 會是 None 。否則,你可以選擇處理這個異常或者讓用戶來處理。如果你想處理異常,確保 __exit__ 在完成工作之後返回 True 。如果你不想處理異常,那就讓它發生吧。

對一些具有良好定義的且通用的設置和清理行爲的類,__enter__ 和 __exit__ 會顯得特別有用。你也可以使用這幾個方法來創建通用的上下文管理器,用來包裝其他對象。下面是一個例子:

class Closer:
    '''一個上下文管理器,可以在with語句中
    使用close()自動關閉對象'''

    def __init__(self, obj):
        self.obj = obj

    def __enter__(self, obj):
        return self.obj  # 綁定到目標

    def __exit__(self, exception_type, exception_value, traceback):
        try:
            self.obj.close()
        except AttributeError:  # obj不是可關閉的
            print('Not closable.')
            return True  # 成功地處理了異常

>>> from magicmethods import Closer
>>> from ftplib import FTP
>>> with Closer(FTP('ftp.somesite.com')) as conn:
...         conn.dir()
...
# 爲了簡單,省略了某些輸出
>>> conn.dir()
# 很長的 AttributeError 信息,不能使用一個已關閉的連接
>>> with Closer(int(5)) as i:
...         i += 1
...
Not closable.
>>> i
6

看到我們的包裝器是如何同時優雅地處理正確和不正確的調用了嗎?這就是上下文管理器和魔法方法的力量。Python標準庫包含一個 contextlib 模塊,裏面有一個上下文管理器 contextlib.closing() 基本上和我們的包裝器完成的是同樣的事情(但是沒有包含任何當對象沒有close()方法時的處理)。

創建描述符對象

描述符是一個類,當使用取值,賦值和刪除 時它可以改變其他對象。描述符不是用來單獨使用的,它們需要被一個擁有者類所包含。描述符可以用來創建面向對象數據庫,以及創建某些屬性之間互相依賴的類。描述符在表現具有不同單位的屬性,或者需要計算的屬性時顯得特別有用(例如表現一個座標系中的點的類,其中的距離原點的距離這種屬性)。

要想成爲一個描述符,一個類必須具有實現 __get__ , __set__ 和 __delete__ 三個方法中至少一個。

讓我們一起來看一看這些魔法方法:

  • __get__(self, instance, owner)

定義當試圖取出描述符的值時的行爲。 instance 是擁有者類的實例, owner 是擁有者類本身。

  • __set__(self, instance, owner)

定義當描述符的值改變時的行爲。 instance 是擁有者類的實例, value 是要賦給描述符的值。

  • __delete__(self, instance, owner)

定義當描述符的值被刪除時的行爲。 instance 是擁有者類的實例

現在,來看一個描述符的有效應用:單位轉換:

class Meter(object):
    '''米的描述符。'''

    def __init__(self, value=0.0):
        self.value = float(value)

    def __get__(self, instance, owner):
        return self.value

    def __set__(self, instance, value):
        self.value = float(value)


class Foot(object):
    '''英尺的描述符。'''

    def __get__(self, instance, owner):
        return instance.meter * 3.2808

    def __set__(self, instance, value):
        instance.meter = float(value) / 3.2808


class Distance(object):
    '''用於描述距離的類,包含英尺和米兩個描述符。'''
    meter = Meter()
    foot = Foot()



if __name__ == '__main__':
    d = Distance()
    d.meter = 100
    print(d.meter)
    print(d.foot)
    

輸出:
100.0
328.08000000000004

拷貝

有些時候,特別是處理可變對象時,你可能想拷貝一個對象,改變這個對象而不影響原有的對象。這時就需要用到Python的 copy 模塊了。然而(幸運的是),Python模塊並不具有感知能力, 因此我們不用擔心某天基於Linux的機器人崛起。但是我們的確需要告訴Python如何有效率地拷貝對象。

  • __copy__(self)

定義對類的實例使用 copy.copy() 時的行爲。 copy.copy() 返回一個對象的淺拷貝,這意味着拷貝出的實例是全新的,然而裏面的數據全都是引用的。也就是說,對象本身是拷貝的,但是它的數據還是引用的(所以淺拷貝中的數據更改會影響原對象)。

  • __deepcopy__(self, memodict=)

定義對類的實例使用 copy.deepcopy() 時的行爲。 copy.deepcopy() 返回一個對象的深拷貝,這個對象和它的數據全都被拷貝了一份。 memodict 是一個先前拷貝對象的緩存,它優化了拷貝過程,而且可以防止拷貝遞歸數據結構時產生無限遞歸。當你想深拷貝一個單獨的屬性時,在那個屬性上調用 copy.deepcopy() ,使用 memodict 作爲第一個參數。

這些魔法方法有什麼用武之地呢?像往常一樣,當你需要比默認行爲更加精確的控制時。例如,如果你想拷貝一個對象,其中存儲了一個字典作爲緩存(可能會很大),拷貝緩存可能是沒有意義的。如果這個緩存可以在內存中被不同實例共享,那麼它就應該被共享。

Pickling

如果你和其他的Python愛好者共事過,很可能你已經聽說過Pickling了。Pickling是Python數據結構的序列化過程,當你想存儲一個對象稍後再取出讀取時,Pickling會顯得十分有用。然而它同樣也是擔憂和混淆的主要來源。

Pickling是如此的重要,以至於它不僅僅有自己的模塊( pickle ),還有自己的協議和魔法方法。首先,我們先來簡要的介紹一下如何pickle已存在的對象類型(如果你已經知道了,大可跳過這部分內容)。

Pickling : 小試牛刀

我們一起來pickle吧。假設你有一個字典,你想存儲它,稍後再取出來。你可以把它的內容寫入一個文件,小心翼翼地確保使用了正確地格式,要把它讀取出來,你可以使用 exec() 或處理文件輸入。但是這種方法並不可靠:如果你使用純文本來存儲重要數據,數據很容易以多種方式被破壞或者修改,導致你的程序崩潰,更糟糕的情況下,還可能在你的計算機上運行惡意代碼。因此,我們要pickle它:

mport pickle

data = {
    'foo': [1, 2, 3],
    'bar': ('Hello', 'world!'),
    'baz': True
}
jar = open('data.pkl', 'wb')
pickle.dump(data, jar) # 將pickle後的數據寫入jar文件
jar.close()

過了幾個小時,我們想把它取出來,我們只需要反pickle它:

import pickle

pkl_file = open('data.pkl', 'rb') # 與pickle後的數據連接
data = pickle.load(pkl_file) # 把它加載進一個變量
print data
pkl_file.close()

將會發生什麼?正如你期待的,它就是我們之前的 data 。

現在,還需要謹慎地說一句: pickle並不完美。Pickle文件很容易因爲事故或被故意的破壞掉。Pickling或許比純文本文件安全一些,但是依然有可能被用來運行惡意代碼。而且它還不支持跨Python版本,所以不要指望分發pickle對象之後所有人都能正確地讀取。然而不管怎麼樣,它依然是一個強有力的工具,可以用於緩存和其他類型的持久化工作。

Pickle你的對象

Pickle不僅僅可以用於內建類型,任何遵守pickle協議的類都可以被pickle。Pickle協議有四個可選方法,可以讓類自定義它們的行爲(這和C語言擴展略有不同,那不在我們的討論範圍之內)

  • __getinitargs__(self)

如果你想讓你的類在反pickle時調用 __init__ ,你可以定義 __getinitargs__(self) ,它會返回一個參數元組,這個元組會傳遞給 __init__ 。注意,這個方法只能用於舊式類。

  • __getnewargs__(self)

對新式類來說,你可以通過這個方法改變類在反pickle時傳遞給 __new__ 的參數。這個方法應該返回一個參數元組。

  • __getstate__(self)

你可以自定義對象被pickle時被存儲的狀態,而不使用對象的 __dict__ 屬性。 這個狀態在對象被反pickle時會被 __setstate__ 使用。

  • __setstate__(self)

當一個對象被反pickle時,如果定義了 __setstate__ ,對象的狀態會傳遞給這個魔法方法,而不是直接應用到對象的 __dict__ 屬性。這個魔法方法和 __getstate__ 相互依存:當這兩個方法都被定義時,你可以在Pickle時使用任何方法保存對象的任何狀態。

  • __reduce__(self)

當定義擴展類型時(也就是使用Python的C語言API實現的類型),如果你想pickle它們,你必須告訴Python如何pickle它們。 __reduce__ 被定義之後,當對象被Pickle時就會被調用。它要麼返回一個代表全局名稱的字符串,Pyhton會查找它並pickle,要麼返回一個元組。這個元組包含2到5個元素,其中包括:一個可調用的對象,用於重建對象時調用;一個參數元素,供那個可調用對象使用;被傳遞給 __setstate__ 的狀態(可選);一個產生被pickle的列表元素的迭代器(可選);一個產生被pickle的字典元素的迭代器(可選);

  • __reduce_ex__(self)

__reduce_ex__ 的存在是爲了兼容性。如果它被定義,在pickle時 __reduce_ex__ 會代替 __reduce__ 被調用。 __reduce__ 也可以被定義,用於不支持 __reduce_ex__ 的舊版pickle的API調用。

一個例子


class Slate:
    '''存儲一個字符串和一個變更日誌的類,每次被pickle都會忘記它當前的值'''

    def __init__(self, value):
        self.value = value
        self.last_change = time.asctime()
        self.history = {}

    def change(self, new_value):
        # 改變當前值,將上一個值記錄到歷史
        self.history[self.last_change] = self.value
        self.value = new_value
        self.last_change = time.asctime()

    def print_change(self):
        print('Change for Slate object')
        for k, v in self.history.items():
            print('%s\t %s' % (k, v))

    def __getstate__(self):
        # 故意不返回self.value或self.last_change
        # 我們想在反pickle時得到一個空白的slate
        return self.history

    def __setstate__(self, state):
        self.history = state
        self.value, self.last_change = None, None

如何調用魔法方法

一些魔法方法直接和內建函數對應,這種情況下,如何調用它們是顯而易見的。然而,另外的情況下,調用魔法方法的途徑並不是那麼明顯。這個附錄旨在展示那些不那麼明顯的調用魔法方法的語法。

魔法方法 什麼時候被調用 解釋
__new__(cls [,…]) instance = MyClass(arg1, arg2) __new__在實例創建時調用
__init__(self [,…]) instance = MyClass(arg1,arg2) __init__在實例創建時調用
__cmp__(self) self == other, self > other 等 進行比較時調用
__pos__(self) +self 一元加法符號
__neg__(self) -self 一元減法符號
__invert__(self) ~self 按位取反
__index__(self) x[self] 當對象用於索引時
__nonzero__(self) bool(self) 對象的布爾值
__getattr__(self, name) self.name #name不存在 訪問不存在的屬性
__setattr__(self, name) self.name = val 給屬性賦值
__delattr_(self, name) del self.name 刪除屬性
__getattribute__(self,name) self.name 訪問任意屬性
__getitem__(self, key) self[key] 使用索引訪問某個元素
__setitem__(self, key) self[key] = val 使用索引給某個元素賦值
__delitem__(self, key) del self[key] 使用索引刪除某個對象
__iter__(self) for x in self 迭代
__contains__(self, value) value in self, value not in self 使用in進行成員測試
__call__(self [,…]) self(args) “調用”一個實例
__enter__(self) with self as x: with聲明的上下文管理器
__exit__(self, exc, val, trace) with self as x: with聲明的上下文管理器
__getstate__(self) pickle.dump(pkl_file, self) Pickling
__setstate__(self) data = pickle.load(pkl_file) Pickling
發佈了21 篇原創文章 · 獲贊 9 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章