在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。我不认为简单地使类可迭代即可解决问题。我也尝试过许多Google,尽我所能想到但找不到任何相关的词:“ python dict to

dict”

也!请注意,调用w.__dict__将不会执行我想要的操作,因为它将包含w.versionand

w.sum。我想投定制dict以同样的方式,我可以自定义投地int使用def int(self)

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

>>> w.__what_goes_here__()

{'a': 'one', 'c': 'three', 'b': 'two'}

但是我假设有一种pythonic的dict(w)工作方式,因为它与int(w)or属于同一类型str(w)。如果没有更Python的方式,那也很好,只是想知道我会问。哦!

我想因为这很重要,所以这是针对python 2.7的,但是对于2.4老旧的解决方案也有超级加分。

在python类上还有另一个问题,就是重载__dict

__()与此类似,但可能有很大的不同,以保证不会重复。我相信OP正在询问如何将其类对象中的所有数据转换为字典。我正在寻找一种更具个性化的方法,因为我不希望__dict__包含的所有内容都包含在返回的字典中dict()。诸如公共变量和私有变量之类的东西可能足以解释我在寻找什么。这些对象将存储一些在计算中使用的值,这样我就不需要/不想在结果字典中显示出来。

更新:我选择了asdict建议的路线,但选择我想成为该问题的答案的确是一个艰难的选择。@RickTeachey和@

jpmc26都提供了我要介绍的答案,但是前者具有更多信息和选项,并且也获得了相同的结果,并且被更多投票,所以我选择了它。尽管各地都支持,并感谢您的帮助。我在stackoverflow上潜伏了很长时间,并且努力将自己的脚趾更多地浸入水中。

回答:

至少有 六种方式。首选方式取决于您的用例。

只需添加一个asdict()方法。

基于问题描述,我会非常考虑asdict其他答案建议的处理方式。这是因为看来您的对象实际上并不是一个集合:

class Wharrgarbl(object):

...

def asdict(self):

return {'a': self.a, 'b': self.b, 'c': self.c}

使用以下其他选项可能会使其他人感到困惑,除非非常明显地知道哪些对象成员将被或不会被迭代或指定为键值对。

'typing.NamedTuple'(或几乎等价的'collections.namedtuple')继承您的类,并使用为您提供的_asdict方法。

from typing import NamedTuple

class Wharrgarbl(NamedTuple):

a: str

b: str

c: str

sum: int = 6

version: str = 'old'

使用命名元组是一个以大量的功能添加到您的类用最少的努力,包括非常方便的方法的_asdict方法。但是,有一个限制是,如上所述,NT将在其中包括

所有 成员_asdict

如果有些成员不想包含在字典中,则需要修改_asdict结果:

from typing import NamedTuple

class Wharrgarbl(NamedTuple):

a: str

b: str

c: str

sum: int = 6

version: str = 'old'

def _asdict(self):

d = super()._asdict()

del d['sum']

del d['version']

return d

另一个限制是NT是只读的。这可能是理想的,也可能不是理想的。

实施__iter__

像这样,例如:

def __iter__(self):

yield 'a', self.a

yield 'b', self.b

yield 'c', self.c

现在您可以执行以下操作:

dict(my_object)

dict()是可行的,因为构造函数接受可重复的(key,

value)成对构造字典。在执行此操作之前,请先问自己一个问题,即在方便创建对象的情况下,以这种方式将对象作为一系列键,值对进行迭代dict在其他情况下实际上可能是令人惊讶的行为。例如,问自己一个问题:“

list(my_object)……的行为应该是什么?”

此外,请注意,直接使用get itemobj["a"]语法访问值将不起作用,并且关键字参数解压缩将不起作用。对于这些,您需要实现映射协议。

实施所述映射协议。这允许按键访问行为,dict而无需使用强制转换为__iter__,并且{**my_obj}如果所有键都是字符串(dict(**my_obj)),则还提供了拆包行为()和关键字拆包行为。

映射协议要求您(至少)同时提供两种方法:keys()__getitem__

class MyKwargUnpackable:

def keys(self):

return list("abc")

def __getitem__(self, key):

return dict(zip("abc", "one two three".split()))[key]

现在您可以执行以下操作:

