我们说我在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对象的多种不同措辞,以及#34;我能想到但却无法找到相关内容:{
另外!请注意,调用w.__dict__
不会做我想做的事情,因为它会包含w.version
和w.sum
。我希望自定义转换为dict
,方法与使用int
自定义转换为def int(self)
的方式相同。
我知道我可以做这样的事情
>>> w.__what_goes_here__()
{'a': 'one', 'c': 'three', 'b': 'two'}
但我假设有一种pythonic方法可以使dict(w)
起作用,因为它与int(w)
或str(w)
属于同一类型。如果没有更多的pythonic方式,这也很好,只是想我会问。哦!我想,因为它很重要,这是针对python 2.7,但也是一个2.4旧的破坏点的超级奖励积分。
还有另一个问题Overloading __dict__() on python class与此类似,但可能有所不同,以保证这不是重复。我相信OP正在询问如何将类对象中的所有数据转换为字典。我正在寻找一种更加个性化的方法,因为我不希望__dict__
中包含的dict()
中的所有内容都包含在asdict
中。像公共变量和私有变量之类的东西可能足以解释我正在寻找的东西。这些对象将存储计算中使用的一些值,这样我就不需要/想要显示在结果词典中。
更新:
我已选择使用建议的get("/*", BaseWebApp::notFound, new JsonTransformer());
put("/*", BaseWebApp::notFound, new JsonTransformer());
post("/*", BaseWebApp::notFound, new JsonTransformer());
delete("/*", BaseWebApp::notFound, new JsonTransformer());
路线,但选择我想要的答案是一个艰难的选择。 @RickTeachey和@ jpmc26都提供了我即将推出的答案,但前者有更多的信息和选项,同样也获得了相同的结果,并且被更多投票,所以我选择了它。尽管如此,还是全力以赴,感谢您的帮助。我已经潜伏了很长时间并且很难进行堆叠溢出,而且我试图让我的脚趾在水中更多。
答案 0 :(得分:54)
至少有五种方法。首选方式取决于您的用例。
选项1:只需添加asdict()
方法。
根据问题描述,我会非常考虑其他答案所建议的asdict
做事方式。这是因为您的对象看起来并不是一个集合:
class Wharrgarbl(object):
...
def asdict(self):
return {'a': self.a, 'b': self.b, 'c': self.c}
使用下面的其他选项可能会让其他选项感到困惑,除非确切地说明哪些对象成员将被迭代或不被迭代或指定为键值对。
选项1a:使用_asdict
method提供的'typing.NamedTuple'
(或大致相同的'collections.namedtuple'
)。
使用命名元组是一种非常方便的方法,可以轻松地为您的班级添加大量功能,包括an _asdict
method。但是,一个限制是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是只读的。这可能是也可能不是。
选项2:实施__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 item obj["a"]
语法直接访问值将不起作用,并且关键字参数解包不会起作用。对于那些,您需要实现映射协议。
选项3: Implement 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
方法(不使用kwarg解包,即dict(m)
) 。因此,当用作可迭代(例如list(m)
)与转换为dict
(dict(m)
)时,导致对象具有不同的行为是可能的 - 有时是方便的。
EMPHASIZED :仅仅因为您可以使用映射协议,并不意味着您应该这样做 。实际上有意义您的对象是作为一组关键字参数传递的吗?通过键访问它 - 就像字典一样 - 真的有意义吗?
如果这些问题的答案是是,那么考虑下一个选项可能是个好主意。
选项4:请使用'collections.abc
' module。
将您的班级从'collections.abc.Mapping
或'collections.abc.MutableMapping
信号传递给其他用户,出于所有意图和目的,您的班级是一个映射 *并且可以预期其行为方式。
您仍然可以根据需要将对象转换为dict
,但可能没有理由这样做。由于duck typing,在大多数情况下,将映射对象强制转换为dict
只会是一个额外的不必要的步骤。
This answer也可能会有所帮助。
如下面的评论中所述:值得一提的是,使用abc方式实际上将您的对象类转换为类似dict
的类(假设您使用MutableMapping
而不是只读Mapping
基类)。你可以使用dict
做的所有事情,你可以使用自己的类对象。这可能是,也可能不是。
还要考虑查看numbers
模块中的数字abcs:
https://docs.python.org/3/library/numbers.html
由于您还要将对象投射到int
,因此将您的课程转变为完全成熟的int
可能更有意义,因此无需投射。
选项5:查看使用dataclasses
module(仅限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}
*"制图"已成为标准"名称" dict
- 像鸭子类型
答案 1 :(得分:17)
没有神奇的方法可以做你想要的。答案就是恰当地命名。对于asdict
的简单转换,dict
是一个合理的选择,主要受namedtuple
启发。但是,您的方法显然会包含特殊逻辑,该逻辑可能不会立即从该名称中显而易见;你只返回类'state的一个子集。如果你能提出一个稍微冗长的名字,清楚地传达概念,那就更好了。
其他答案建议使用__iter__
,但除非您的对象是真正可迭代的(代表一系列元素),否则这实际上没什么意义,并且构成了对该方法的笨拙滥用。事实上,你想要过滤掉某些类的状态,这使得这种方法更加可疑。
答案 2 :(得分:9)
这样的事情可能会起作用
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)
答案 3 :(得分:9)
我认为这对你有用。
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}
答案 4 :(得分:3)
与许多其他人一样,我建议实现一个to_dict()函数而不是(或者除此之外)允许转换为字典。我认为这更加明显,该类支持这种功能。您可以轻松实现这样的方法:
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
答案 5 :(得分:2)
如果不了解问题的整个背景,很难说,但我不会覆盖__iter__
。
我会在课堂上实现__what_goes_here__
。
as_dict(self:
d = {...whatever you need...}
return d
答案 6 :(得分:1)
这是非常干净和快速的解决方案 我创建了一个函数,可以将任何自定义类转换为 dict
def convert_to_dict(args: dict):
json = dict()
for key, value in args.items():
key_vals = str(key).split("_")
last_index = len(key_vals)
json[str(key_vals[last_index-1])] = value
return json
你需要的是提供它 object.__dict__
然后它会帮你清理它并帮助你将它存储在数据库中。
答案 7 :(得分:0)
我正在尝试编写一个list
或dict
都属于的类。我希望程序员能够同时将此对象“投射”到list
(放下键)或dict
(带有键)。
看看Python当前执行dict()
强制转换的方式:它使用传递的对象调用Mapping.update()
。这是the code from the Python repo:
def update(self, other=(), /, **kwds):
''' D.update([E, ]**F) -> None. Update D from mapping/iterable E and F.
If E present and has a .keys() method, does: for k in E: D[k] = E[k]
If E present and lacks .keys() method, does: for (k, v) in E: D[k] = v
In either case, this is followed by: for k, v in F.items(): D[k] = v
'''
if isinstance(other, Mapping):
for key in other:
self[key] = other[key]
elif hasattr(other, "keys"):
for key in other.keys():
self[key] = other[key]
else:
for key, value in other:
self[key] = value
for key, value in kwds.items():
self[key] = value
if语句的最后一个子案例(在other
上进行迭代)是大多数人想到的。但是,如您所见,也可以具有keys()
属性。结合__getitem__()
应该可以轻松地将子类正确地转换为字典:
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 __keys__(self):
return ["a", "b", "c"]
def __getitem__(self, key):
# have obj["a"] -> obj.a
return self.__getattribute__(key)
这将起作用:
>>> w = Wharrgarbl('one', 'two', 'three', 6)
>>> dict(w)
{'a': 'one', 'c': 'three', 'b': 'two'}