python - 如何动态创建具有只读 attributes 的对象

我想创建具有只读 attributes 的对象。并且需要动态初始化。

这是我想要的情况。

readOnlyObject = ReadOnlyClass({'name': 'Tom', 'age': 24})

print(readOnlyObject.name)
>> 'Tom'
print(readOnlyObject.age)
>> 24
readOnlyObject.age = 14
>> AttributeError: can't set attribute

我找到了一种使用 property 函数的 https://stackoverflow.com/a/51104302/12728265

但我认为 property 函数仅适用于预先声明的 attributes。

这是我的 property 不起作用的代码。

class ReadOnlyClass:
  _preDeclaredVar = "Read-Only!"
  preDeclaredVar = property(lambda self: self._preDeclaredVar)

  def __init__(self, data: dict):
    for attr in data:
      setattr(self, '_' + attr, data[attr])
      setattr(self, attr, property(lambda self: getattr(self, '_' + attr)))



readOnlyObject = ReadOnlyClass({'name': 'Tom', 'age': 24})

print(readOnlyObject.preDeclaredVar)
>> "Read-Only!"

readOnlyObject.preDeclaredVar = "Can write?"
>> AttributeError: can't set attribute '

print(readOnlyObject.name)
>> <property object at 0x016C62A0>  # I think it is weird.. property func only work on pre-declared variable?

发生了什么?

我想知道有没有办法动态创建只读对象。

回答1

考虑从 __setattr__ 开始:

>>> class ReadOnlyClass:
...     def __init__(self, **kwargs):
...         self.__dict__.update(kwargs)
...     
...     def __setattr__(self, key, value):
...         raise AttributeError("can't set attribute")
...
>>> readonly_object = ReadOnlyClass(name='Tom', age=24)
>>> readonly_object.name
'Tom'
>>> readonly_object.age
24
>>> readonly_object.age = 10
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in __setattr__
AttributeError: can't set attribute

但是,这可能无法完全满足您的期望。您仍然可以通过 __dict__ 设置 attributes:

>>> readonly_object.__dict__['age'] = 10
>>> readonly_object.age
10

回答2

您可以使用命名元组:

>>> import collections
>>> def ReadOnlyClass(data):
...     class_ = collections.namedtuple('ReadOnlyClass', data.keys())
...     return class_(**data)
... 
>>> readOnlyObject = ReadOnlyClass({'name': 'Tom', 'age': 24})
>>> print(readOnlyObject.name)
Tom
>>> print(readOnlyObject.age)
24
>>> readOnlyObject.age = 14
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

相似文章

随机推荐

最新文章