我正在尝试编写一个专门的Python内置property
子类,它在如下装饰函数时接受一个输入参数:
@special_property(int)
def my_number(self):
return self._number
我一直使用https://realpython.com/primer-on-python-decorators/上的示例作为参考,试图实现以下目标:
class special_property(property):
def __init__(self, property_type):
super().__init__()
self.type = property_type
def __call__(self, fn):
fn.type = self.type
return fn
此设置允许我检索在使用my special_property
的类中为属性指定的显式type
,如下所示:
class Object(object):
def __init__(self):
super().__init__()
self._number = 0
@special_property(int)
def my_number(self):
return self._number
def load_from_json(self, json_file):
with open(json_file, 'r') as f:
state = json.load(f)
for name, value in state.items():
if hasattr(self, name):
klass = self.__class__.__dict__[name].type
try:
self.__setattr__(name, klass(value))
except:
ValueError('Error loading from JSON')
我这样做的原因是,通过修饰应该存储/加载在JSON文件中的属性,可以创建一个JSON可序列化类。在本例中,不需要显式地确保my_number
的类型是int
,因为json
模块可以自动处理该类型。但在我的实际案例中,有一些更复杂的对象,我将其标记为可使用decorator序列化的JSON,并实现自定义序列化/反序列化方法。但是,为了使其工作,代码需要知道属性的类型。你知道吗
例如,这允许我创建JSON可序列化类的层次结构。我当前的实现允许从JSON存储和加载整个数据结构,而不会丢失任何信息。你知道吗
现在我想更进一步,在尝试设置specialized_property
的值时,也可以验证数据的格式。因此,我希望能够做到:
@specialized_property(int)
def my_number(self):
return self._number
@my_number.setter
def my_number(self, value):
if value < 0:
raise ValueError('Value of `my_number` should be >= 0')
self._number = value
例如,这将允许我确保从JSON文件加载的数字列表具有正确的大小。你知道吗
但是,由于代码使得添加property_type
参数起作用,现在不可能使用@my_number.setter
。如果我尝试运行代码,我会得到:
AttributeError: 'function' object has no attribute 'setter'
这对我来说很有意义,因为重写__call__
方法并返回function
对象。但我该如何绕过这一点,实现我想要的?你知道吗
这是我的实现。它使用了Descriptor HOWTO中概述的
property
的Python实现。我为此添加了一个包装器,它接受在设置或获取值时将调用的函数或类型。在包装器的闭包中,我定义了special_property_descriptor
类,它有一个.type
。这是给外部包装器的函数/类型。最后,这个属性描述符类由设置了.type
属性的包装器返回。你知道吗显然,您可以修改这里的功能。在我的示例中,描述符将在设置/获取值之前尝试将值强制转换为所需的类型。如果愿意,可以执行
isinstance(value, self.type)
操作,只强制类型,而不尝试转换无效值。你知道吗不要乱动财物。在自己的类变量中分别跟踪类型。你知道吗
请参见下面的prop_type class变量以获取说明。你知道吗
相关问题 更多 >
编程相关推荐