Python 中类的构造方法 __New__的妙用
作者:somenzz 发布时间:2021-04-06 04:45:56
目录
1、概述
2、__new__ 和 __init__ 的区别
3、应用1:改变内置的不可变类型
4、应用2:实现一个单例
5、应用3:客户端缓存
6、应用4:不同文件不同的解密方法
1、概述
python
的类中,所有以双下划线__包起来的方法,叫魔术方法,魔术方法在类或对象的某些事件发出后可以自动执行,让类具有神奇的魔力,比如常见的构造方法__new__
、初始化方法__init__
、析构方法__del__
,今天来聊一聊__new__
的妙用,主要分享以下几点:
__new__ 和 __init__ 的区别
应用1:改变内置的不可变类型
应用2:实现一个单例
应用3:客户端缓存
应用4:不同文件不同的解密方法
应用5:Metaclasses
2、__new__ 和 __init__ 的区别
调用时机不同:
new
是真正创建实例的方法,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,在调用 A(1, 2, 3, x=4) 时先执行 new,再执行 init,等价于:
x = A.__new__(A, 1, 2, 3, x=4)
if isinstance(x, A):
type(x).__init__(x, 1, 2, 3, x=4)
代码的运行结果如下:
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
的主要作用就是让程序员可以自定义类的创建行为,以下是其主要应用场景:
3、应用1:改变内置的不可变类型
我们知道,元组是不可变类型,但是我们继承 tuple
,然后可以在 new
中,对其元组的元素进行修改,因为 new
返回之前,元组还不是元组,这在 init 函数中是无法实现的。比如说,实现一个大写的元组,代码如下:
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、应用2:实现一个单例
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、应用3:客户端缓存
当客户端的创建成本比较高时,比如读取文件或者数据库,可以采用以下方法,同一个客户端属于同一个实例,节省创建对象的成本,这本质就是多例模式。
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、应用4:不同文件不同的解密方法
先在脚本所在目录创建三个文件:plaintext_hello.txt、rot13_hello.txt、otp_hello.txt,
程序会根据不同的文件选择不同的解密算法
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
来源:https://developer.51cto.com/art/202110/686454.htm
猜你喜欢
- 地理图表什么是地理图表?地理图表有什么作用?地理图表主要应用在那些领域?其实这些问题看看下面的实例图形就已不攻自破了,地理图表一看首先就是地
- 👀前言代码出现异常而报错再正常不过了,但为什么要处理异常?由于异常的存在,代码运行时会出现一大堆的红色字体提示,对于程序员还好,见红色报错见
- 首先说明,Supervisor 只能安装在 Python 2.x 环境中!但是基本上所有的 Linux 都同时预装了 Python 2.x
- 今日上课,有位同学问到:w和w+有何区别呢。说实话,我们经常只是用一种权限,没用在意之间的区别,实际上,w+具有可读可写权限,而w只有可写权
- 装饰器模式在以下场景中被广泛应用:动态地向对象添加职责或行为,而不需要更改对象的代码。例如,可以通过装饰器模式来实现日志记录、性能分析、缓存
- 本文实例讲述了php版银联支付接口开发的方法。分享给大家供大家参考,具体如下:支付接口现在有第三方的支付接口也有银行的支付接口。这里就来介绍
- 本文实例为大家分享了python实现转盘效果的具体代码,供大家参考,具体内容如下#抽奖 面向对象版本import tkinterimport
- 在对浏览器兼容性要求越来越高的时候,大家是否正在寻找一个完整的解决方案呢?继《[原]最新CSS兼容方案》之后,更新的CSS hack出炉啦,
- 本文实例讲述了Python求两个文本文件以行为单位的交集、并集与差集的方法。分享给大家供大家参考。具体实现方法如下:s1 = set(ope
- 目录正文开始1. DRF 中的限流2. 限流进阶配置3. 限流思路分析4. 源码分析5. 其它注意事项参考资料正文开始先说一个限流这个概念,
- 本文实例讲述了Python二叉搜索树与双向链表转换算法。分享给大家供大家参考,具体如下:题目描述输入一棵二叉搜索树,将该二叉搜索树转换成一个
- 推导式comprehensions(又称解析式),是Python的一种独有特性。推导式是可以从一个数据序列构建另一个新的数据序列(的一种结构
- 一、Python图像处理PIL库1.1 转换图像格式# PIL(Python Imaging Library)from PIL import
- 本文实例为大家分享了JSP实现客户信息管理系统的具体代码,供大家参考,具体内容如下项目示意图大概这样吧。我自己画的 登录界面代码index.
- 今天写了一段CSS,写时突然想到的,写出来和大家分享一下; 我们可能早已习惯了padding在不同浏览器中的不同之处,
- 尽管XML还处在开发阶段,其标准正在由W3C组织制定,但是已经有许多公司表示全力支持XML,并开发了不少XML工具。Adobe公司的Fram
- 在学习编程过程中,我们不仅要学习python语法,同时也需要学习如何把自己代码写的更美观,效率更高。一.什么是推导式推导式是从一个或者多个迭
- 本文实例讲述了python使用wxPython打开并播放wav文件的方法。分享给大家供大家参考。具体实现方法如下:''
- 代码如下:'************************************ '截取文字长度函数,支持UT
- 在Web标准中一个很重要的概念就是强调页面的结构与表现分离。说的通俗一点就是XHTML中应该没有样式化的东西,而且Web在浏览器中除内容外都