在Python2.7上使用AttrDict时出现奇怪的错误
在Python2.7上使用AttrDict2.0时,我遇到了一个奇怪的重复错误。奇怪的是,传递赋值似乎会中断,但只有在使用AttrDict时才会中断 发生的事情是,如果一个对象不存在,我想在该对象上实例化一个新列表,然后向其追加数据 如果我使用AttrDict,列表会以某种方式转换为元组,我会得到一个异常在Python2.7上使用AttrDict时出现奇怪的错误,python,python-2.7,Python,Python 2.7,在Python2.7上使用AttrDict2.0时,我遇到了一个奇怪的重复错误。奇怪的是,传递赋值似乎会中断,但只有在使用AttrDict时才会中断 发生的事情是,如果一个对象不存在,我想在该对象上实例化一个新列表,然后向其追加数据 如果我使用AttrDict,列表会以某种方式转换为元组,我会得到一个异常 from attrdict import AttrDict class Test(object): pass try: for cls_ in [Test,AttrDic
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]
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:', [])
这是
AttrDict
自动递归的一部分。与自述文件相比,内联帮助
(您可以在源代码中找到)中更好地解释了这一点:
如果作为属性访问的值是序列类型(而不是字符串/字节),它将转换为_Sequence_类型,其中的任何映射都将转换为Attrs
换句话说,为了在执行属性访问时将AttrDict
中的任何dict
或其他映射递归地自动转换为AttrDict
值,它还将所有序列转换为(默认情况下)元组。这有点奇怪,但似乎是故意的,并且有一些记录在案的行为,而不是bug
>>> 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
……但对此:
target2 = value
target1 = target2
target2 = value
target1 = value
理解这一点的最佳方式是:目标不是表达式,因此没有值。当然,通常完全相同的标记序列作为语法中其他地方的表达式是有效的,但该标记序列在赋值语句中的任何地方都不会作为表达式进行计算,否则,如果d['spam']='egs'
不存在,则像d['spam']
这样的简单操作将不得不引发异常
而且,a.li=[]
实际上并不在任何地方分配元组([])
;它实际上在内部存储[]
,并在稍后尝试访问a.li
时执行元组(…)
。在没有阅读源代码的情况下,你不能确切地说出这一点,但是当你认为<>代码> ['Li ] 给你<代码> []/Cord>而不是<代码>()<代码>时,它几乎必须是真的。事实上:
>>> li = []
>>> a.li = li
>>> a['li'] is li
True
您应该能够在不使用所有其他东西的情况下对其进行测试:如果只执行a=AttrDict(),会发生什么;a、 li=[];打印(a.li)
?是[]
还是()
?如果是后者,那么你问题中的所有其他内容都是无关的。我添加chk只是为了尝试调试,它以前是坏的。测试类是为了确保我没有搞乱属性初始化,它似乎指出了AttrDict的一个问题。但是,是的,我会添加您的建议。这似乎是AttrDict
的预期行为,即使自述文件中没有对此进行很好的解释。因此,传递性作业中的每个目标都会得到列表。AttrDict将其转换为元组,但这是它的业务,在我的示例中不影响对chk
/b
的赋值?有道理。@JLPeyret完全正确。事实上,如果您通读源代码,AttrDict
现在甚至不会将其转换为元组,但只有在以后,当您通过a.li
访问它时才会将其转换为元组。这就是为什么a['li']
仍然可以工作的原因。