我在Python 2.7上使用 AttrDict 2.0时遇到了一个奇怪的重复错误。奇怪的是,传递分配似乎破裂了,但只有在使用AttrDict时才会破坏。
发生的事情是,如果某个对象不存在,我想在对象上实例化一个新列表,然后将数据附加到该对象上。
如果我使用AttrDict,列表会以某种方式转换为元组,我会得到一个异常。
from attrdict import AttrDict
class Test(object):
pass
try:
for cls_ in [Test,AttrDict]:
foo = cls_()
print ("\ntesting with class %s" % (cls_))
#this
chk = foo.li = getattr(foo, "li", None) or []
print(" type(chk):%s, id(chk):%s" % (type(chk),id(chk)))
print(" type(foo.li):%s, id(foo.li):%s" % (type(foo.li),id(foo.li)))
foo.li.append(3)
print (" success appending with class %s: foo.li:%s" % (cls_, foo.li))
except (Exception,) as e:
# pdb.set_trace()
raise
现在查看输出,当我使用Test
类时使用AttrDict
时。
testing with class <class '__main__.Test'>
type(chk):<type 'list'>, id(chk):4465207704
type(foo.li):<type 'list'>, id(foo.li):4465207704
success appending with class <class '__main__.Test'>: foo.li:[3]
根据预期,自定义Test
类,chk
和foo.li
都是列表,并且具有相同的id
。附加作品。
使用AttrDict查看传递,id
不匹配,foo.li
是元组而不是列表。
testing with class <class 'attrdict.dictionary.AttrDict'>
type(chk):<type 'list'>, id(chk):4465207848
type(foo.li):<type 'tuple'>, id(foo.li):4464595080
Traceback (most recent call last):
File "test_attrdict2.py", line 25, in <module>
test()
File "test_attrdict2.py", line 18, in test
foo.li.append(3)
AttributeError: 'tuple' object has no attribute 'append'
attrdict赋值实际上是否会返回某些属性/访问者对象,第二次访问它时会被更改?
接受了@ abartnet的建议:
from attrdict import AttrDict
a = AttrDict()
a.li = []
print(a.li)
输出:
()
好的,但即使这指出了AttrDict结束时的一些奇怪的行为,传递分配如何也不分配元组?
返工:
from attrdict import AttrDict
a = AttrDict()
b = a.li = []
print("a.li:", a.li)
print("b:",b)
输出:
('a.li:', ())
('b:', [])
答案 0 :(得分:2)
这是AttrDict
的自动递归的一部分。内联help
(您可以在源代码中找到here)比在README中更好地解释了这一点:
如果作为属性访问的值是Sequence-type(并且不是字符串/字节),则它将转换为_sequence_type,其中的任何映射都转换为Attrs。
换句话说,为了在执行属性访问时在dict
到AttrDict
值内递归地自动转换任何AttrDict
或其他映射,它还会将所有序列转换为(通过默认)tuple
。这有点奇怪,但似乎是故意的,有些记录的行为,而不是错误。
>>> a = AttrDict()
>>> a._sequence_type
tuple
>>> a.li = []
>>> a.li
()
更灵活的AttrMap
类型允许您指定序列类型,以及通过传递None
来禁用此递归重新映射内容的文档:
>>> a = AttrMap(sequence_type=None)
>>> a.li = []
>>> a.li
[]
但当然AttrMap
不是dict
(尽管它是collections.abc.MutableMapping
,更常见的是鸭子类型为dict
- 类型)。
好的,但即使这指向了AttrDict结尾的一些奇怪行为,传递分配如何也不分配元组?
因为这不是链式分配的工作方式。过度简化:
target1 = target2 = value
......不等于此:
target2 = value
target1 = target2
......但是对此:
target2 = value
target1 = value
理解为什么这是真的最好方法:目标不是表达式,因此没有值。当然,通常完全相同的标记序列将作为语法中其他地方的表达式有效,但该标记序列永远不会在赋值语句中的任何位置被评估为表达式 - 否则,简单的事情如{如果d['spam'] = 'eggs'
不存在,{1}}必须提出异常。
此外,d['spam']
实际上并未将a.li = []
分配到任何地方;它实际上会在内部存储tuple([])
,并在您尝试访问[]
时执行tuple(…)
。如果没有阅读消息来源,你无法确定这一点,但是当你认为a.li
给你a['li']
而不是[]
时,它几乎必须是真的。事实上:
()