日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

Python 的 Magic Methods 指南(转)

發(fā)布時間:2023/12/31 python 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python 的 Magic Methods 指南(转) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

介紹

本指南是數(shù)月博客的總結(jié)。主題是魔術(shù)方法。

什么是魔術(shù)方法呢?它們是面向?qū)ο驪ython語言中的一切。它們是你可以自定義并添加“魔法”到類中的特殊方法。它們被雙下劃線環(huán)繞(比如__init__或__lt__)。它們的文檔也不像它所需要的那么齊備。Python的所有魔術(shù)方法都在Python文檔的同一區(qū)域,但它們的使用分散,組織松散。而且文檔的這部分區(qū)域中幾乎沒有一個示例(這很有可能是設(shè)計好的,因為在語法參考里它們都很詳盡,但伴隨的是枯燥的語法描述等等)。

因此,為了解決Python文檔中我認為的缺陷,我想提供一些更簡單直白的表述——示例驅(qū)動型的Python魔術(shù)方法文檔。我從每周的博客開始,現(xiàn)在我已經(jīng)完成了,并把它們合到了一起。

我希望你能喜歡它。把它作為一個教程、復習或參考使用;它希望能成為一個Python魔術(shù)方法用戶友好的指導。

構(gòu)造與初始化

我們每個知道的最基本的“魔法”方法是__init__。一種讓我們在初始化一個類時定義一些行為。然而當我執(zhí)行 x = SomeClass(), __init__ 不是第一個被執(zhí)行的。事實上,第一被執(zhí)行的的方法是__new__,它會創(chuàng)建一個實例,然后在構(gòu)造器創(chuàng)建時傳遞一些參數(shù)。在一個object的生命周期的另一端的方法是__del__。讓我們仔細看看這3個“魔法”方法:

  • __new__(cls, [...)

  • __new__ 是一個類的初始化過程中第一個被執(zhí)行的方法。它創(chuàng)建了類,然后把一些參數(shù)傳遞給__init__。__new__ 很少被使用,特別是當我們用一些不可變類型的子類時(像tuple ,string),我不想關(guān)心__new__的太多的細節(jié),因為那是沒有用的。但它有它存在的意義。更多詳細的請看?in the Python docs.

  • __init__(self, [...)

  • 類的構(gòu)造器,當初始構(gòu)造方法被執(zhí)行(例如,我們執(zhí)行 x = SomeClass(10,'foo')),__init__ 就會獲得 10 和 ‘foo’ 作為參數(shù)。__init__ 在python類的定義中經(jīng)常被使用

  • __del__(self)

  • 若果 __new__ 和 __init__ 形成一個類的構(gòu)造函數(shù),__del__ 是就是析構(gòu)函數(shù)。它不實現(xiàn)語句 del x 的行為(這樣代碼就不會轉(zhuǎn)換為 x.__del__())。它定義了一個被垃圾回收的行為。它在類消除的時后需要做一些額外的行為時是非常有用的,就像 sockets 和 file 類。注意,當編譯器還在運行,如果類還存活著,這里不能確保__del__一定會被執(zhí)行。所以__del__ 不能替代一些良好的編程習慣(比如連接用完了將其關(guān)掉),事實上__del__很少被使用,因為它的調(diào)用是非常不穩(wěn)定的;請謹慎使用!

把他們合起來后,這里就是一個 __init__ 和 __del__ 使用的例子:

01from?os.path?import?joinclass?FileObject:
02????'''Wrapper?for?file?objects?to?make?sure?the?file?gets?closed?on?deletion.'''
03?
04????def?__init__(self,?filepath='~',?filename='sample.txt'):
05????????#?open?a?file?filename?in?filepath?in?read?and?write?mode
06????????self.file?=?open(join(filepath,?filename),?'r+')
07?
08????def?__del__(self):
09????????self.file.close()
10????????del?self.file

?

定義自己的類中的操作

我們使用Python的“魔法”方法最大得優(yōu)勢之一是它提供了一種簡單的方法去定義類的行為,比如 built-in 類型。這就意味著你可以避免丑陋的,違反直覺的,非標準化的基本操作方法。在一些語言中,他們通常這樣寫:

1if?instance.equals(other_instance):
2????#?do?something

當讓Python中也可以這么做,但是這增加了混亂和不必要的冗余。不同的類庫中的相同的方法可能會用不同名字,使得使用者做了太多不必要的操作。相比之下“魔法”方法是強大的,我們可以使用它定義一個方法代替上面的例子(__eq__ , 在這個例子中):

1if?instance?==?other_instance:
2????#do?something

這是“魔法”方法強大用途的一部分。他們絕大部分讓我們定義操作的意義,以至于我們可以使用他們在我們自己的類中就像使用built in 類型。

?

魔法比較方法

python擁有大量用于實現(xiàn)對象與對象之間比較的魔法方法,這些對象使用運算符進行直觀比較而不是難看的方法調(diào)用。同時它也提供了一種方法去重載python默認的對象比較行為(比較引用)。這里有一個這些方法和它們做了什么事情的列表:

  • __cmp__(self, other)

  • __cmp__?是比較方法里面最基本的的魔法方法。實際上它實現(xiàn)了所有的比較運算符(如<, ==, !=)的行為,但也許不是你想要的行為(例如,一個實例是否和另一個實例相等應該由某個條件來決定,一個實例是否大于另一個實例應該由其他的條件來決定)。當self < other時__cmp__應該返回一個負整數(shù),當self == other時返回0,self > other時返回正整數(shù)。通常來說最好是定義每個你需要的比較方法而不是一次性定義所有的比較方法,但是__cmp__是一個消除重復性的良途,并且當你有很多比較方法需要用相類似的條件去實現(xiàn)的時候這能讓代碼變得清晰。

  • __eq__(self, other)

  • 定義相等符號的行為,==

  • __ne__(self,other)

  • 定義不等符號的行為,!=

  • __lt__(self,other)

  • 定義小于符號的行為,<

  • __gt__(self,other)

  • 定義大于符號的行為,>

  • __le__(self,other)

  • 定義小于等于符號的行為,<=

  • __ge__(self,other)

  • 定義大于等于符號的行為,>=

?例如,假設(shè)一個類是一個單詞模型。我們可能要按字典比較單詞(按字母),這是比較字符串默認行為,但我們也可能需要基于其他一些標準來做比較,比如按長度、或字節(jié)數(shù)量等。在下面的例子中,我們將比較長度。下面是實現(xiàn):

class?Word(str):
????'''Class?for?words,?defining?comparison?based?on?word?length.'''

????def?__new__(cls,?word):
????????#?Note?that?we?have?to?use?__new__.?This?is?because?str?is?an?immutable
????????#?type,?so?we?have?to?initialize?it?early?(at?creation)
????????if?'?'?in?word:
????????????print?"Value?contains?spaces.?Truncating?to?first?space."
????????????word?=?word[:word.index('?')]?#?Word?is?now?all?chars?before?first?space
????????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)?

?

現(xiàn)在,我們可以創(chuàng)建兩個單詞(通過使用Word('foo')和Word('bar'))然后依據(jù)長度比較它們。但要注意,我們沒有定義__eq__和__ne__,因為這樣會導致其他一些奇怪的行為(尤其是Word('foo')==Word('bar')會判定為true),它不是基于長度相等意義上的測量,所以我們回歸到字符平等意義上的實現(xiàn)。

現(xiàn)在需要留心啦——為達到預期的比較效果你不需要為每個比較定義魔術(shù)方法。如果你只定義__eq__以及其他的(比如__gt__,__lt__等),標準庫已經(jīng)在functools模塊里為我們提供了一個類修飾器,它可以定義所有的富特性比較方法。這個特性只有在Python 2.7中才是可用的,但如果你碰巧的話這可以節(jié)省大量的時間和精力。你可以通過將@total_ordering放置在類定義前面來使用它。

?

數(shù)值魔術(shù)方法

就如同你可以通過定義比較操作來比較你自己的類實例一樣,你也可以自己定義數(shù)學運算符號的行為。好吧,先系緊你的褲腰帶,深呼吸......,這些操作可多著呢。由于文章組織需要,我把這些數(shù)學“魔術(shù)方法”分為5類:單目運算操作,一般數(shù)學運算操作,滿足交換律的數(shù)學運算(后面會有更多介紹),參數(shù)賦值操作和類型轉(zhuǎn)換操作:

單目運算符操作與函數(shù):

單目運算符或單目運算函數(shù)只有一個操作數(shù): 比如取負(-2),絕對值操作等。

  • __pos__(self)

  • 實現(xiàn)一個取正數(shù)的操作(比如 +some_object ,python調(diào)用__pos__函數(shù))

  • __neg__(self)

  • 實現(xiàn)一個取負數(shù)的操作(比如 -some_object )

  • __abs__(self)

  • 實現(xiàn)一個內(nèi)建的abs()函數(shù)的行為

  • __invert__(self)

  • 實現(xiàn)一個取反操作符(~操作符)的行為。想要了解這個操作的解釋,參考the Wikipedia article on bitwise operations.

  • __round__(self, n)

  • 實現(xiàn)一個內(nèi)建的round()函數(shù)的行為。 n 是待取整的十進制數(shù).

  • __floor__(self)

  • 實現(xiàn)math.floor()的函數(shù)行為,比如, 把數(shù)字下取整到最近的整數(shù).

  • __ceil__(self)

  • 實現(xiàn)math.ceil()的函數(shù)行為,比如, 把數(shù)字上取整到最近的整數(shù).

  • __trunc__(self)

  • 實現(xiàn)math.trunc()的函數(shù)行為,比如, 把數(shù)字截斷而得到整數(shù).

  • 一般算數(shù)運算

    好吧,現(xiàn)在我們開始介紹雙目運算操作或函數(shù),比如 +, -, * 等等. 這些很容易自解釋.?


    • __add__(self, other)

    • 實現(xiàn)一個加法.

    • __sub__(self, other)

    • 實現(xiàn)一個減法.

    • __mul__(self, other)

    • 實現(xiàn)一個乘法.

    • __floordiv__(self, other)

    • 實現(xiàn)一個“//”操作符產(chǎn)生的整除操作()

    • __div__(self, other)

    • 實現(xiàn)一個“/”操作符代表的除法操作.

    • __truediv__(self, other)

    • 實現(xiàn)真實除法,注意,只有當你from __future__ import division時才會有效

    • __mod__(self, other)?

      實現(xiàn)一個“%”操作符代表的取模操作.

    • __divmod__(self, other)

    • 實現(xiàn)一個內(nèi)建函數(shù)divmod()

    • __pow__

    • 實現(xiàn)一個指數(shù)操作(“**”操作符)的行為

    • __lshift__(self, other)

    • 實現(xiàn)一個位左移操作(<<)的功能

    • __rshift__(self, other)

    • 實現(xiàn)一個位右移操作(>>)的功能.

    • __and__(self, other)

    • 實現(xiàn)一個按位進行與操作(&)的行為.

    • __or__(self, other)?

      實現(xiàn)一個按位進行或操作(|)的行為.

    • __xor__(self, other)

    • 實現(xiàn)一個異或操作(^)的行為

?

反射算術(shù)運算符

你相信我說我能用一位來表示反射運算嗎?可能有人會認為表示一個反射運算是大的嚇人的“外國概念”,反射實際上它是非常簡單的。看下面的例子:

some_object?+?other

這是一個正常的加法。除了可以交換操作數(shù)以外,反射運算和加法是一樣的:

other?+?some_object

除了執(zhí)行那種 other對像作為第一個操作數(shù),而它自身作為第二個操作數(shù)的運算以外,所有的魔法方法做的事情與正常運算表示的意義是等價的。在大部分情況下反射運算結(jié)果和它正常的運算是等價的,所以你可以不定義__radd__,而是調(diào)用__add__等等。注意,對像(本例中的other)在運算符左邊的時候,必須保證該對像沒有定義(或者返回NotImplemented的)它的非反射運算符。例如,在這個例子中,some_object.__radd__? 只有在 other沒有定義__add__的時候才會被調(diào)用。

  • __radd__(self, other)

  • 反射加法

  • __rsub__(self, other)

  • 反射減法的

  • __rmul__(self, other)

  • 反射除法

  • __rfloordiv__(self, other)

  • 反射地板除,使用//運算符的

  • __rdiv__(self, other)

  • 反射除法,使用/運算符的.

  • __rtruediv__(self, other)

  • 反射真除.注意只有from __future__ import division 的時候它才有效

  • __rmod__(self, other)

  • 反射取模運算,使用%運算符.

  • __rdivmod__(self, other)

  • 長除法,使用divmod()內(nèi)置函數(shù),當divmod(other,self)時被調(diào)用.

  • __rpow__

  • 反射乘方,使用**運算符的

  • __rlshift__(self, other)

  • 反射左移,使用<<操作符.

  • __rrshift__(self, other)

  • 反射右移,使用>>操作符.

  • __rand__(self, other)

  • 反射位與,使用&操作符.

  • __ror__(self, other)

  • 反射位或,使用|操作符.

  • __rxor__(self, other)

  • 反射異或,使用^操作符.

?

增量運算

Python 還有很多種魔法方法,允許一些習慣行為被定義成增量運算。你很可能已經(jīng)熟悉了增量運算,增量運算是算術(shù)運算和賦值運算的結(jié)合。如果你還不知道我在說什么,就看一下下面的例子:

x?=?5x?+=?1?#?in?other?words?x?=?x?+?1

每一個方法的返回值都會被賦給左邊的變量。(比如,對于a += b, __iadd__ 可能會返回a + b, a + b會賦給變量a。) 下面是清單:

  • __iadd__(self, other)

  • 加法賦值

  • __isub__(self, other)

  • 減法賦值.

  • __imul__(self, other)

  • 乘法賦值

  • __ifloordiv__(self, other)

  • 整除賦值,地板除,相當于 //= 運算符.

  • __idiv__(self, other)

  • 除法賦值,相當于 /= 運算符.

  • __itruediv__(self, other)

  • 真除賦值,注意只有你?whenfrom __future__ import divisionis,才有效.

  • __imod_(self, other)

  • 模賦值,相當于 %= 運算符.

  • __ipow__

  • 乘方賦值,相當于 **= 運算符.

  • __ilshift__(self, other)

  • 左移賦值,相當于 <<= 運算符.

  • __irshift__(self, other)

  • 左移賦值,相當于 >>=?運算符.

  • __iand__(self, other)

  • 與賦值,相當于 &= 運算符.

  • __ior__(self, other)

  • 或賦值,相當于 |= 運算符.

  • __ixor__(self, other)

  • 異或運算符,相當于 ^= 運算符.

類型轉(zhuǎn)換魔法

Python 同樣有一系列的魔法方法旨在實現(xiàn)內(nèi)置類型的轉(zhuǎn)換,比如float() 函數(shù)。它們是:

  • __int__(self)

  • 轉(zhuǎn)換成整型.

  • __long__(self)

  • 轉(zhuǎn)換成長整型.

  • __float__(self)

  • 轉(zhuǎn)換成浮點型.

  • __complex__(self)

  • 轉(zhuǎn)換成?復數(shù)型.

  • __oct__(self)

  • 轉(zhuǎn)換成八進制.

  • __hex__(self)

  • 轉(zhuǎn)換成十六進制.

  • __index__(self)

  • 當對象被切片時轉(zhuǎn)換成int型。如果你定義了一個可能被用來做切片操作的數(shù)值型,你就應該定義__index__.

  • __trunc__(self)

  • 當 math.trunc(self) 使用時被調(diào)用.__trunc__返回自身類型的整型截取 (通常是一個長整型).

  • __coerce__(self, other)

  • 執(zhí)行混合類型的運算,如果轉(zhuǎn)換不能完成,應該返回None;否則,要返回一對兩個元數(shù)的元組self和other, 被操作成同類型。

?

表示你的類

用一個字符串來表示一個類往往會非常有用。在Python中,有很多你可以在類定義中實施的方法來自定義內(nèi)置函數(shù)的返回值以表示出你所寫出的類的某些行為。

  • __str__(self)?

  • 定義當?str()?被你的一個類的實例調(diào)用時所要產(chǎn)生的行為。

  • __repr__(self)

  • 定義?當?repr()??被你的一個類的實例調(diào)用時所要產(chǎn)生的行為。?str()??repr()?的主要區(qū)別是其目標群體。?repr()?返回的是機器可讀的輸出,而?str()?返回的是人類可讀的。?

  • __unicode__(self)

  • 定義當?unicode() 被你的一個類的實例調(diào)用時所要產(chǎn)生的行為。?unicode()??str()?很相似,但是返回的是unicode字符串。注意,如果對你的類調(diào)用?str()?然而你只定義了?__unicode__()?,那么其將不會工作。你應該定義?__str__()?來確保調(diào)用時能返回正確的值,并不是每個人都有心情去使用unicode。

  • __format__(self, formatstr)

  • 定義當你的一個類的實例被用來用新式的格式化字符串方法進行格式化時所要產(chǎn)生的行為。例如,?"Hello, {0:abc}!".format(a) 將會導致調(diào)用?a.__format__("abc") 。這對定義你自己的數(shù)值或字符串類型是十分有意義的,你可能會給出一些特殊的格式化選項。

  • __hash__(self)?

  • 定義當?hash()被你的一個類的實例調(diào)用時所要產(chǎn)生的行為。它返回一個整數(shù),用來在字典中進行快速比較。請注意,這通常也承擔著實現(xiàn)__eq__。有下面這樣的規(guī)則:a == b 暗示著?hash(a) == hash(b) 。


  • __nonzero__(self)?

  • 定義當?bool() 被你的一個類的實例調(diào)用時所要產(chǎn)生的行為。本方法應該返回True或者False,取決于你想讓它返回的值。

  • __dir__(self)

  • 定義當 dir()?被你的一個類的實例調(diào)用時所要產(chǎn)生的行為。該方法應該返回一個屬性的列表給用戶,一般而言,實現(xiàn)?__dir__ 是不必要的,但是,如果你重新定義了__getattr__或__getattribute__(你將在下一節(jié)中看到)或者其它的動態(tài)生成屬性,那么它對你的類的交互使用是至關(guān)重要的。

  • __sizeof__(self)

  • 定義當?sys.getsizeof()?被你的一個類的實例調(diào)用時所要產(chǎn)生的行為。該方法應該以字節(jié)為單位,返回你的對象的大小。這通常對于以C擴展的形式實現(xiàn)的Python類更加有意義,其有助于理解這些擴展。

我們幾乎完成了對這些枯燥的魔法方法(并且沒有實例)的指導。現(xiàn)在,我們已經(jīng)提及到了一些較基本的魔法方法,到了該轉(zhuǎn)移到更高級內(nèi)容的時候了。

?

?

屬性訪問控制

很多用過其它語言的人抱怨Python缺乏對類真正的封裝(比如沒辦法定義private屬性和public的getter和settter)。但這不是真的啊:真相是Python通過“魔法”實現(xiàn)了大量的封裝,而不是使用明確的方法或字段修飾符。看一下吧:

  • __getattr__(self, name)

  • 你可以定義如何處理用戶試圖訪問一個不存在(不存在或還沒創(chuàng)建)屬性的行為。這對于捕獲或者重定向一般的拼寫錯誤非常有用,給出訪問了不能訪問的屬性的警告(如果你愿意,你還可以推斷并返回那個屬性。),或者巧妙地處理一個AttributeError異常。它只有在一個不存在的屬性被訪問的情況下才被調(diào)用,然而,這并不是一個真正封裝的方案。?

  • __setattr__(self, name, value)

  • 與__getattr__不同,__setattr__是一個真正的封裝方案。它允許你定義當給一個存在或不存在的屬性賦值時的行為,意味著對任何屬性值的改變你都可以定義一個規(guī)則。可是,你得小心使用__setattr__,在這個清單結(jié)尾的例子會向你說明。

  • __delattr__

  • 它與__setattr__非常像, 只不過是用來刪除而不是設(shè)置屬性。 __detattr__需要預防措施,就像setattr一樣,當被調(diào)用時可能會引起無限遞歸(當__delattr__已經(jīng)實現(xiàn)時,調(diào)用 del self.name 就會引起無限的遞歸)。

  • __getattribute__(self, name)

  • ?__getattribute__相當適合它的同伴__setattr__和__delattr__.但我卻不建議你使用它。__getattribute__只有在新風格的類中才會被使用(所有的新風格類在Python最新的版本中,在老版本中,你可以子類化object來獲得一個新風格類。它允許你定義一條規(guī)則來處理無論什么時候?qū)傩灾当辉L問時的行為。比如類似于由于其它的伙伴犯錯而引起的無限遞歸(這時你就可以調(diào)用基類的__getattribute__方法來阻止它)。它也避免了對__getattr__的依賴,當__getattribute__方法已經(jīng)實現(xiàn)的時候,__getattr__只有在__getattribute__被明確的調(diào)用或拋出一個AttributeError異常的時候才會被調(diào)用。這個方法能被使用(畢竟,這是你的選擇),但是我不推薦它,因為它很少使用并且運行的時候很難保證沒有BUG。?


如果定義了任何屬性訪問控制方法,容易產(chǎn)生錯誤。思考下面這個例子:def?__setattr__(self,?name,?value):
????self.name?=?value
????#?since?every?time?an?attribute?is?assigned,?__setattr__()?is?called,?this
????#?is?recursion.
????#?so?this?really?means?self.__setattr__('name',?value).?Since?the?method
????#?keeps?calling?itself,?the?recursion?goes?on?forever?causing?a?crashdef?__setattr__(self,?name,?value):
????self.__dict__[name]?=?value?#?assigning?to?the?dict?of?names?in?the?class
????#?define?custom?behavior?here


再次證明了Python的魔法方法是難以置信的強大,但強大的力量也需要強大的責任。如果你不想運行時中斷你的代碼,那了解如何適當?shù)厥褂媚Хǚ椒ň头浅V匾病?/p>

