我是OP的问题,我将回答我自己的问题,因为我认为我在键入它的过程中发现了答案。在其他人确认它正确之前,我不会将其标记为正确。
这里的这个问题特别相关,但是这个问题与这个问题并不相同,尽管答案很有启发性(尽管注释变成了关于C和Python以及“
pythonic”的启发性但深奥的论点),但应该设置它在这里更清楚地说明这个问题。希望这对以后的读者有所帮助。此答案中的代码已在Python
3.6.1中进行了验证。
关于不可变对象的事情是,很明显,一旦创建它,您就不想设置它的成员。在Python中执行此 *** 作的方法是将
__setattr__()特殊方法覆盖为
raise错误(
AttributeError),以使人们无法执行
my_immutable_object.x= 3。以下面的自定义不可变类为例。
class Immutable(object): def __init__(self, a, b): self.a = a self.b = b def __setattr__(self, key, value): raise AttributeError("LOL nope.")
让我们尝试使用它。
im = Immutable(2, 3)print(im.a, im.b, sep=", ")
输出:
AttributeError: LOL nope.
“但是什么!?”,我听到你问,“创建之后,我没有设置任何属性!” 啊但是 是的,你
在里面
__init__()。由于
__init__()被称为 后 创建对象,这些线
self.a = a和
self.b =b在设置的属性
a和
b后 创建的
im。你真正想要的是设置属性
a和
b之前 创建的不可变对象。一种明显的方法是首先创建一个
可变 类型( 允许 在其中设置其属性
__init__()),然后将 不可变 类型作为其 子类 ,并确保实现
__new__()
不可变子类的方法首先构造一个可变版本,然后使其变为不可变,如下所示。
class Mutable(object): def __init__(self, a, b): self.a = a self.b = bclass ActuallyImmutable(Mutable): def __new__(cls, a, b): thing = Mutable(a, b) thing.__class__ = cls return thing def __setattr__(self, key, value): raise AttributeError("LOL nope srsly.")
现在,让我们尝试运行它。
im = ActuallyImmutable(2, 3)print(im.a, im.b, sep=", ")
输出:
AttributeError: LOL nope srsly.
“ WTF !?
__setattr__()这次什么时候接到电话?”
事情是,
ActuallyImmutable是的子类
Mutable,并且在没有显式实现它的情况下
__init__(),在创建对象
之后
__init__()会自动调用父类的,因此总共调用了父类两次,一次在创建之前(确定),一次 在之后 (这 不行*
)。因此,让我们再试一次,这次覆盖。
ActuallyImmutable``__init__()``im
*
AcutallyImmutable.__init__()
class Mutable(object): def __init__(self, a, b): print("Mutable.__init__() called.") self.a = a self.b = bclass ActuallyImmutable(Mutable): def __new__(cls, a, b): thing = Mutable(a, b) thing.__class__ = cls return thing # noinspection PyMissingConstructor def __init__(self, *args, **kwargs): # Do nothing, to prevent it from calling parent's __init__(). pass def __setattr__(self, key, value): raise AttributeError("LOL nope srsly.")
现在应该可以了。
im = ActuallyImmutable(2, 3)print(im.a, im.b, sep=", ")
输出:
2, 3
很好,很有效。哦,不用担心
# noinspectionPyMissingConstructor,这只是一个PyCharm骇客,它可以阻止PyCharm抱怨我没有打电话给父母的
__init__(),这显然是我们打算在这里做的。最后,只是要检查它是否
im确实是不变的,请验证是否
im.a= 42可以给您
AttributeError: LOL nope srsly.。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)