我正在观察以下行为,因为python通过引用传递了对象?
class Person(object):
pass
person = Person()
person.name = 'UI'
def test(person):
person.name = 'Test'
test(person)
print(person.name)
>>> Test
我找到了copy.deepcopy()到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
答案 0 :(得分:1)
我正在观察以下行为,因为python通过引用传递了对象?
不是。这是一个微妙的问题。您可以查看python - How do I pass a variable by reference? - Stack Overflow
我个人并不完全同意接受的答案,因此建议您使用Google call by sharing
。然后,您可以对这个微妙的问题做出自己的决定。
我找到了copy.deepcopy()到deepcopy对象,以防止修改传递的对象。还有其他建议吗?
据我所知,如果不使用第三个软件包,没有其他更好的方法了。
答案 1 :(得分:0)
您可以使用__setattr__
魔术方法来实现一个基类,该基类使您可以在完成处理后“冻结”对象。
这不是防弹的;您仍然可以访问__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
答案 2 :(得分:0)
并没有真正100%防水的方法,但是您可能会难以无意间突变想要保持冻结的对象;对于大多数人而言,推荐的方法可能是使用冻结的DataClass
或冻结的attrs
类
@RaymonHettinger在他的talk on DataClasses(2018年)中提到了三种方法:一种方法是使用元类,另一种方法是在fractions module中使用属性只读属性; DataClass
模块扩展__setattr__
和__delattr__
,并覆盖__hash__
:
好的资源包括@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__
,并覆盖`哈希 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
库还提供了创建不可变对象的选项。