我們從Python中定制的屬性訪問中學到了什么?它們不是被輕易使用的。事實上,它有點過分強大并且違反直覺。但它們存在的原因是用來止癢的:Python不阻止你制造遭糕東西,但可能會讓它變的困難。自由是最重要的東西,所以你可做任何你想做的事情。這里有一個例子,展示了一些特殊的屬性訪問控制行為。(注意我們使用super,因為不是所有的類都有__dict__屬性):

class?AccessCounter(object):
????'''A?class?that?contains?a?value?and?implements?an?access?counter.????The?counter?increments?each?time?the?value?is?changed.'''

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

????def?__setattr__(self,?name,?value):
????????if?name?==?'value':
????????????super(AccessCounter,?self).__setattr__('counter',?self.counter?+?1)
????????#?Make?this?unconditional.
????????#?If?you?want?to?prevent?other?attributes?to?be?set,?raise?AttributeError(name)
????????super(AccessCounter,?self).__setattr__(name,?value)

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

自定義序列

有很多辦法能讓你的Python類使用起來就像內(nèi)置的序列(dict,tuple,list,string等)。Python里有一些目前我最喜歡的辦法,因為它們給你的控制到了荒謬的程度并且神奇地使得大量的全局函數(shù)優(yōu)雅地工作在你類的實例當中。但是在深入講這些好東西之前,我們先介紹下需求。

