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