<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          如何寫出令人驚嘆的Python類

          共 3482字,需瀏覽 7分鐘

           ·

          2021-12-01 20:40

          我身邊有搞機(jī)器學(xué)習(xí)的,也有數(shù)據(jù)科學(xué)家,Python 是他們的首選語言。然而,他們并非每個都是經(jīng)驗豐富的 Python 開發(fā)人員,他們也不太可能掌握 Python 提供的所有優(yōu)秀功能。這當(dāng)然是可以理解的,但同時也是不幸的。為什么?因為了解語言的細(xì)節(jié)需要編寫代碼......

          這就是為什么我想為提升 Python 技能的人提供一些幫助,這樣你就可以編寫更多出色的代碼,也許會給您的伙伴或同事留下深刻印象,并從中獲得更多樂趣!具體來說,在這篇文章中,我想談?wù)勅绾问褂?Python 中的魔術(shù)方法,寫出令人驚嘆的 class,讓我們開始吧。

          什么是魔術(shù)方法

          魔術(shù)方法首先是方法,是屬于類的函數(shù)。它們既可以是實例方法,也可以是類方法。你可以輕松識別它們,因為它們都以雙下劃線開頭和結(jié)尾,即它們都看起來像 __actual_name__。

          重要的是,魔術(shù)方法不可以直接調(diào)用!當(dāng)然,你可以這樣做并寫一些類似 YourClass().__actual_name__() 的東西,但請不要直接調(diào)用。

          那么魔術(shù)方法是如何調(diào)用的呢?它們會在適當(dāng)?shù)臅r候被調(diào)用,比如,調(diào)用 str(YourClass()) 將調(diào)用魔術(shù)方法 __str__ 或 YourClass() + YourClass() 將調(diào)用 __add__,如果你已經(jīng)實現(xiàn)了這兩個魔術(shù)方法。

          那么,魔法方法有什么用?它讓我們能夠編寫可與 python 內(nèi)置方法一起使用的類,這樣寫出的代碼更易讀和更少的冗余。

          為了強(qiáng)調(diào)魔術(shù)方法的有用性,并了解在進(jìn)行機(jī)器學(xué)習(xí)或數(shù)據(jù)科學(xué)時如何從使用它們中受益,讓我們舉一個具體的例子。

          實例:自定義范圍的 datetime 類

          下面的代碼展示了如何使用魔術(shù)方法編寫類似于內(nèi)置 range 函數(shù)的 DateTimeRange 類,代碼如下:

          from?datetime?import?datetime,?timedelta
          from?typing?import?Iterable
          from?math?import?ceil


          class?DateTimeRange:
          ????def?__init__(self,?start:?datetime,?end_:datetime,?step:timedelta?=?timedelta(seconds=1)):
          ????????self._start?=?start
          ????????self._end?=?end_
          ????????self._step?=?step

          ????def?__iter__(self)?->?Iterable[datetime]:
          ????????point?=?self._start
          ????????while?point?????????????yield?point
          ????????????point?+=?self._step

          ????def?__len__(self)?->?int:
          ????????return?ceil((self._end?-?self._start)?/?self._step)

          ????def?__contains__(self,?item:?datetime)?->?bool:
          ????????mod?=?divmod(item?-?self._start,?self._step)?#?divmod?return?the?tuple?(x//y,?x%y).??Invariant:?div*y?+?mod?==?x.
          ????????return?item?>=?self._start?and?item?
          ????def?__getitem__(self,?item:?int)?->?datetime:
          ????????n_steps?=?item?if?item?>=?0?else?len(self)?+?item
          ????????return_value?=?self._start?+?n_steps?*?self._step
          ????????if?return_value?not?in?self:
          ????????????raise?IndexError()

          ????????return?return_value
          ???
          ????def?__str__(self):
          ????????return?f"Datetime?Range?[{self._start},?{self._end})?with?step?{self._step}"

          def?main():
          ????my_range?=?DateTimeRange(datetime(2021,1,1),?datetime(2021,12,1),?timedelta(days=12))
          ????print(my_range)
          ????print(f"{len(my_range)?==?len(list(my_range))?=?}")
          ????print(f"{my_range[-2]?in?my_range?=?}")
          ????print(f"{my_range[2]?+?timedelta(seconds=12)?in?my_range?=?}")
          ????
          ????for?r?in?my_range:
          ???? print(r)
          ????????#do_something(r)

          if?__name__?==?'__main__':
          main()

          先看下運行結(jié)果:

          看到運行結(jié)果,你也許可以更快的理解類 DateTimeRange 的作用,代碼有點多,不過別擔(dān)心,我會解釋。

          總的來說,上述代碼實現(xiàn)了六種不同的魔法方法:

          1、__init__ 方法。你肯定知道,此方法主要用于初始化您的類的實例屬性。在這里,我們將范圍類的開始和結(jié)束與步長一起傳給 DateTimeRange。

          2、__iter__ 方法。for 循環(huán)或 list(DateTimeRange()) 時會調(diào)用。這可能是最重要的一個,因為它生成了我們?nèi)掌跁r間范圍內(nèi)的所有元素。這個函數(shù)是一個所謂的生成器函數(shù),它一次創(chuàng)建一個元素,將它交給調(diào)用者,并允許調(diào)用者處理它。它會這樣做,直到到達(dá)范圍的末尾。在查看 yield 關(guān)鍵字時,您可以輕松識別生成器函數(shù)。此語句暫停函數(shù)保存其所有狀態(tài),然后在連續(xù)調(diào)用時從那里繼續(xù)。這允許您一次使用一個元素并使用它,而無需您將每個元素都放在內(nèi)存中。

          當(dāng)范圍比較大時,將所有內(nèi)容都放在內(nèi)存中會變得非常占用內(nèi)存。例如,執(zhí)行 list(DateTimeRange(datetime(1900,1,1), datetime(2000,1,1)) 時會將 3184617600 個日期時間放入內(nèi)存。太大了,然而 ,使用生成器您可以輕松地一一處理這些元素。

          3、現(xiàn)在你已經(jīng)看到它不是列表或元組。然而,為了處理這個 DateTimeRange 類,就像它是一個列表或元組一樣,我添加了另外三個神奇的方法,即 __len__ 、 __contains____getitem__

          使用 __len__ ,您可以通過調(diào)用 len(my_range) 找出屬于您的范圍的元素數(shù)量。例如,當(dāng)?shù)性夭⑾胫酪呀?jīng)從所有可用元素中處理了多少元素時,這會變得非常有用。它也可能告訴你,嘿,我要處理很多數(shù)據(jù),請喝杯咖啡。

          使用 __contains__,您可以使用 my_range 中的內(nèi)置語法元素檢查某個元素是否屬于您的范圍。給定實現(xiàn)的好處在于,這是使用純數(shù)學(xué)完成的,無需將給定元素與范圍內(nèi)的所有元素進(jìn)行比較。這意味著檢查元素是否在您的范圍內(nèi)是一個恒定時間操作,不依賴于實際范圍實例的大小。同樣,這對于我們在處理數(shù)據(jù)時經(jīng)常看到的大范圍會變得很方便。

          使用 __getitem__ 您可以使用索引語法從對象中檢索條目。因此,可以通過 my_range[-1] 獲取我們范圍的最后一個元素。一般來說,使用 __getitem__ 可以編寫非常干凈和可讀的界面。

          4、__str__ ?方法的作用是將類的實例轉(zhuǎn)換為字符串。將實例轉(zhuǎn)換為字符串時自動調(diào)用該方法,例如調(diào)用 print(my_range) 或 str(my_range) 時就會調(diào)用__str__。

          最后的話

          本文分享了如何通過魔法方法編寫一個非常優(yōu)雅的類,魔術(shù)方法可在 Python 內(nèi)置的函數(shù)或操作中自動調(diào)用,可以讓我們編寫出可讀性、易用性更好的類,就像本文中的 DateTimeRange。

          如果覺得有幫助,還請點贊、轉(zhuǎn)發(fā)、在看,感謝你的支持。



          瀏覽 30
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  中国久久一级片 | 云南性老太HD大全 | 黑人操逼黑 | 日日干天天干天天舔 | 国产精品成人在线视频 |