【发布时间】:2018-08-29 17:50:04
【问题描述】:
阅读 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 是“全局”的,因为它在类的所有实例中都是单例。当 t2 被实例化时,is_set 已经从前一个对象为 True。
class T(object):
v = ImmutableTyped(int)
def __init__(self, v):
self.v = v
t1 = T()
t2 = T() # fail when instantiating
尝试#2:__set__ 中的 Thought 实例指的是包含该属性的类,因此尝试检查 instance.__dict__[self.name] 是否仍然是 Typed。这也是错误的。
想法 #3:通过接受返回 T 个实例的 __dict__ 的“fget”方法,使 Typed 的使用更类似于 @property。这需要在 T 中定义一个函数,类似于:
@Typed
def v(self):
return self.__dict__
这似乎是错误的。
如何实现不可变性和类型检查作为描述符?
【问题讨论】:
-
您是否尝试过使用一个只有
__get__方法且没有设置不变性的非继承类。另外,如果值是不可变的,为什么需要强制进行类型检查?这不是自相矛盾吗? -
目的是将设置限制在(内部)
__init__方法(就像 Java 构造函数可以设置最终变量一样),同时还检查类型。实际上,可以实现方法来进行类型检查,同时通过@property保持不变性。不过,同时做这两件事似乎更优雅。
标签: python immutability typechecking descriptor