使用Python类作为数据容器

时间:2010-07-28 21:18:36

标签: python class dictionary struct

有时将相关数据集中在一起是有意义的。我倾向于用dict这样做,例如,

self.group = dict(a=1, b=2, c=3)
print self.group['a']

我的一位同事更喜欢创建一个类

class groupClass(object):
    def __init__(a, b, c):
        self.a = a
        self.b = b
        self.c = c
self.group = groupClass(1, 2, 3)
print self.group.a

请注意,我们没有定义任何类方法。

我喜欢使用dict,因为我喜欢最小化代码行数。我的同事认为如果使用类,代码更具可读性,并且将来可以更轻松地向类中添加方法。

您更喜欢哪个?为什么?

12 个答案:

答案 0 :(得分:42)

如果你真的没有定义任何类方法,那么dict或namedtuple在我看来更有意义。简单+内置很好!但对他自己而言。

答案 1 :(得分:22)

<强>背景

R. Hettinger在SF Python 2017年假日聚会上介绍了基于属性的替代数据容器的摘要。查看他的tweet和他的slide deck。他还在PyCon 2018上为数据类提供了talk

article中提到了其他数据容器类型,主要在Python 3文档中提及(参见下面的链接)。

以下是关于将recordclass添加到标准库的python-ideas邮件列表的讨论。

选项

标准库中的备选方案

外部选项

  • records:mutable namedtuple(另请参阅recordclass
  • bunches:添加对dicts的属性访问权限(SimpleNamedspace的灵感)
  • box:使用dot-style lookup功能
  • 包装dicts
  • attrdict:从映射中访问元素作为键或属性
  • fields:从容器类中删除样板文件。
  • namedlist:可变的,类似于元组的容器,默认为E. Smith

哪一个?

决定使用哪个选项取决于具体情况(参见下面的示例)。通常一个老式的可变字典或不可变的namedtuple就足够了。数据类是最新增加的(Python 3.7a),它提供了可变性和optional immutability,并且受到attrs项目启发的减少样板的承诺。

<强>实施例

import typing as typ
import collections as ct
import dataclasses as dc


# Problem: You want a simple container to hold personal data.
# Solution: Try a NamedTuple.
>>> class Person(typ.NamedTuple):
...     name: str
...     age: int
>>> a = Person("bob", 30)
>>> a
Person(name='bob', age=30)

# Problem: You need to change age each year, but namedtuples are immutable. 
# Solution: Use assignable attributes of a traditional class.
>>> class Person:
...     def __init__(self, name, age):
...         self.name = name
...         self.age = age
>>> b = Person("bob", 30)
>>> b.age = 31
>>> b
<__main__.Person at 0x4e27128>

# Problem: You lost the pretty repr and want to add comparison features.
# Solution: Use included repr and eq features from the new dataclasses.
>>> @dc.dataclass(eq=True)
... class Person:
...     name: str
...     age: int
>>> c = Person("bob", 30)
>>> c.age = 31
>>> c
Person(name='bob', age=31)
>>> d = Person("dan", 31)
>>> c != d
True

答案 2 :(得分:8)

我更喜欢关注YAGNI并使用词典。

答案 3 :(得分:7)

有一项新提案旨在准确实施您所寻找的内容,称为data classes。看看吧。

在dict上使用类是一个偏好的问题。就个人而言,我更喜欢使用一个字典,当钥匙不是先验的时候。 (作为映射容器)。

使用类来保存数据意味着您可以为类属性提供文档。

就个人而言,也许我使用类的最大原因是使用IDE自动完成功能! (技术上是一个蹩脚的原因,但在实践中非常有用)

答案 4 :(得分:5)

你的方式更好。不要试图预测未来太多,因为你不可能成功。

然而,it may make sense sometimes to use something like a C struct,例如,如果您想识别不同的类型,而不是使用dicts来处理所有事情。

答案 5 :(得分:4)

顺便说一句,我认为Python 3.7实现@ dataclass是将类实现为数据容器的最简单,最有效的方法。

@dataclass
class Data:
    a: list
    b: str    #default variables go after non default variables
    c: bool = False

def func():
    return A(a="hello")

print(func())

输出为:hello

它与Scala这样的案例类太相似,并且是使用类作为容器的最简单方法。

答案 6 :(得分:3)

您可以使用从dict继承的一些包装类将dict和class的优点结合在一起。您不需要编写样板代码,同时可以使用点表示法。

class ObjDict(dict):
    def __getattr__(self,attr):
        return self[attr]
    def __setattr__(self,attr,value):
        self[attr]=value

self.group = ObjDict(a=1, b=2, c=3)
print self.group.a

答案 7 :(得分:2)

我不同意使用没有方法的类,代码更具可读性。您通常期望来自类的功能,而不仅仅是数据。

所以,在出现功能需求之前,我会选择一个字典,然后该类的构造函数可以收到一个字典: - )

答案 8 :(得分:1)

在支持它的语言中,我会使用struct。字典最接近Python中的结构,至少就我看来而言。

更不用说,如果真的想要,你可以在字典中添加一个方法;)

答案 9 :(得分:1)

dict显然适合这种情况。它专为该用例而设计。除非你真的要把这个类作为一个类使用,否则重新发明轮子会产生额外的开销/浪费一个充当错误字典的类的空间(没有字典特征)。

答案 10 :(得分:1)

Prodict

怎么样?
group = Prodict(a=1, b=2, c=3)
group.d = 4

如果你想要自动类型转换和自动代码完成(智能):

class Person(Prodict):
    name: str
    email: str
    rate: int

john = Person(name='John', email='john@appleseed.com')
john.rate = 7
john.age = 35  # dynamic

答案 11 :(得分:1)

如果不关心内存占用,那么dictnamedtupledataclass或仅带有__slots__的类都是不错的选择。

但是如果必须创建具有数个简单属性的数百万个对象,那么有一种基于recordclass库的解决方案:

from recordclass import make_dataclass
C = make_dataclass("C", ('a', 'b', 'c'))
c = C(1, 2, 3)

与类定义相同:

from recordclass import dataobject
class C(dataobject):
    a:int
    b:int
    c:int    
c = C(1, 2, 3)

它具有最小的内存占用= sizeof(PyObject_HEAD) + 3*sizeof(PyObject*)个字节。

为进行比较,基于__slots__的变体需要sizeof(PyGC_Head) + sizeof(PyObject_HEAD) + 3*sizeof(PyObject*)个字节。