gpt4 book ai didi

python - 属性与前面的属性赋值操作的右侧值不同

转载 作者:太空宇宙 更新时间:2023-11-03 14:39:35 25 4
gpt4 key购买 nike

这个问题表面上看起来像是重复的,但它不是关于通常的 mutable surprise带有列表。

稍后会详细介绍,但简而言之,就在

self.facts = facts
print("facts: ", id(facts))
print("self.facts: ", id(self.facts))

有时 self.factsfacts 并不相同。

app是单线程的,区别还是有的,所以它不是似乎是竞争条件或缓冲区延迟。

我确实清除了缓存:找到。 -name "*.pyc"-delete

我试着想出一个 mcve ,但无法重现错误。这是一个尝试。

class Fact():
def __init__(self, a):
self.a = a
def __eq__(self, other):
return self.a == self.b

facts1 = [Fact(1), Fact(2), Fact(3)]
id(facts1)
facts2 = facts1
id(facts2)
# same as facts1
facts3 = [Fact(1), Fact(2), Fact(3)]
id(facts3)
facts2 = facts3
id(facts2)
# same as fact3, as it should

可以在 this issue 中找到快照和重现步骤.

只要 __eq__expanded还要检查确实发生变化的字段,factsself.facts 都包含相等的元素(在 __eq__ 的意义上),非常好足够,但不完全相同,这仍然很奇怪。

这是已知的吗?这是我的 python 版本:

Python 3.6.5 (default, Mar 31 2018, 19:45:04) [GCC] on linux
on openSUSE Leap 15.0

可能会发生什么?

最佳答案

这种行为可能是由许多因素引起的,所有因素都控制如何访问对象的属性。从这个意义上说,self.x = yx = y 有很大不同。前者尝试用 y 设置属性 "x"在对象 self 上,而后者将名称 "x" 绑定(bind)到本地范围内的对象 y

描述符

Descriptors可以控制属性如何通过定义特殊方法 __get__, __set__, __delete__ 来处理。一个例子:

from copy import copy

class Descriptor:
def __get__(self, obj, cls):
return copy(self.list_obj) # Return a copy -> id changes.

def __set__(self, obj, val):
self.list_obj = copy(val) # Store a copy -> id changes.

class Foo:
facts = Descriptor()

facts = [1, 2, 3]
obj = Foo()
obj.facts = facts
assert id(obj.facts) != id(facts) # ids are different.

属性

property可能是最突出的使用场景之一数据描述符。因此工作原理非常相似:

from copy import copy

class Foo:
@property
def facts(self):
return copy(self._facts) # Return a copy -> id changes.

@facts.setter
def facts(self, val):
self._facts = copy(val) # Store a copy -> id changes.

facts = [1, 2, 3]
obj = Foo()
obj.facts = facts
assert id(obj.facts) != id(facts) # ids are different.

__getattr____setattr__

通过定义方法 __getattr____setattr__一个类可以控制属性访问它的实例。例如:

from copy import copy

class Foo:
def __getattr__(self, name):
return copy(super().__getattr__(name)) # Return a copy -> id changes.

def __setattr__(self, name, val):
super().__setattr__(name, copy(val)) # Store a copy -> id changes.

facts = [1, 2, 3]
obj = Foo()
obj.facts = facts
assert id(obj.facts) != id(facts) # ids are different.

如何找出拦截属性访问的内容?

您可以检查type(obj).facts 以查明facts 是否被定义为描述符。类似地,您可以检查 type(obj).__(get|set)attr__ 以查看基类中是否定义了任何这种特殊的方法。这里值得注意的是,如果定义了上述任何方法,它也可以工作在方法解析顺序中的任何类(__mro__,即父类)。所以你需要检查例如:

any('__getattr__' in vars(cls) for cls in type(obj).__mro__)

OP的具体例子

您链接的类继承自 this class它定义了 __setattr__以它检查的方式对于具有现有值的相等(==;不是同一性()),如果它们比较相等则返回。这意味着如果你有两个比较相等的列表,即 self.facts == facts,那么执行 self.facts = facts 只会返回而不设置属性。因此没有任何改变并且这两个对象(self.factsfacts)仍然是不同的。代码基本上归结为:

class Foo:
def __setattr__(self, name, val):
if self.__dict__.get(name, None) == val: # Could also use `getattr(self, name, None)`.
return
super().__setattr__(name, val)

facts = [1, 2, 3]
obj = Foo()
obj.facts = [1, 2, 3]
assert obj.facts == facts # The two lists compare equal,
obj.facts = facts # hence nothing will happen here,
assert obj.facts == facts # they still compare equal,
assert id(obj.facts) != id(facts) # but are still two distinct objects.

关于python - 属性与前面的属性赋值操作的右侧值不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54393731/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com