问题
I have a test that passes in Python2 and fails in Python3, I'm trying to find out why. The test fails at the following line:
self._timeseries[0].resource.__dict__
With the error:
AttributeError: 'Resource' object has no attribute '__dict__'
If I debug the test, and print the object in the debugger, I can see the following:
(Pdb) p self._timeseries[0].resource.__dict__
OrderedDict([('type', 'type_value'), ('labels', {'label1': 'value1', 'label2': 'value2', 'label3': 'value3'})])
If I do the same in Python3 debugger, I get this:
(Pdb) p self._timeseries[0].resource.__dict__
*** AttributeError: 'Resource' object has no attribute '__dict__'
Any ideas why this might be happening? The object looks exactly the same if I print it in the debugger without the .__dict__
, why is this failing for Python3?
回答1:
So I found the answer after some digging, this indeed is a difference between Python2 and Python3, a nuisant one at that.
It turns out the type Resource
in the code is actually a named tuple. In Python2, .__dict__
is added as convenient property wrapper of ._asdict()
, but this isn't done in Python3:
https://docs.python.org/2/library/collections.html#collections.somenamedtuple._asdict (find __dict__
here)
https://docs.python.org/3/library/collections.html#collections.somenamedtuple._asdict
So it looks like ._asdict
is in fact the source of truth, and should be used for portable 2to3 code.
It's worth mentioning that vars
is also a wrapper that exists in Python2 only.
回答2:
I wrote a little function, I'm probably missing a few edge cases but it satisfied the few little testcases I wrote (probably broken for multiple inheritance)
class C(object):
def __init__(self):
self.x = 1
self.y = 1
class D(object):
__slots__ = ('x', 'y')
def __init__(self):
self.x = 1
self.y = 1
class E(D):
__slots__ = ()
class F(D):
__slots__ = ('z',)
def __init__(self):
super(F, self).__init__()
self.z = 1
def vars2(x):
if hasattr(x, '__dict__'):
return vars(x)
else:
ret = {slot: getattr(x, slot) for slot in x.__slots__}
for cls in type(x).mro():
spr = super(cls, x)
if not hasattr(spr, '__slots__'):
break
for slot in spr.__slots__:
ret[slot] = getattr(x, slot)
return ret
def main():
print(vars2(C()))
print(vars2(D()))
print(vars2(E()))
print(vars2(F()))
OUTPUT = '''\
{'y': 1, 'x': 1}
{'y': 1, 'x': 1}
{'y': 1, 'x': 1}
{'y': 1, 'x': 1, 'z': 1}
'''
if __name__ == '__main__':
exit(main())
来源:https://stackoverflow.com/questions/41658015/object-has-no-attribute-dict-in-python3