>>> m=MyKwargUnpackable()

>>> m["a"]

'one'

>>> dict(m) # cast to dict directly

{'a': 'one', 'b': 'two', 'c': 'three'}

>>> dict(**m) # unpack as kwargs

{'a': 'one', 'b': 'two', 'c': 'three'}

如上所述,如果您使用的是足够新的python版本,您还可以像这样将您的映射协议对象解压缩到字典理解中(在这种情况下,不需要您的键是字符串):

>>> {**m}

{'a': 'one', 'b': 'two', 'c': 'three'}

请注意,在将对象直接投射到直接对象时(不使用kwarg解包,即),映射协议 优先于

__iter__方法。因此,当将对象用作可迭代对象(例如)与强制转换为()时,可能导致对象具有不同的行为。dict``dict(m)``list(m)``dict``dict(m)

:仅因为您可以使用映射协议, 并不意味着您 这样做。将对象作为一组键值对或作为关键字参数和值来传递,这实际上 有意义

吗?像字典一样,通过键访问它真的有意义吗?

如果这些问题的答案是 肯定的 ,那么考虑下一个选择可能是一个好主意。

使用'collections.abc‘模块。

出于所有意图和目的,从其他用户继承您的类'collections.abc.Mapping'collections.abc.MutableMapping向其他用户发出信号,即您的类

是一个映射 *,可以预期会以这种方式运行。

您仍然可以将对象dict强制转换为所需的对象,但是这样做的理由可能很少。由于使用鸭子输入,dict在大多数情况下,麻烦将映射对象转换为a只是额外的不必要步骤。

如下面的注释中所述:值得一提的是,使用abc方法本质上将您的对象类转换为类似dict类(假设您使用的MutableMapping是只读Mapping基类,而不是只读基类)。您可以使用的所有内容dict,也可以使用自己的类对象。这可能是理想的,也可能不是理想的。

还可以考虑查看numbers模块中的数字abcs :

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

由于您也将对象强制转换为int,因此从本质上将您的类转换为完全成熟的类可能更为有意义,int因此无需强制转换。

使用dataclasses模块(仅适用于Python

3.7),该模块包含一种方便的asdict()实用程序方法。

from dataclasses import dataclass, asdict, field, InitVar

@dataclass

class Wharrgarbl(object):

a: int

b: int

c: int

sum: InitVar[int] # note: InitVar will exclude this from the dict

version: InitVar[str] = "old"

def __post_init__(self, sum, version):

self.sum = 6 # this looks like an OP mistake?

self.version = str(version)

现在您可以执行以下操作:

    >>> asdict(Wharrgarbl(1,2,3,4,"X"))

{'a': 1, 'b': 2, 'c': 3}

Use

typing.TypedDict,已在python

3.8中添加。

注意:选项6可能 OP或基于此问题标题的其他读者所寻找的。请参阅下面的其他注释。

class Wharrgarbl(TypedDict):

a: str

b: str

c: str

使用此选项,得到的对象 dict(强调:这是 不是 一个Wharrgarbl)。完全没有理由将其“投射”到字典中(除非您要进行复制)。

并且由于对象 是adict,因此初始化签名与的签名相同,dict因此它仅接受关键字参数或其他字典。

    >>> w = Wharrgarbl(a=1,b=2,b=3)

>>> w

{'a': 1, 'b': 2, 'c': 3}

>>> type(w)

<class 'dict'>

强调 :上述“类”Wharrgarbl实际上根本不是一个新类。它只是语法糖,dict用于为类型检查器创建具有不同类型字段的类型化对象。

这样,此选项可以非常方便地向您的代码阅读器(以及向类型检查器(如mypy))发信号,告知此类dict对象应该具有具有特定值类型的特定键。

但这意味着您无法添加其他方法,尽管您可以尝试:

class MyDict(TypedDict):

def my_fancy_method(self):

return "world changing result"

…但是它不起作用:

>>> MyDict().my_fancy_method()

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

AttributeError: 'dict' object has no attribute 'my_fancy_method'


*“映射”已成为dict类鸭类型的标准“名称”

以上是 在python中,如何将类对象转换为字典 的全部内容, 来源链接: utcz.com/qa/409279.html

回到顶部