python - 用于类型检查和不变性的 Python 描述符
问题描述
阅读 Python Cookbook 并查看描述符,尤其是使用类属性时强制类型的示例。我正在编写一些有用的类,但我也想强制执行不变性。怎么做?改编自本书的类型检查描述符:
class Descriptor(object):
def __init__(self, name=None, **kwargs):
self.name = name
for key, value in kwargs.items():
setattr(self, key, value)
def __set__(self, instance, value):
instance.__dict__[self.name] = value
# by default allows None
class Typed(Descriptor):
def __init__(self, expected_types=None, **kwargs):
self.expected_types = expected_types
super().__init__(**kwargs)
def __set__(self, instance, value):
if value is not None and not isinstance(value, self.expected_types):
raise TypeError('Expected: {}'.format(str(self.expected_types)))
super(Typed, self).__set__(instance, value)
class T(object):
v = Typed(int)
def __init__(self, v):
self.v = v
尝试 #1:self.is_set
向 Typed 添加一个属性
# by default allows None
class ImmutableTyped(Descriptor):
def __init__(self, expected_types=None, **kwargs):
self.expected_types = expected_types
self.is_set = False
super().__init__(**kwargs)
def __set__(self, instance, value):
if self.is_set:
raise ImmutableException(...)
if value is not None and not isinstance(value, self.expected_types):
raise TypeError('Expected: {}'.format(str(self.expected_types)))
self.is_set = True
super(Typed, self).__set__(instance, value)
错误的,因为在执行以下操作时,ImmutableTyped
它是“全局”的,因为它在类的所有实例中都是一个单例。Whent2
被实例化,is_set
从前一个对象中已经是 True 。
class T(object):
v = ImmutableTyped(int)
def __init__(self, v):
self.v = v
t1 = T()
t2 = T() # fail when instantiating
尝试#2:Thought instance in__set__
是指包含该属性的类,因此尝试检查是否instance.__dict__[self.name]
仍然是 Typed。那也是错误的。
@property
想法#3:通过接受fget
返回__dict__
T 个实例的 ' ' 方法,使 Typed 的使用更类似于。这需要在 T 中定义一个函数,类似于:
@Typed
def v(self):
return self.__dict__
这似乎是错误的。
如何实现不变性和类型检查作为描述符?
解决方案
现在这是我解决问题的方法:
class ImmutableTyped:
def __set_name__(self, owner, name):
self.name = name
def __init__(self, *, immutable=False, types=None)
self.immutable == immutable is True
self.types = types if types else []
def __get__(self, instance, owner):
return instance.__dict__[self.name]
def __set__(self, instance, value):
if self.immutable is True:
raise TypeError('read-only attribute')
elif not any(isinstance(value, cls)
for cls in self.types):
raise TypeError('invalid argument type')
else:
instance.__dict__[self.name] = value
旁注:__set_name__
可用于允许您在初始化时不指定属性名称。这意味着您可以这样做:
class Foo:
bar = ImmutableTyped()
并且实例ImmutableTyped
将自动具有该name
属性bar
,因为我在__set_name__
方法中键入了该属性。
推荐阅读
- spring-batch - 无法自动接线。找不到“JobRepositoryTestUtils”类型的 bean
- linux - bash 脚本剪切/替换指南
- c++ - 使用原始套接字接收到的重复数据包并提升 asio
- google-chrome - 单击以在 javascript 中打开多个选项卡,但由于弹出块而无法打开
- excel - 按类别求和产品,每天求和并求和最高时间
- python - 使用 for 循环在 Python 中定义多个函数?
- python - 如何使 re.findall 不区分大小写?
- python - 如何计算多重响应(即“检查所有适用”)问题的出现频率?- Python
- flutter - 如何在飞镖中运行自定义异常时通过编译器解决错误?
- c# - EF Linq 排除属性