是否有推荐的方法来确保不变性
Is there a recommended way of ensuring immutability
我正在观察以下行为,因为 python 通过引用传递对象?
class Person(object):
pass
person = Person()
person.name = 'UI'
def test(person):
person.name = 'Test'
test(person)
print(person.name)
>>> Test
我发现 copy.deepcopy() 可以深度复制对象以防止修改传递的对象。还有其他建议吗?
import copy
class Person(object):
pass
person = Person()
person.name = 'UI'
def test(person):
person_copy = copy.deepcopy(person)
person_copy.name = 'Test'
test(person)
print(person.name)
>>> UI
I am observing following behavior since python passes object by reference?
不是真的。这是一个微妙的问题。你可以看看python - How do I pass a variable by reference? - Stack Overflow
就我个人而言,我并不完全同意接受的答案并推荐您google call by sharing
。然后,你可以在这个微妙的问题上做出自己的决定。
I found copy.deepcopy() to deepcopy object to prevent modifying the passed object. Are there any other recommendations ?
据我所知,如果不使用第三个包,没有其他更好的方法。
您可以使用 __setattr__
魔术方法来实现一个基础 class,它允许您在完成后 "freeze" 一个对象。
这不是bullet-proof;你仍然可以访问 __dict__
来改变对象,你也可以通过取消设置 _frozen
来解冻对象,如果属性的值本身是可变的,这没有多大帮助(x.things.append('x')
将适用于 things
).
的列表
class Freezable:
def freeze(self):
self._frozen = True
def __setattr__(self, key, value):
if getattr(self, "_frozen", False):
raise RuntimeError("%r is frozen" % self)
super().__setattr__(key, value)
class Person(Freezable):
def __init__(self, name):
self.name = name
p = Person("x")
print(p.name)
p.name = "y"
print(p.name)
p.freeze()
p.name = "q"
产出
x
y
Traceback (most recent call last):
File "freezable.py", line 21, in <module>
p.name = 'q'
RuntimeError: <__main__.Person object at 0x10f82f3c8> is frozen
没有真正 100% 无懈可击的方法,但是您可以使您难以无意中改变要冻结的对象;对于大多数人来说,推荐的方法可能是使用冷冻 DataClass
或冷冻 attrs
class
在他的talk on DataClasses (2018), @RaymonHettinger mentions three approaches: one way, is with a metaclass, another, like in the fractions module是给属性一个read only 属性; DataClass
模块 扩展了 __setattr__
和 __delattr__
,并覆盖了 __hash__
:
-> 使用元class.
好的资源包括@DavidBeasley 的书籍和在 python 的讲座。
-> 给属性一个只读 属性
class SimpleFrozenObject:
def __init__(self, x=0):
self._x = x
@property
def x(self):
return self._x
f = SimpleFrozenObject()
f.x = 2 # raises AttributeError: can't set attribute
-> 扩展 __setattr__
和 __delattr__
,并覆盖 `hash
class FrozenObject:
...
def __setattr__(self, name, value):
if type(self) is cls or name in (tuple of attributes to freeze,):
raise FrozenInstanceError(f'cannot assign to field {name}')
super(cls, self).__setattr__(name, value)
def __delattr__(self, name):
if type(self) is cls or name in (tuple of attributes to freeze,):
raise FrozenInstanceError(f'cannot delete field {name}')
super(cls, self).__delattr__(name, value)
def __hash__(self):
return hash((tuple of attributes to freeze,))
...
库 attrs
还提供了创建不可变对象的选项。
我正在观察以下行为,因为 python 通过引用传递对象?
class Person(object):
pass
person = Person()
person.name = 'UI'
def test(person):
person.name = 'Test'
test(person)
print(person.name)
>>> Test
我发现 copy.deepcopy() 可以深度复制对象以防止修改传递的对象。还有其他建议吗?
import copy
class Person(object):
pass
person = Person()
person.name = 'UI'
def test(person):
person_copy = copy.deepcopy(person)
person_copy.name = 'Test'
test(person)
print(person.name)
>>> UI
I am observing following behavior since python passes object by reference?
不是真的。这是一个微妙的问题。你可以看看python - How do I pass a variable by reference? - Stack Overflow
就我个人而言,我并不完全同意接受的答案并推荐您google call by sharing
。然后,你可以在这个微妙的问题上做出自己的决定。
I found copy.deepcopy() to deepcopy object to prevent modifying the passed object. Are there any other recommendations ?
据我所知,如果不使用第三个包,没有其他更好的方法。
您可以使用 __setattr__
魔术方法来实现一个基础 class,它允许您在完成后 "freeze" 一个对象。
这不是bullet-proof;你仍然可以访问 __dict__
来改变对象,你也可以通过取消设置 _frozen
来解冻对象,如果属性的值本身是可变的,这没有多大帮助(x.things.append('x')
将适用于 things
).
class Freezable:
def freeze(self):
self._frozen = True
def __setattr__(self, key, value):
if getattr(self, "_frozen", False):
raise RuntimeError("%r is frozen" % self)
super().__setattr__(key, value)
class Person(Freezable):
def __init__(self, name):
self.name = name
p = Person("x")
print(p.name)
p.name = "y"
print(p.name)
p.freeze()
p.name = "q"
产出
x
y
Traceback (most recent call last):
File "freezable.py", line 21, in <module>
p.name = 'q'
RuntimeError: <__main__.Person object at 0x10f82f3c8> is frozen
没有真正 100% 无懈可击的方法,但是您可以使您难以无意中改变要冻结的对象;对于大多数人来说,推荐的方法可能是使用冷冻 DataClass
或冷冻 attrs
class
在他的talk on DataClasses (2018), @RaymonHettinger mentions three approaches: one way, is with a metaclass, another, like in the fractions module是给属性一个read only 属性; DataClass
模块 扩展了 __setattr__
和 __delattr__
,并覆盖了 __hash__
:
-> 使用元class.
好的资源包括@DavidBeasley 的书籍和在 python 的讲座。
-> 给属性一个只读 属性
class SimpleFrozenObject:
def __init__(self, x=0):
self._x = x
@property
def x(self):
return self._x
f = SimpleFrozenObject()
f.x = 2 # raises AttributeError: can't set attribute
-> 扩展 __setattr__
和 __delattr__
,并覆盖 `hash
class FrozenObject:
...
def __setattr__(self, name, value):
if type(self) is cls or name in (tuple of attributes to freeze,):
raise FrozenInstanceError(f'cannot assign to field {name}')
super(cls, self).__setattr__(name, value)
def __delattr__(self, name):
if type(self) is cls or name in (tuple of attributes to freeze,):
raise FrozenInstanceError(f'cannot delete field {name}')
super(cls, self).__delattr__(name, value)
def __hash__(self):
return hash((tuple of attributes to freeze,))
...
库 attrs
还提供了创建不可变对象的选项。