在python中,如何将类对象转换为字典

比方说,我已经有了一个简单的Python类

class Wharrgarbl(object): def __init__(self, a, b, c, sum, version='old'): self.a = a self.b = b self.c = c self.sum = 6 self.version = version def __int__(self): return self.sum + 9000 def __what_goes_here__(self): return {'a': self.a, 'b': self.b, 'c': self.c} 

我可以很容易地把它转换成一个整数

 >>> w = Wharrgarbl('one', 'two', 'three', 6) >>> int(w) 9006 

太棒了! 但是,现在我想用类似的方式把它写成字典

 >>> w = Wharrgarbl('one', 'two', 'three', 6) >>> dict(w) {'a': 'one', 'c': 'three', 'b': 'two'} 

我需要什么来定义这个工作? 我试着用__dict__dict代替__what_goes_here__ ,但是dict(w)导致了TypeError: Wharrgarbl object is not iterable在两种情况下TypeError: Wharrgarbl object is not iterable 。 我不认为简单地让这个类迭代就可以解决这个问题。 我也尝试了许多与“python cast object dict”不同的字眼,但我找不到任何相关的内容:

也! 注意如何调用w.__dict__不会做我想要的,因为它将包含w.versionw.sum 。 我想自定义转换为dict ,我可以使用def int(self)自定义转换为int

我知道我可以做这样的事情

 >>> w.__what_goes_here__() {'a': 'one', 'c': 'three', 'b': 'two'} 

但是,我认为有一个pythonic的方式来使dict(w)工作,因为它是int(w)str(w)相同types的东西。 如果没有更多pythonic的方式,也没关系,只是想我会问。 哦! 我猜是因为它很重要,这是为python 2.7,但也是一个2.4旧的解决scheme,以及超级奖励点。

还有一个问题是重载Python类的__dict __() ,类似于这个,但可能会有所不同,以保证这不是重复的。 我相信OP是在问如何将他的类对象中的所有数据作为字典。 我正在寻找一种更为自定义的方法,我不希望在dict()返回的dict()包含__dict__中的所有内容。 像公共variables和私有variables可能足以解释我在找什么。 这些对象将存储计算中使用的一些值,这样我就不需要/不想出现在生成的字典中。

更新:我select了build议的asdict路线,但select我想成为问题的答案是一个艰难的select。 @RickTeachey和@ jpmc26都提供了我要回答的答案,但是前者有更多的信息和选项,并且也取得了同样的结果,而且被提高了,所以我就跟着去了。 Upvotes四周虽然,并感谢您的帮助。 我已经潜伏了很长时间,而且还努力把脚趾放在水里。

你需要重载' __iter__'

像这样,例如:

 def __iter__(self): yield 'a', self.a yield 'b', self.b yield 'c', self.c 

现在你可以做:

 dict(my_object) 

我也build议看看'collections.abc ”模块。 这个答案可能有帮助:

https://stackoverflow.com/a/27803404/2437514

具体来说,你会想看看'Mapping''MutableMapping'对象。 如果你使用这个模块,并且从类似于dict的abc中inheritance你的对象,你可以按照你的需要把你的对象转换成dict

正如在下面的评论中指出的那样:值得一提的是,以abc的方式进行这个操作,基本上可以把你的对象类变成类似dict的类。 所以你可以用dict来做所有事情,你可以用自己的类对象来做。 这可能是,也可能不是,是可取的。 这也意味着可能没有什么理由(因为鸭子打字)来打扰你的对象首先是一个dict

另外考虑看一下numbers模块中的数字abc:

https://docs.python.org/3/library/numbers.html

既然你也把你的对象强制转换为int ,那么将本质转化为完整的int可能更有意义,这样就不需要强制转换。

然而,在多思考这个问题之后,我会非常考虑其他答案所提出的asdict方式。 它似乎并不是你的对象真的是一个集合。 使用iter或abc方法可能会让其他人感到困惑,除非非常明确地知道哪些对象成员将会迭代。

没有什么神奇的方法可以做你想做的事情。 答案只是简单地命名。 asdict是一个明智的转换为dict的合理select,主要由namedtuple启发。 然而,你的方法显然会包含特殊的逻辑,这个名字可能不会立即显而易见。 你只返回类的一个子集。 如果你能想出一个稍微更详细的名字来清楚地传达这些概念,那就更好了。

其他答案build议使用__iter__ ,但除非你的对象是真正可迭代的(代表一系列元素),否则这实际上是没有意义的,并构成一个尴尬的方法滥用。 事实上,你想过滤出一些类的状态,使得这种方法更加可疑。

像这样的东西可能会工作

 class MyClass: def __init__(self,x,y,z): self.x = x self.y = y self.z = z def __iter__(self): #overridding this to return tuples of (key,value) return iter([('x',self.x),('y',self.y),('z',self.z)]) dict(MyClass(5,6,7)) # because dict knows how to deal with tuples of (key,value) 

我认为这会为你工作。

 class A(object): def __init__(self, a, b, c, sum, version='old'): self.a = a self.b = b self.c = c self.sum = 6 self.version = version def __int__(self): return self.sum + 9000 def __iter__(self): return self.__dict__.iteritems() a = A(1,2,3,4,5) print dict(a) 

产量

{'a':1,'c':3,'b':2,'sum':6,'version':5}

如果不知道问题的整个上下文很难说,但我不会覆盖__iter__

我会在课堂上实现__what_goes_here__

 as_dict(self: d = {...whatever you need...} return d 

像其他许多人一样,我会build议实现一个to_dict()函数,而不是(或除了)允许转换成字典。 我认为这更明显的是,这个类支持这种function。 你可以很容易地实现这样的方法:

 def to_dict(self): class_vars = vars(MyClass) # get any "default" attrs defined at the class level inst_vars = vars(self) # get any attrs defined on the instance (self) all_vars = dict(class_vars) all_vars.update(inst_vars) # filter out private attributes public_vars = {k: v for k, v in all_vars.items() if not k.startswith('_')} return public_vars