假设我在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
。我不认为简单地使类可迭代将解决问题。我也尝试过许多谷歌,其中有许多不同的字词“python cast object to dict”,正如我想象的那样,却找不到任何相关内容:{
也!注意如何调用w.__dict__
不会做我想要的,因为它将包含w.version
和w.sum
。我想用dict
自定义转换为int
,就像我可以使用def int(self)
自定义转换为>>> w.__what_goes_here__()
{'a': 'one', 'c': 'three', 'b': 'two'}
一样。
我知道我可以做这样的事情
dict(w)
但我假设有一种pythonic方式使int(w)
工作,因为它是与str(w)
或Overloading __dict__() on python class相同类型的东西。如果没有更多的pythonic方式,那也没关系,我想问一下。哦!我想因为它很重要,这是针对python 2.7,但是对于2.4旧的破坏解决方案也是超级奖励积分。
还有一个问题__dict__
与此类似,但可能有足够的不同以保证这不是重复。我相信OP正在询问如何将类对象中的所有数据转换为字典。我正在寻找一种更加个性化的方法,因为我不希望dict()
中的所有内容都包含在asdict
返回的字典中。像公共变量和私有变量之类的东西可能足以解释我正在寻找的东西。这些对象将存储计算中使用的一些值,这样我就不需要/想要显示在生成的词典中。
更新:我选择了建议的asdict()
路线,但选择我想要的答案是一个艰难的选择。 @RickTeachey和@jpmc26都提供了我将要推出的答案,但前者有更多的信息和选项,并且也获得了相同的结果,并且被更多投票,所以我选择了它。尽管如此,还是全力以赴,感谢您的帮助。我已经潜伏在stackoverflow上,并且我试图让我的脚趾更多地在水中。
至少有五种方式。首选方式取决于您的用例。
选项1:只需添加asdict
方法。
根据问题描述,我会非常考虑class Wharrgarbl(object):
...
def asdict(self):
return {'a': self.a, 'b': self.b, 'c': self.c}
的做事方式由其他答案建议。这是因为您的对象看起来并不是一个集合:
_asdict
method
使用下面的其他选项可能会让其他选项感到困惑,除非确切地说明哪些对象成员将会被迭代或不被指定为键值对。
选项1a:使用'typing.NamedTuple'
提供的'collections.namedtuple'
(或大多数等同的an _asdict
method)。
使用命名元组是一种非常方便的方法,可以通过最少的工作量为您的类添加大量功能,包括_asdict
。但是,一个限制是NT将包括其_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
结果:
__iter__
另一个限制是NT是只读的。这可能是也可能不是所希望的。
选项2:实施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)
-可能实际上是在其他环境中令人惊讶的行为。例如,问自己一个问题“obj["a"]
的行为应该是什么......?”
另外,请注意,使用get item Implement语法直接访问值将不起作用,并且关键字参数解包将不起作用。对于那些,您需要实现映射协议。
选项3:mapping protocol dict
。这允许按键访问行为,在不使用__iter__
的情况下强制转换为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'}
现在你可以做以下事情:
__iter__
请注意,当直接将对象转换为dict
时,映射协议优先于dict(m)
方法(不使用kwarg解包,即list(m)
)。因此,当用作可迭代(例如,dict
)与投射到dict(m)
('collections.abc
' module)时,使对象具有不同的行为是可能的 - 并且有时是方便的。
EMPHASIZED:只是因为你可以使用映射协议,并不意味着你应该这样做。您的对象作为一组关键字参数传递实际上是否有意义?通过键访问它 - 就像字典一样 - 真的有意义吗?
如果这些问题的答案是肯定的,那么考虑下一个选项可能是个好主意。
选项4:考虑使用'collections.abc.Mapping
。
从'collections.abc.MutableMapping
或dict
继承你的类向其他用户发出信号,为了所有意图和目的,你的类是一个映射*,并且可以期望这样做。
您仍然可以根据需要将对象转换为duck typing,但可能没有理由这样做。由于dict
,在大多数情况下,将你的映射对象强制转换为This answer只会是一个额外的不必要的步骤。
dict
也许会有所帮助。
正如下面的评论中所指出的:值得一提的是,以abc方式执行此操作实质上将您的对象类转换为类似MutableMapping
的类(假设您使用Mapping
而不是只读dict
基类)。你可以用numbers
做的一切,你可以用你自己的类对象。这可能是,也可能不是。
还要考虑查看https://docs.python.org/3/library/numbers.html模块中的数字abcs:
int
既然你也把你的对象转换为int
,那么将你的类变成一个完整的dataclasses
module可能更有意义,这样就不必进行投射了。
选项5:使用asdict()
(仅限Python 3.7),包括一个方便的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}
现在你可以这样做:
dict
*“制图”已成为asdict
式鸭子的标准“名称”
没有什么神奇的方法可以做你想要的。答案就是恰当地命名。 dict
是一个合理的选择,可以简单地转换为namedtuple
,主要受到__iter__
的启发。但是,您的方法显然会包含特殊逻辑,该逻辑可能不会立即从该名称中显而易见;你只返回类'state的一个子集。如果你能想出一个稍微冗长的名字来清楚地传达这些概念,那就更好了。
其他答案建议使用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)
,但除非您的对象是真正可迭代的(代表一系列元素),否则这实际上没有多大意义,并构成了对该方法的尴尬滥用。事实上,你想要过滤掉一些类的状态,这使得这种方法更加可疑。
我认为这对你有用。
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)
{'a':1,'c':3,'b':2,'sum':6,'version':5}
像这样的东西可能会奏效
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
像许多其他人一样,我建议实现一个to_dict()函数,而不是(或除此之外)允许转换为字典。我认为这更加明显,该类支持这种功能。您可以轻松实现这样的方法:
__iter__
如果不知道问题的整个背景,很难说,但我不会覆盖__what_goes_here__
。
我会在课堂上实施as_dict(self:
d = {...whatever you need...}
return d
。
qazxswpoi