隐藏页面特效

描述符示例详解

代码

这里要创建一个描述符,根据要求(如隐藏敏感信息、正确地设置日期的格式)对属性的值进行变换,并返回修改后的版本: from dataclasses import dataclass from datetime import datetime from functools import partial from typing import Callable class BaseFieldTransformation: def __init__(self, transformation: Callable[[], str]) -> None: print("初始化") self._name = None self.transformation = transformation def __get__(self, instance, owner): print("get执行") if instance is None: return self raw_value = instance.__dict__[self._name] return self.transformation(raw_value) def __set_name__(self, owner, name): print("set_name执行") self._name = name def __set__(self, instance, value): print("set执行") instance.__dict__[self._name] = value ShowOriginal = partial(BaseFieldTransformation, transformation=lambda x: x) HideField = partial( BaseFieldTransformation, transformation=lambda x: "**redacted**" ) FormatTime = partial( BaseFieldTransformation, transformation=lambda ft: ft.strftime("%Y-%m-%d %H:%M"), ) @dataclass class LoginEvent: username: str = ShowOriginal() password: str = HideField() ip: str = ShowOriginal() timestamp: datetime = FormatTime() def serialize(self) -> dict: return { "username": self.username, "password": self.password, "ip": self.ip, "timestamp": self.timestamp, } if __name__ == '__main__': le = LoginEvent("john", "secret password", "1.1.1.1", datetime.utcnow()) >>> le = LoginEvent("john", "secret password", "1.1.1.1", datetime. utcnow()) >>> vars(le) {'username': 'john', 'password': 'secret password', 'ip': '1.1.1.1', 'timestamp': ...} >>> le.serialize() {'username': 'john', 'password': '**redacted**', 'ip': '1.1.1.1', 'timestamp': '...'} >>> le.password '**redacted**' 这段代码使用了 Python 中的描述符(Descriptor)和数据类(Data Class)来实现一个 LoginEvent 类,该类用于表示用户的登录事件,并包含了一些敏感信息。其中,BaseFieldTransformation 类是一个基类,它定义了描述符的通用行为。LoginEvent 类继承了 dataclass 装饰器,这使得该类具有自动生成 init____repr 等方法的特性。 BaseFieldTransformation 描述符有三个方法: __init__: 在对象创建时被调用,用于初始化对象状态; __get__: 在属性被访问时被调用,用于获取属性的值; __set__: 在属性被赋值时被调用,用于设置属性的值; __set_name__: 在类中定义属性时被调用,用于设置描述符名称。 在该代码中,我们定义了三个具体的 BaseFieldTransformation 子类:ShowOriginalHideField FormatTime。这些子类通过 partial 函数将 transformation 参数预设为不同的函数,以便对应不同的字段转换方式。例如,ShowOriginal 字段保持原样,而 HideField 字段使用 "redacted" 来代替其真实值。 最后,我们使用 LoginEvent 类创建了一个数据记录。该数据记录用于存储用户的登录事件,包括用户名、密码、IP 地址和时间戳。其中,用户名和 IP 地址字段使用 ShowOriginal 描述符,这意味着它们不会被转换。密码字段使用 HideField 描述符,这意味着它将被替换为 "redacted"。时间戳字段使用 FormatTime 描述符,这意味着它将按照指定格式进行格式化。登录事件还包括一个 serialize 方法,用于将该事件序列化为 dict 格式的数据。

示例

class CelsiusWithDescriptor: def __init__(self, temperature=0): print("CelsiusWithDescriptor初始化") self._temperature = temperature # print(self._temperature) # 0 def __get__(self, instance, owner): print("Getting value...") return self._temperature def __set__(self, instance, value): if value < -273: raise ValueError("Temperature below -273 is not possible") print("Setting value.......................") print(value) # 25 self._temperature = value class TemperatureWithDescriptor: def __init__(self, celsius): self.celsius = celsius # 描述符对应的值25 def __str__(self): return f"{self.celsius} degrees Celsius is {self.fahrenheit:.2f} degrees Fahrenheit" @property def fahrenheit(self): return self.celsius * 1.8 + 32 class TemperatureDataModel: temperature = CelsiusWithDescriptor() def __init__(self, temperature): self.temperature = temperature # print(self.temperature == TemperatureDataModel.temperature) # True # print(self.temperature) # 25 def __str__(self): """打印对象时会执行此函数""" return str(TemperatureWithDescriptor(self.temperature)) if __name__ == '__main__': """代码分析TemperatureDataModel(25) 实例化 1.类的执行顺序,会先执行类中定义的变量属性等 2.会先执行CelsiusWithDescriptor()的初始化__init__方法,此时它的self._temperature为0 3.执行初始化TemperatureDataModel的__init__方法,此时temperature为25 4.其中的self.temperature描述符实际是调用CelsiusWithDescriptor()中的__set__方法,并将上面的temperature的值25当做value传递进去 5.经过上面的__set__方法后,CelsiusWithDescriptor对象的self._temperature为25. 6.打印tmp 7.会执行TemperatureDataModel类的__str__方法 8.此时的self.temperature为25,当做参数传递给TemperatureWithDescriptor类 9.会先执行当做参数传递给TemperatureWithDescriptor类的__init__方法 10.初始化实例属性self.celsius = 25 11.外面的str,会执行TemperatureWithDescriptor类中定义的__str__方法,所以最终返回25 degrees Celsius is 77.00 degrees Fahrenheit """ tmp = TemperatureDataModel(25) # print(tmp) tmp.temperature = 50 # 跟上面一样,执行__set__ # print(tmp.temperature) # 执行__get__ tmp1 = TemperatureDataModel(59) print(tmp1.temperature) # 59 print(tmp.temperature) # 59 如上代码有问题:可以看出不同的对象,却打印了同一个值。原因是CelsiusWithDescriptor类中getset魔法方法中它自己存储数据, 而不是将数据存储到每个对象中去所以才会出现上面的问题。需要修改CelsiusWithDescriptor类中的代码 class CelsiusWithDescriptor: def __init__(self, temperature=0): self.name = None self._temperature = temperature # print(self._temperature) # 0 def __set_name__(self, owner, name): self.name = name def __get__(self, instance, owner): print("Getting value...") return instance.__dict__[self.name] # 必须要使用__dict__ def __set__(self, instance, value): if value < -273: raise ValueError("Temperature below -273 is not possible") print("Setting value.......................") instance.__dict__[self.name] = value # 必须要使用__dict__ tmp = TemperatureDataModel(25) # print(tmp) tmp.temperature = 50 # 跟上面一样,执行__set__ # print(tmp.temperature) # 执行__get__ tmp1 = TemperatureDataModel(59) print(tmp1.temperature) # 59 print(tmp.temperature) # 50

__EOF__

本文作者404 Not Found
本文链接https://www.cnblogs.com/weiweivip666/p/17299269.html
关于博主:可能又在睡觉
版权声明:转载请注明出处
声援博主:如果看到我睡觉请喊我去学习
posted @   我在路上回头看  阅读(35)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示