<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 中類的構(gòu)造方法 __new__ 的妙用

          共 5251字,需瀏覽 11分鐘

           ·

          2021-10-22 14:57

          Python 的類中,所有以雙下劃線__包起來的方法,叫魔術(shù)方法,魔術(shù)方法在類或?qū)ο蟮哪承┦录l(fā)出后可以自動(dòng)執(zhí)行,讓類具有神奇的魔力,比如常見的構(gòu)造方法__new__、初始化方法__init__、析構(gòu)方法__del__,今天來聊一聊__new__的妙用,主要分享以下幾點(diǎn):

          • __new____init__ 的區(qū)別
          • 應(yīng)用1:改變內(nèi)置的不可變類型
          • 應(yīng)用2:實(shí)現(xiàn)一個(gè)單例
          • 應(yīng)用3:客戶端緩存
          • 應(yīng)用4:不同文件不同的解密方法
          • 應(yīng)用5:Metaclasses

          __new____init__ 的區(qū)別

          1、調(diào)用時(shí)機(jī)不同:new 是真正創(chuàng)建實(shí)例的方法,init 用于實(shí)例的初始化,new 先于 init 運(yùn)行。

          2、返回值不同,new 返回一個(gè)類的實(shí)例,而 init 不返回任何信息。

          3、new 是 class 的方法,而 init 是對(duì)象的方法。

          示例代碼:

          class?A:
          ????def?__new__(cls,?*args,?**kwargs):
          ????????print("new",?cls,?args,?kwargs)
          ????????return?super().__new__(cls)

          ????def?__init__(self,?*args,?**kwargs):
          ????????print("init",?self,?args,?kwargs)


          def?how_object_construction_works():
          ????x?=?A(1,?2,?3,?x=4)
          ????print(x)????
          ????print("===================")
          ????x?=?A.__new__(A,?1,?2,?3,?x=4)
          ????if?isinstance(x,?A):
          ????????type(x).__init__(x,?1,?2,?3,?x=4)
          ????print(x)

          if?__name__?==?"__main__":
          ????how_object_construction_works()

          上述代碼定義了一個(gè)類 A,在調(diào)用 A(1, 2, 3, x=4) 時(shí)先執(zhí)行 new,再執(zhí)行 init,等價(jià)于:

          x?=?A.__new__(A,?1,?2,?3,?x=4)
          if?isinstance(x,?A):
          ????type(x).__init__(x,?1,?2,?3,?x=4)

          代碼的運(yùn)行結(jié)果如下:

          new?'__main__.A'>?(1,?2,?3)?{'x':?4}
          init?<__main__.A?object?at?0x7fccaec97610>?(1,?2,?3)?{'x':?4}
          <__main__.A?object?at?0x7fccaec97610>
          ===================
          new?'__main__.A'>?(1,?2,?3)?{'x':?4}
          init?<__main__.A?object?at?0x7fccaec97310>?(1,?2,?3)?{'x':?4}
          <__main__.A?object?at?0x7fccaec97310>

          new 的主要作用就是讓程序員可以自定義類的創(chuàng)建行為,以下是其主要應(yīng)用場(chǎng)景:

          應(yīng)用1:改變內(nèi)置的不可變類型

          我們知道,元組是不可變類型,但是我們繼承 tuple ,然后可以在 new 中,對(duì)其元組的元素進(jìn)行修改,因?yàn)?new 返回之前,元組還不是元組,這在 init 函數(shù)中是無法實(shí)現(xiàn)的。比如說,實(shí)現(xiàn)一個(gè)大寫的元組,代碼如下:

          class?UppercaseTuple(tuple):
          ????def?__new__(cls,?iterable):
          ????????upper_iterable?=?(s.upper()?for?s?in?iterable)
          ????????return?super().__new__(cls,?upper_iterable)

          ????#?以下代碼會(huì)報(bào)錯(cuò),初始化時(shí)是無法修改的
          ????#?def?__init__(self,?iterable):
          ????#?????print(f'init?{iterable}')
          ????#?????for?i,?arg?in?enumerate(iterable):
          ????#?????????self[i]?=?arg.upper()

          if?__name__?==?'__main__':
          ????print("UPPERCASE?TUPLE?EXAMPLE")
          ????print(UppercaseTuple(["hello",?"world"]))

          #?UPPERCASE?TUPLE?EXAMPLE
          #?('HELLO',?'WORLD')

          應(yīng)用2:實(shí)現(xiàn)一個(gè)單例

          class?Singleton:
          ????_instance?=?None

          ????def?__new__(cls,?*args,?**kwargs):
          ????????if?cls._instance?is?None:
          ????????????cls._instance?=?super().__new__(cls,?*args,?**kwargs)
          ????????return?cls._instance


          if?__name__?==?"__main__":

          ????print("SINGLETON?EXAMPLE")
          ????x?=?Singleton()
          ????y?=?Singleton()
          ????print(f"{x?is?y=}")
          #?SINGLETON?EXAMPLE
          #?x?is?y=True

          應(yīng)用3:客戶端緩存

          當(dāng)客戶端的創(chuàng)建成本比較高時(shí),比如讀取文件或者數(shù)據(jù)庫(kù),可以采用以下方法,同一個(gè)客戶端屬于同一個(gè)實(shí)例,節(jié)省創(chuàng)建對(duì)象的成本,這本質(zhì)就是多例模式。

          class?Client:
          ????_loaded?=?{}
          ????_db_file?=?"file.db"

          ????def?__new__(cls,?client_id):
          ????????if?(client?:=?cls._loaded.get(client_id))?is?not?None:
          ????????????print(f"returning?existing?client?{client_id}?from?cache")
          ????????????return?client
          ????????client?=?super().__new__(cls)
          ????????cls._loaded[client_id]?=?client
          ????????client._init_from_file(client_id,?cls._db_file)
          ????????return?client

          ????def?_init_from_file(self,?client_id,?file):
          ????????#?lookup?client?in?file?and?read?properties
          ????????print(f"reading?client?{client_id}?data?from?file,?db,?etc.")
          ????????name?=?...
          ????????email?=?...
          ????????self.name?=?name
          ????????self.email?=?email
          ????????self.id?=?client_id


          if?__name__?==?'__main__':
          ????print("CLIENT?CACHE?EXAMPLE")
          ????x?=?Client(0)
          ????y?=?Client(0)
          ????print(f"{x?is?y=}")
          ????z?=?Client(1)
          #?CLIENT?CACHE?EXAMPLE
          #?reading?client?0?data?from?file,?db,?etc.
          #?returning?existing?client?0?from?cache
          #?x?is?y=True
          #?reading?client?1?data?from?file,?db,?etc.

          應(yīng)用4:不同文件不同的解密方法

          先在腳本所在目錄創(chuàng)建三個(gè)文件:plaintext_hello.txt、rot13_hello.txt、otp_hello.txt,程序會(huì)根據(jù)不同的文件選擇不同的解密算法


          import?codecs
          import?itertools


          class?EncryptedFile:
          ????_registry?=?{}??#?'rot13'?->?ROT13Text

          ????def?__init_subclass__(cls,?prefix,?**kwargs):
          ????????super().__init_subclass__(**kwargs)
          ????????cls._registry[prefix]?=?cls

          ????def?__new__(cls,?path:?str,?key=None):
          ????????prefix,?sep,?suffix?=?path.partition(":///")
          ????????if?sep:
          ????????????file?=?suffix
          ????????else:
          ????????????file?=?prefix
          ????????????prefix?=?"file"
          ????????subclass?=?cls._registry[prefix]
          ????????obj?=?object.__new__(subclass)
          ????????obj.file?=?file
          ????????obj.key?=?key
          ????????return?obj

          ????def?read(self)?->?str:
          ????????raise?NotImplementedError


          class?Plaintext(EncryptedFile,?prefix="file"):
          ????def?read(self):
          ????????with?open(self.file,?"r")?as?f:
          ????????????return?f.read()


          class?ROT13Text(EncryptedFile,?prefix="rot13"):
          ????def?read(self):
          ????????with?open(self.file,?"r")?as?f:
          ????????????text?=?f.read()
          ????????return?codecs.decode(text,?"rot_13")


          class?OneTimePadXorText(EncryptedFile,?prefix="otp"):
          ????def?__init__(self,?path,?key):
          ????????if?isinstance(self.key,?str):
          ????????????self.key?=?self.key.encode()

          ????def?xor_bytes_with_key(self,?b:?bytes)?->?bytes:
          ????????return?bytes(b1?^?b2?for?b1,?b2?in?zip(b,?itertools.cycle(self.key)))

          ????def?read(self):
          ????????with?open(self.file,?"rb")?as?f:
          ????????????btext?=?f.read()
          ????????text?=?self.xor_bytes_with_key(btext).decode()
          ????????return?text


          if?__name__?==?"__main__":
          ????print("ENCRYPTED?FILE?EXAMPLE")
          ????print(EncryptedFile("plaintext_hello.txt").read())
          ????print(EncryptedFile("rot13:///rot13_hello.txt").read())
          ????print(EncryptedFile("otp:///otp_hello.txt",?key="1234").read())
          #?ENCRYPTED?FILE?EXAMPLE
          #?plaintext_hello.txt
          #?ebg13_uryyb.gkg
          #?^FCkYW_X^GLE

          應(yīng)用5:Metaclasses

          metaclass 可以像裝飾器那樣定制和修改繼承它的子類,前文Python黑魔法之metaclass

          最后

          本文分享了 Python 的構(gòu)造方法 __new__ 的常用場(chǎng)景,如果有幫助,請(qǐng)點(diǎn)個(gè)在看分享給在學(xué)習(xí) Python 的朋友們,點(diǎn)個(gè)贊也行,感謝你的支持。

          關(guān)注我,每天學(xué)習(xí)一個(gè) Python 小技術(shù)。



          瀏覽 29
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  亚洲一区二区黄色电影视频 | 干干网| 免费看一级A片 | 国产精品久久久久久久久免费挑花 | 人人草人人摸人人搞 |