需求

在討論在Python中創(chuàng)建你自己的序列也是時候談談協(xié)議了。在其他語言中協(xié)議有點類似于接口,因為你必須實現(xiàn)一系列的方法。然而,在Python中協(xié)議是完全不正式的,不需要顯式的聲明去實現(xiàn)它,它更像是一種指導原則。

為什么我們要談論協(xié)議呢?因為在Python中實現(xiàn)自定義容器類型涉及到這些協(xié)議的使用。首先,有一些協(xié)議用于定義不變?nèi)萜?#xff1a;為了實現(xiàn)一個不變窗口,你只需定義__len__和__getitem__方法(接下來會細說)。不變?nèi)萜鞯膮f(xié)議要求所有的類加上一個?__setitem____delitem__方法。最后,如果你想讓你的容器支持遍歷,你必須定義__iter__方法,它返回一個iterator。這個iterator必須遵守iterator的協(xié)議,它要求iterator類里面有__iter__方法(返回自身)和next方法。

?

?

?

容器后的魔法

不需要再等待了,這里就是容器所使用的一些魔法方法。

  • __len__(self)

  • 返回容器的長度。對于可變和不可變?nèi)萜鞯膮f(xié)議,這都是其中的一部分。

  • __getitem__(self, key)

  • 定義當某一項被訪問時,使用self[key]所產(chǎn)生的行為。這也是不可變?nèi)萜骱涂勺內(nèi)萜鲄f(xié)議的一部分。如果鍵的類型錯誤將產(chǎn)生TypeError;如果key沒有合適的值則產(chǎn)生KeyError。

  • __setitem__(self, key, value)

  • 定義當一個條目被賦值時,使用self[nkey] = value所產(chǎn)生的行為。這也是協(xié)議的一部分。而且,在相應的情形下也會產(chǎn)生KeyError和TypeError。

  • __delitem__(self, key)

  • 定義當某一項被刪除時所產(chǎn)生的行為。(例如del self[key])。這只是可變?nèi)萜鲄f(xié)議的一部分。當你使用一個無效的鍵時必須拋出適當?shù)漠惓!?/p>

  • __iter__(self)

  • 返回一個容器迭代器,很多情況下會返回迭代器,尤其是當內(nèi)置的iter()方法被調(diào)用的時候,以及當使用for x in container:方式循環(huán)的時候。迭代器是它們本身的對象,它們必須定義返回self的__iter__方法。

  • __reversed__(self)

  • 實現(xiàn)當reversed()被調(diào)用時的行為。應該返回序列反轉(zhuǎn)后的版本。僅當序列可以是有序的時候?qū)崿F(xiàn)它,例如對于列表或者元組。

  • __contains__(self, item)

  • 定義了調(diào)用in和not in來測試成員是否存在的時候所產(chǎn)生的行為。你可能會問為什么這個不是序列協(xié)議的一部分?因為當__contains__沒有被定義的時候,Python會迭代這個序列,并且當找到需要的值時會返回True。

  • __missing__(self, key)

  • 其在dict的子類中被使用。它定義了當一個不存在字典中的鍵被訪問時所產(chǎn)生的行為。(例如,如果我有一個字典d,當"george"不是字典中的key時,使用了d["george"],此時d["george"]將會被調(diào)用)。

