人妖在线一区,国产日韩欧美一区二区综合在线,国产啪精品视频网站免费,欧美内射深插日本少妇

新聞動態(tài)

Python 中類的構(gòu)造方法 __New__的妙用

發(fā)布日期:2021-12-22 22:18 | 文章來源:站長之家

1、概述

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

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

2、__new__ 和 __init__ 的區(qū)別

  • 調(diào)用時機不同:new 是真正創(chuàng)建實例的方法,init 用于實例的初始化,new 先于 init 運行。
  • 返回值不同,new 返回一個類的實例,而 init 不返回任何信息。
  • new class 的方法,而 init 是對象的方法。

示例代碼:

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() 

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

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

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

new <class '__main__.A'> (1, 2, 3) {'x': 4} 
init <__main__.A object at 0x7fccaec97610> (1, 2, 3) {'x': 4} 
<__main__.A object at 0x7fccaec97610> 
=================== 
new <class '__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)用場景:

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

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

class UppercaseTuple(tuple): 
 def __new__(cls, iterable): 
  upper_iterable = (s.upper() for s in iterable) 
  return super().__new__(cls, upper_iterable) 
 
 # 以下代碼會報錯,初始化時是無法修改的 
 # 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') 

4、應(yīng)用2:實現(xiàn)一個單例

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 

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

當(dāng)客戶端的創(chuàng)建成本比較高時,比如讀取文件或者數(shù)據(jù)庫,可以采用以下方法,同一個客戶端屬于同一個實例,節(jié)省創(chuàng)建對象的成本,這本質(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. 

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

先在腳本所在目錄創(chuàng)建三個文件:plaintext_hello.txt、rot13_hello.txt、otp_hello.txt,程序會根據(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 

到此這篇關(guān)于Python 中類的構(gòu)造方法 New的妙用的文章就介紹到這了,更多相關(guān)Python 中類的構(gòu)造方法 New內(nèi)容請搜索本站以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持本站!

版權(quán)聲明:本站文章來源標(biāo)注為YINGSOO的內(nèi)容版權(quán)均為本站所有,歡迎引用、轉(zhuǎn)載,請保持原文完整并注明來源及原文鏈接。禁止復(fù)制或仿造本網(wǎng)站,禁止在非www.sddonglingsh.com所屬的服務(wù)器上建立鏡像,否則將依法追究法律責(zé)任。本站部分內(nèi)容來源于網(wǎng)友推薦、互聯(lián)網(wǎng)收集整理而來,僅供學(xué)習(xí)參考,不代表本站立場,如有內(nèi)容涉嫌侵權(quán),請聯(lián)系alex-e#qq.com處理。

相關(guān)文章

實時開通

自選配置、實時開通

免備案

全球線路精選!

全天候客戶服務(wù)

7x24全年不間斷在線

專屬顧問服務(wù)

1對1客戶咨詢顧問

在線
客服

在線客服:7*24小時在線

客服
熱線

400-630-3752
7*24小時客服服務(wù)熱線

關(guān)注
微信

關(guān)注官方微信
頂部