python 对象转字典及序列化对象相关问题,__dict__!!!!必看,多坑

目录

__dict__只能存储实例变量,不能存储类变量

情况一:(可以直接通过__dict__序列化对象)

情况二:(不能直接通过__dict__序列化对象)

情况三:(定义keys和__getitem__方法)

关于细节方面的测试


先给结论:python不能直接序列化对象(往下看)

对于普通得python对象来说,__dict__就可以序列化对象。

__dict__的作用:把类的实例对象的实例属性以字典形式返回。简单的说就是 用来存储实例变量


__dict__只能存储实例变量,不能存储类变量

python 对象转字典及序列化对象相关问题,__dict__!!!!必看,多坑_第1张图片


情况一:(可以直接通过__dict__序列化对象)

python 对象转字典及序列化对象相关问题,__dict__!!!!必看,多坑_第2张图片


情况二:(不能直接通过__dict__序列化对象)

但是如果对象里面的属性又是另外一个对象,那么这样就很容易出现递归好多对象,这样就无法直接序列化了。

情况如下图:

python 对象转字典及序列化对象相关问题,__dict__!!!!必看,多坑_第3张图片

解决办法:

在代码中设置一个默认方法,按照下面写就行

整体测试代码如下:

python 对象转字典及序列化对象相关问题,__dict__!!!!必看,多坑_第4张图片

情况三:(定义keys和__getitem__方法)

python 对象转字典及序列化对象相关问题,__dict__!!!!必看,多坑_第5张图片

注意上图return的一定要是个序列,可以是元组也可以是列表。

使用dict的方式如下, 如果直接使用会报错.

a = A()
dict(a)

使用dict之时,将自动调用类中的keys方法,keys中定义了字典的键,调用keys方法后,程序将依照字典取值的方式尝试获得这些键对应的值。
当使用如字典的取值方式时: 比如a['name'],可以看到a['name']这样的方式是用来访问一个字典的,但是很明显我们的a不是一个字典,而是一个对象,如果对象想以a['name']这样的方式访问,我们就需要为对象增加一个方法叫__getitem__,当python遇到  对象[]  的方式的时候就会调用类中的__getitem__方法, 然后把name当做item参数传递进来,__getitem__方法返回的这个值就是a['name']所调用的结果
因此只需要在一例中添加两个方法就可以使对象可以通过dict转字典:

def keys(self):
    return ('name', 'age' )
 
def __getitem__(self, item):
    return getattr(self, item)

通过这种方式, 既可以支持类变量的转换, 又可以自定义需要转换的字段.

完整代码:

class A(object):
    name = 'jenrey'
    age = 18
 
    def __init__(self):
        self.gender = 'male'
 
    def keys(self):
        '''当对实例化对象使用dict(obj)的时候, 会调用这个方法,这里定义了字典的键, 其对应的值将以obj['name']的形式取,
        但是对象是不可以以这种方式取值的, 为了支持这种取值, 可以为类增加一个方法'''
        return ('name', 'age', 'gender')
 
    def __getitem__(self, item):
        '''内置方法, 当使用obj['name']的形式的时候, 将调用这个方法, 这里返回的结果就是值'''
        return getattr(self, item)
 
a = A()
r = dict(a)
print(r)

关于细节方面的测试

class D:
    name = 'zhangsan'
    age = 18

    def __init__(self):
        self.sex = '男'

    def keys(self):
        return ('name', 'age', 'sex')

    def __getitem__(self, item):
        return "111"


d = D()
print(d.__dict__)  # {'sex': '男'}
print(dict(d))  # {'name': '111', 'age': '111', 'sex': '111'}

如何通过对象下面的属性名字来拿到这个属性的值呢? 

就需要使用getattr方法(下图)

class D:
    name = 'zhangsan'
    age = 18

    def __init__(self):
        self.sex = '男'

    def keys(self):
        return ('name', 'sex')

    def __getitem__(self, item):
        return getattr(self, item)


d = D()
print(d.__dict__)  # {'sex': '男'}
print(dict(d))  # {'name': 'zhangsan', 'sex': '男'} 如果注销了getitem方法就会报错TypeError: 'D' object is not iterable

 keys方法只return一个只有一个元素的元组的时候会报错AttributeError: 'D' object has no attribute 'n'

class D:
    name = 'zhangsan'
    age = 18

    def __init__(self):
        self.sex = '男'

    def keys(self):
        return ('name')

    def __getitem__(self, item):
        return getattr(self, item)


d = D()
print(d.__dict__)  # {'sex': '男'}
print(dict(d))  # keys方法只return一个的时候会报错AttributeError: 'D' object has no attribute 'n'

为什么是n呢?而且报错的时候是在getattr方法的时候报错的,这就说明这个getitem方法的形参item传入的是一个n而不是name,这是因为我们想的是 return('name')只是定义了一个元素的元组,但是一个元素的元组不是这么定义的,而是要在后面加入一个,号!return('name',)

class D:
    name = 'zhangsan'
    age = 18

    def __init__(self):
        self.sex = '男'

    def keys(self):
        return ('name',)

    def __getitem__(self, item):
        return getattr(self, item)


d = D()
print(d.__dict__)  # {'sex': '男'}
print(dict(d))  # 注意定义一个元素的元组的时候要在后面加上逗号 {'name': 'zhangsan'}

class D:
    name = 'zhangsan'
    age = 18

    def __init__(self):
        self.sex = '男'

    def keys(self):
        return ['name']  # 是用列表也是可以的,只要是返回序列类型的就可以

    def __getitem__(self, item):
        return getattr(self, item)


d = D()
print(d.__dict__)  # {'sex': '男'}
print(dict(d))  # {'name': 'zhangsan'}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(Python)