?

?

?

一個例子

對于我們的例子, 讓我們看看一個列表,它實現(xiàn)了一些功能結(jié)構(gòu),你可能在其他在其他程序中用到 (例如Haskell).

class?FunctionalList:
????'''A?class?wrapping?a?list?with?some?extra?functional?magic,?like?head,????tail,?init,?last,?drop,?and?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):
????????#?if?key?is?of?invalid?type?or?value,?the?list?values?will?raise?the?error
????????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?FunctionalList(reversed(self.values))

????def?append(self,?value):
????????self.values.append(value)
????def?head(self):
????????#?get?the?first?element
????????return?self.values[0]
????def?tail(self):
????????#?get?all?elements?after?the?first
????????return?self.values[1:]
????def?init(self):
????????#?get?elements?up?to?the?last
????????return?self.values[:-1]
????def?last(self):
????????#?get?last?element
????????return?self.values[-1]
????def?drop(self,?n):
????????#?get?all?elements?except?first?n
????????return?self.values[n:]
????def?take(self,?n):
????????#?get?first?n?elements
????????return?self.values[:n]

?

這樣你擁有了它,如何實現(xiàn)自己的序列的,有點用的例子。當然,也有更有用的應用程序的自定義序列,但在標準庫中,已經(jīng)有相當多的實現(xiàn)(包括電池,對吧?),像Counter,OrderedDict,和NamedTuple。

反射

你也可以控制怎么使用內(nèi)置在函數(shù)sisinstance()和issubclass()方法 反射定義魔法方法. 這個魔法方法是:

  • __instancecheck__(self, instance)

  • 檢查對象是否是您定義的類的一個實例(例.isinstance(instance, class).

  • __subclasscheck__(self, subclass)

  • 檢查類是否是你定義類的子類 (例.issubclass(subclass, class)).

這些魔法方法的用例看起來很小, 并且確實非常實用. 我不想花太多時間在反射魔法方法上,因為它們不是非常重要, 但是它們反應了關(guān)于面向?qū)ο蟪绦蛏弦恍┲匾臇|西在Python上,并且總的來說Python: 總是一個簡單的方法去找某些事情, 即使是沒有必要的. 這些魔法方法可能看起來不是很有用, 但是一旦你需要它們,你會感到慶幸它們的存在 (并且為自己閱讀了本指南高興!).

可調(diào)用對象

你也許已經(jīng)知道,在Python中,方法是最高級的對象。這意味著他們也可以被傳遞到方法中,就像其他對象一樣。這是一個非常驚人的特性。

在Python中,一個特殊的魔法方法可以讓類的實例的行為表現(xiàn)的像函數(shù)一樣,你可以調(diào)用它們,將一個函數(shù)當做一個參數(shù)傳到另外一個函數(shù)中等等。這是一個非常強大的特性,其讓Python編程更加舒適甜美。

  • __call__(self, [args...])

  • 允許一個類的實例像函數(shù)一樣被調(diào)用。實質(zhì)上說,這意味著?x()??x.__call__()?是相同的。注意?__call__ 的參數(shù)可變。這意味著你可以定義?__call__?為其他你想要的函數(shù),無論有多少個參數(shù)。

__call__ 在那些類的實例經(jīng)常改變狀態(tài)的時候會非常有效。“調(diào)用”這個實例是一種改變這個對象狀態(tài)的直接和優(yōu)雅的做法。比如這樣一個例子,一個類表示了一個實體在飛機上的位置:?

class?Entity:
????'''表示一個實體的類。調(diào)用該類以更新實體的位置。'''

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

????def?__call__(self,?x,?y):
????????'''Change?the?position?of?the?entity.'''
????????self.x,?self.y?=?x,?y

????#?snip...

?

會話管理器

在Python 2.5中,為了代碼重用而新定義了一個關(guān)鍵字with,其也就帶來了一種with語句。會話管理在Python中并不罕見(之前是作為庫的一部分而實現(xiàn)的),不過直到PEP 343被接受后,其就作為了一種一級語言結(jié)構(gòu)。你也許在之前看到過這樣的語句

with?open('foo.txt')?as?bar:
????#?執(zhí)行一些針對bar的操作

會話管理器通過包裝一個with語句來設(shè)置和清理相應對象的行為。會話管理器的行為通過兩個魔方方法來決定:

  • __enter__(self)

  • 定義了當使用with語句的時候,會話管理器在塊被初始創(chuàng)建事要產(chǎn)生的行為。請注意,__enter__的返回值與with語句的目標或者as后的名字綁定。

  • __exit__(self, exception_type, exception_value, traceback)

  • 定義了當一個代碼塊被執(zhí)行或者終止后,會話管理器應該做什么。它可以被用來處理異常、執(zhí)行清理工作或做一些代碼塊執(zhí)行完畢之后的日常工作。如果代碼塊執(zhí)行成功,exception_type,exception_value,和traceback將會為None。否則,你可以選擇處理這個異常或者是直接交給用戶處理。如果你想處理這個異常的話,請確保__exit__在所有語句結(jié)束之后返回True。如果你想讓異常被會話管理器處理的話,那么就讓其產(chǎn)生該異常。

__enter__和__exit__對于那些定義良好以及有普通的啟動和清理行為的類是很有意義的。你也可以使用這些方法來創(chuàng)建一般的可以包裝其它對象的會話管理器。下面是一個例子:

class?Closer:
????'''通過with語句和一個close方法來關(guān)閉一個對象的會話管理器。'''

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

????def?__enter__(self):
????????return?self.obj?#?bound?to?target

????def?__exit__(self,?exception_type,?exception_val,?trace):
????????try:
???????????self.obj.close()
????????except?AttributeError:?#?obj?isn't?closable
???????????print?'Not?closable.'
???????????return?True?#?exception?handled?successfully

?

下面是一個實際使用Closer的例子,使用一個FTP連接來證明(一個可關(guān)閉的套接字):

view sourceprint?
01>>>?from?magicmethods?import?Closer
02>>>?from?ftplib?import?FTP
03>>>?with?Closer(FTP('ftp.somesite.com'))?as?conn:
04...?????conn.dir()
05...
06>>>?conn.dir()
07>>>?with?Closer(int(5))?as?i:
08...?????i?+=?1
09...
10Not?closable.
11>>>?i
126

看到我們的包裝器如何友好地處理恰當和不不恰當?shù)男袨榱藛?#xff1f;這是會話管理器和魔法方法的強大功能。請注意,Python標準庫包括了一個叫作?contextlib?的模塊,其包含了一個會話管理器,contextlib.closing()完成了類似的功能(當一個對象沒有close()方法時則沒有任何處理)。

抽象基類

見http://docs.python.org/2/library/abc.html。

創(chuàng)建描述器對象

描述器是通過獲取、設(shè)置以及刪除的時候被訪問的類。當然也可以改變其它的對象。描述器并不是獨立的。相反,它意味著被一個所有者類持有。當創(chuàng)建面向?qū)ο蟮臄?shù)據(jù)庫或者類,里面含有相互依賴的屬相時,描述器將會非常有用。一種典型的使用方法是用不同的單位表示同一個數(shù)值,或者表示某個數(shù)據(jù)的附加屬性(比如坐標系上某個點包含了這個點到原點的距離信息)。

為了成為一個描述器,一個類必須至少有__get__,__set__,__delete__方法被實現(xiàn),讓我們看看這些魔法方法:

  • __get__(self, instance, owner)

  • 定義了當描述器的值被取得的時候的行為。instance是擁有該描述器對象的一個實例。owner是擁有者本身。

  • __set__(self, instance, value)

  • 定義了當描述器的值被改變的時候的行為。instance是擁有該描述器類的一個實例。value是要設(shè)置的值。

  • __delete__(self, instance)

  • 定義了當描述器的值被刪除的時候的行為。instance是擁有該描述器對象的一個實例。

下面是一個描述器的實例:單位轉(zhuǎn)換。?

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.2808class?Distance(object):
????'''用米和英寸來表示兩個描述器之間的距離。'''
????meter?=?Meter()
????foot?=?Foot()

?

復制

有時候,尤其是當你在處理可變對象時,你可能想要復制一個對象,然后對其做出一些改變而不希望影響原來的對象。這就是Python的copy所發(fā)揮作用的地方。然而(幸運的是),Python的模塊并不是“感性”的,所以我們沒必要擔心一個基于Linux的機器會突然開始工作,但是我們確實需要告訴Python如何高效地復制一些東西。

  • __copy__(self)

  • 定義了當對你的類的實例調(diào)用copy.copy()時所產(chǎn)生的行為。copy.copy()返回了你的對象的一個淺拷貝——這意味著,當實例本身是一個新實例時,它的所有數(shù)據(jù)都被引用了——例如,當一個對象本身被復制了,它的數(shù)據(jù)仍然是被引用的(因此,對于淺拷貝中數(shù)據(jù)的更改仍然可能導致數(shù)據(jù)在原始對象的中的改變)。

  • __deepcopy__(self, memodict={})

  • 定義了當對你的類的實例調(diào)用copy.deepcopy()時所產(chǎn)生的行為。copy.deepcopy()返回了你的對象的一個深拷貝——對象和其數(shù)據(jù)都被拷貝了。memodict是對之前被拷貝的對象的一個緩存——這優(yōu)化了拷貝過程并且阻止了對遞歸數(shù)據(jù)結(jié)構(gòu)拷貝時的無限遞歸。當你想要進行對一個單獨的屬性進行深拷貝時,調(diào)用copy.deepcopy(),并以memodict為第一個參數(shù)。

這些魔法方法的使用例子都是什么?答案和以往一樣,當你需要進行和默認行為相比,更細粒度的控制時使用這些方法。例如,你想要復制一個對象,其中以字典的形式(其可能會很大)存儲了一個緩存,那么對緩存進行復制可能是沒有意義的——如果當該緩存可以在內(nèi)存中被多個實例共享,那么對其進行復制就確實是沒意義的。

?

?

Pickling 序列化你的對象

如果你打算與其他python發(fā)燒友交換數(shù)據(jù),那你一定應該聽說過pickling。Pickling是一個將Python數(shù)據(jù)結(jié)構(gòu)進行序列化的工具,它對于存儲、重新取回一個對象這類工作來說真是難以置信的有用。但它也是一些擔心和誤解的源頭。

Pickling是如此的重要,以至于它不僅僅擁有自己的模塊(pickling),而且還有自己的協(xié)議和“魔術(shù)”方法。但首先,我們先簡單地介紹一下Pickling如何序列化已存在的類型(如果你已經(jīng)知道這些了,那么請自行飄過)。?

Pickling: 趕快到鹽水中泡泡

(譯者注:pickle是用來直接保存Python對象的模塊,在英文中有“腌制”的意思)

讓我們深入挖掘pickling方法。假設(shè)你想保存一個字典并在之后檢索它:你可以把它寫入一個文件中,小心確保其有正確的語法,之后用exec()或者讀取文件來檢索它。但這很有可能是相當危險的:如果你將重要數(shù)據(jù)保存在純文本中,它可能會損壞或者發(fā)生各種各樣的改變,有些會讓你的程序崩潰,有些甚至會在你的電腦上運行惡意代碼。因此,我們應該使用 pickle方法:?

import?pickle
data?=?{'foo':?[1,?2,?3],
????????'bar':?('Hello',?'world!'),
????????'baz':?True}
jar?=?open('data.pkl',?'wb')
pickle.dump(data,?jar)?#?write?the?pickled?data?to?the?file?jar
jar.close()

幾個小時之后,我們希望找回這些數(shù)據(jù),現(xiàn)在我們只需unpickle它:

import?pickle
pkl_file?=?open('data.pkl',?'rb')?#?connect?to?the?pickled?data
data?=?pickle.load(pkl_file)?#?load?it?into?a?variable
print?data
pkl_file.close()

?

發(fā)生了什么?正如你所想的那樣,我們現(xiàn)在找回了data。

現(xiàn)在,我們要注意一點:pickle并不完美。被pickle序列化的文件很容易被意外或是有意損壞。pickle模塊可能比一般的純文本文件要來的安全,但它仍然可能會被利用去運行惡意代碼。而且它在各個Python版本之間是不兼容的,所以不要傳送pkl文件并妄想其他人可以打開它。但是,pickle確實是處理緩存和其他序列化任務的強有力工具。

?

?

?

用Pickle序列化你的對象

pickle模塊不僅可以用于內(nèi)建類型,它還可以以用于序列化任何遵循pickle協(xié)議的類。pickle協(xié)議為Python對象定義了四個可選的方法,你可以重載這些方法來定義它們的行為(這和C擴展有些不同,但這不在我們的討論范圍之內(nèi)):

  • __getinitargs__(self)

  • 如果你想在你的類被unpickle的時候執(zhí)行__init__方法,你可以重載__getinitargs__方法,它會返回一個元組,包含你想傳給__init__方法的參數(shù)。注意,這種方法只適用于舊式的Python類型(譯者注:區(qū)別于2.2中引入的新式類)。

  • __getnewargs__(self)

  • 對于新式類,在unpickle的時候你可以決定傳給__new__方法的參數(shù)。以上方法可以返回一個包含你想傳給__new__方法的參數(shù)元組。

  • __getstate__(self)

  • 除了儲存__dict__中的原來的那些變量,你可以自定義使用pickle序列化對象時想要儲存的額外屬性。這些屬性將在你unpickle文件時被__setstate__方法使用。

  • __setstate__(self, state)

  • 當文件被unpickle時,其中保存的對象屬性不會直接被寫入對象的__dict中,而是會被傳入這個方法。這個方法和__getstate__是配套的:當他們都被定義了的時候,你可以任意定義對象被序列化存儲時的狀態(tài)。?

  • __reduce__(self)

  • 當你定義擴展類(使用C語言實現(xiàn)的Python擴展類)時,可以通過實現(xiàn)__reduce__函數(shù)來控制pickle的數(shù)據(jù)。如果__reduce__()方法被定義了,在一個對象被pickle時它將被調(diào)用。如果它返回一個字符串,那么pickle在將在全局空間中搜索對應名字的對象進行pickle;它還可以返回一個元組,包含2-5個元素:?一個可以用來重建該對象的可調(diào)用對象,一個包含有傳給該可調(diào)用對象參數(shù)的元組,傳給__setstate__方法的參數(shù)(可選),一個用于待pickle對象列表的迭代器(譯者注:這些對象會被append到原來對象的后面)(可選)調(diào)用對象,一個包含有傳給該可調(diào)用對象參數(shù)的元組,傳給__setstate__方法的參數(shù)(可選),一個用于待pickle對象列表的迭代器(譯者注:這些對象會被append到原來對象的后面)(可選),一個用于待pickle的字典的迭代器(可選)。

  • __reduce_ex__(self)

  • __reduce_ex__是為兼容性而設(shè)計的。如果它被實現(xiàn)了,__reduce_ex__將會取代__reduce__在pickle時被執(zhí)行。__reduce__可以同時被實現(xiàn)以支持那些不支持__reduce_ex__的老版本pickling API。

(譯者注:這段說的不是非常清楚,感興趣可以去看文檔,一般來說只要使用上一節(jié)中的方法就足夠了,注意在反序列化之前要先有對象的定義,否則會出錯)

一個例子

我們以Slate為例,這一段記錄一個值以及這個值是何時被寫入的程序,但是,這個Slate有一點特殊的地方,就是當前值不會被保存。?

import?time

class?Slate:
????'''Class?to?store?a?string?and?a?changelog,?and?forget?its?value?when????pickled.'''

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

????def?change(self,?new_value):
????????#?Change?the?value.?Commit?last?value?to?history
????????self.history[self.last_change]?=?self.value
????????self.value?=?new_value
????????self.last_change?=?time.asctime()

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

????def?__getstate__(self):
????????#?Deliberately?do?not?return?self.value?or?self.last_change.
????????#?We?want?to?have?a?"blank?slate"?when?we?unpickle.
????????return?self.history

????def?__setstate__(self,?state):
????????#?Make?self.history?=?state?and?last_change?and?value?undefined
????????self.history?=?state
????????self.value,?self.last_change?=?None,?None

總結(jié)

這份指南的目的是希望為所有人帶來一些知識,即使你是Python大牛或者精通面向?qū)ο箝_發(fā)。如果你是一個Python初學者,閱讀這篇文章之后,你已經(jīng)獲得了編寫豐富,優(yōu)雅,靈活的類的知識基礎(chǔ)了。如果你是一個有一些經(jīng)驗的Python程序員,你可能會發(fā)現(xiàn)一些能讓你寫的代碼更簡潔的方法。如果你是一個曾經(jīng)使用過Python的程序員,該文可能會幫助你知曉一些新的概念和方法以及幫助你減少編寫代碼量的方式。如果你是一個Python專家,該文會幫助你想起來一些你已經(jīng)遺忘的只是,或者一些你還沒聽說過的新功能。不慣你現(xiàn)在有多少經(jīng)驗,我希望這次對于Python特殊方法的旅程是真正的一次神奇之旅。(雙關(guān)語的感覺真是棒!)?

?

?

附錄 1: 如何調(diào)用Magic Method

一些magic method已經(jīng)映射到自帶的方法(built-in functions);這種情況下如何調(diào)用他們是顯而易見的。然而,在其他情況下,調(diào)用它們就不那么容易了。本附錄致力于展示能夠調(diào)用magic method的一些不被察覺的語法。

Magic Method????????????何時被調(diào)用(例子)????????????????Explanation
__new__(cls [,...])instance = MyClass(arg1, arg2)?__new__?is called on instance creation
__init__(self [,...])instance = MyClass(arg1, arg2)__init__?is called on instance creation
__cmp__(self, other)self == other,?self > other, etc.Called for any comparison
__pos__(self)+selfUnary plus sign
__neg__(self)-selfUnary minus sign
__invert__(self)~selfBitwise inversion
__index__(self)x[self]Conversion when object is used as index
__nonzero__(self)bool(self)Boolean value of the object
__getattr__(self, name)self.name # name doesn't existAccessing nonexistent attribute
__setattr__(self, name, val)self.name = valAssigning to an attribute
__delattr__(self, name)del self.nameDeleting an attribute
__getattribute__(self, name)self.nameAccessing any attribute
__getitem__(self, key)self[key]Accessing an item using an index
__setitem__(self, key, val)self[key] = valAssigning to an item using an index
__delitem__(self, key)del self[key]Deleting an item using an index
__iter__(self)for x in selfIteration
__contains__(self, value)value in self,value not in selfMembership tests using?in
__call__(self [,...])self(args)"Calling" an instance
__enter__(self)with self as x:with?statement context managers
__exit__(self, exc, val, trace)with self as x:with?statement context managers
__getstate__(self)pickle.dump(pkl_file, self)Pickling
__setstate__(self)data = pickle.load(pkl_file)Pickling

希望這個表能夠解決你可能會遇到的哪個語法調(diào)用哪個magic method的問題。

附錄?2: Python 3中的改動?

這里我們列舉出一些Python?3與2.x在對象模型上主要的的不同之處。

  • 因為Python?3中string和unicode直接已經(jīng)沒有差別,__unicode__已經(jīng)不存在了,并且__bytes__(它的行為與__str__和__unicode__類似)成為新的自帶方法來構(gòu)造byte數(shù)組

  • 因為Python 3里面的division默認變成了true division,__div__在Python3中不存在了。

  • __coerce__被去除掉了是因為它與其他magic method冗余并且造成了行為混淆。

  • __cmp__被去除掉了是因為它與其他magic method冗余。

  • __nonzero__被重命名為__bool__

?

?

?

?

?

總結(jié)

以上是生活随笔為你收集整理的Python 的 Magic Methods 指南(转)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 黄色大片日本 | 国内自拍偷拍视频 | 91色在线观看 | 国产精品电影一区二区三区 | 在线看片国产 | 中文字幕天堂av | 卡一卡二在线视频 | 午夜高清| 欧美一级三级 | 操校花视频| 中文字幕2018 | 美女视频黄a视频全免费观看 | 国产理伦 | 小辣椒福利视频导航 | 好吊妞精品 | 神马久久久久 | 欧美xx视频 | 亚洲无码精品在线播放 | 免费看一级片 | 亚洲色网址| 国产精品久久久久久无人区 | 91性高潮久久久久久久 | 欧美色精品在线 | 嫩草视频在线观看免费 | 亚洲女优在线观看 | 欧美巨大荫蒂茸毛毛人妖 | 欧美日韩国产成人 | 亚洲国产日韩欧美在线观看 | 97国产在线播放 | 四虎成人在线观看 | 成年人视频免费 | av在线激情 | 亚洲天堂2021av | 青青青手机在线视频 | 国产一二三四在线 | 久久九九久精品国产免费直播 | 免费激情小视频 | 四虎8848精品成人免费网站 | 日本熟女一区二区 | 在线观看欧美成人 | 亚洲视频在线观看 | 精品久操| 揄拍成人国产精品视频 | 国产午夜视频在线 | 国产做爰全免费的视频软件 | 日韩色区| 激情四射av | 污视频网站免费观看 | 日韩久久视频 | 亚洲国产无码精品 | 91精品视频在线 | 人妻互换免费中文字幕 | 久久久久久av | av成人免费在线观看 | 99热手机在线观看 | 中文字幕在线2021 | 污黄网站在线观看 | 午夜在线观看一区 | 久久久噜噜噜久久 | 蜜臀久久精品久久久用户群体 | 国产精品黄色 | 中文在线字幕 | aa片在线观看视频在线播放 | 亚洲色偷精品一区二区三区 | 亚洲欧美视频在线观看 | 含羞草一区二区 | 日韩美女激情视频 | 四虎免看黄 | 黄网站在线观看 | 日韩性网 | 日韩操比 | 日本h视频在线观看 | 九九热综合 | 亚洲一二三区视频 | 亚洲精品无 | av免播放器在线观看 | 欧美男女交配 | 熟妇一区二区三区 | 奇米网久久| 91av福利 | 蜜桃色一区二区三区 | 精品www久久久久久奶水 | 国产乱淫av片免费 | 亚洲一区日本 | 蜜桃av影视 | 亚洲一区二区三区四区 | 日韩中文字幕一区 | 天天看片中文字幕 | 最色网站 | 天天操操操操操 | www.激情.com| 啪视频在线观看 | 超碰免费91| 亚洲每日在线 | 99免费观看视频 | 欧美日韩少妇 | 日本黄网在线观看 | 轮乱| 性色av无码久久一区二区三区 |