小编典典
至少有 五 六种方式。首选方式取决于您的用例。
选项1: 只需添加一个asdict()方法。
基于问题描述,我会非常考虑asdict其他答案建议的处理方式。这是因为看来您的对象实际上并不是一个集合:
class Wharrgarbl(object):
...
def asdict(self):
return {'a': self.a, 'b': self.b, 'c': self.c}
使用以下其他选项可能会使其他人感到困惑,除非非常明显地知道哪些对象成员将被或不会被迭代或指定为键值对。
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是只读的。这可能是理想的,也可能不是理想的。
像这样,例如:
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"]语法访问值将不起作用,并且关键字参数解压缩将不起作用。对于这些,您需要实现映射协议。
方案3: 实施所述映射协议。这允许按键访问行为,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.Mapping或'collections.abc.MutableMapping向其他用户发出信号,即您的类
是一个映射 *,可以预期会以这种方式运行。
您仍然可以将对象dict强制转换为所需的对象,但是这样做的理由可能很少。由于使用鸭子输入,dict在大多数情况下,麻烦将映射对象转换为a只是额外的不必要步骤。
如下面的注释中所述:值得一提的是,使用abc方法本质上将您的对象类转换为类似dict类(假设您使用的MutableMapping是只读Mapping基类,而不是只读基类)。您可以使用的所有内容dict,也可以使用自己的类对象。这可能是理想的,也可能不是理想的。
还可以考虑查看numbers模块中的数字abcs :
由于您也将对象强制转换为int,因此从本质上将您的类转换为完全成熟的类可能更为有意义,int因此无需强制转换。
选项5:研究
使用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}
注意:选项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)
强调 :上述“类”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 "", line 1, in
AttributeError: 'dict' object has no attribute 'my_fancy_method'
*“映射”已成为dict类鸭类型的标准“名称”
2020-12-20