Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Object has no attribute '.__dict__' in python3

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?

like image 969
yelsayed Avatar asked Jan 15 '17 05:01

yelsayed


People also ask

What is the __ dict __ attribute of an object in python?

__dict__ is A dictionary or other mapping object used to store an object's (writable) attributes. Or speaking in simple words every object in python has an attribute which is denoted by __dict__. And this object contains all attributes defined for the object.

What does __ dict __ mean in python?

All objects in Python have an attribute __dict__, which is a dictionary object containing all attributes defined for that object itself. The mapping of attributes with its values is done to generate a dictionary.

What is attribute in dictionary python?

AttrDict , Attribute Dictionary, is the exact same as a python native dict , except that in most cases, you can use the dictionary key as if it was an object attribute instead. This allows users to create container objects that looks as if they are class objects (as long as the user objects the proper limitations).


2 Answers

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.

like image 59
yelsayed Avatar answered Oct 19 '22 23:10

yelsayed


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())
like image 21
Anthony Sottile Avatar answered Oct 20 '22 01:10

Anthony Sottile