有时将相关数据集中在一起是有意义的。我倾向于用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,因为我喜欢最小化代码行数。我的同事认为如果使用类,代码更具可读性,并且将来可以更轻松地向类中添加方法。
您更喜欢哪个?为什么?
答案 0 :(得分:42)
如果你真的没有定义任何类方法,那么dict或namedtuple在我看来更有意义。简单+内置很好!但对他自己而言。
答案 1 :(得分:22)
<强>背景强>
R. Hettinger在SF Python 2017年假日聚会上介绍了基于属性的替代数据容器的摘要。查看他的tweet和他的slide deck。他还在PyCon 2018上为数据类提供了talk。
此article中提到了其他数据容器类型,主要在Python 3文档中提及(参见下面的链接)。
以下是关于将recordclass
添加到标准库的python-ideas邮件列表的讨论。
选项强>
标准库中的备选方案
collections.namedtuple
:带有属性的元组(请参阅开创性recipe)typing.NamedTuple
:可分类的元组(请参阅此post将其与namedtuple
进行比较)types.SimpleNamespace
:简单类w /可选类声明types.MappingProxy
:只读dict enum.Enum
:约束相关常量的集合(表现得像一个类)dataclasses.dataclass
:mutable namedtuple with default / boilerplate-less classes 外部选项
SimpleNamedspace
的灵感)哪一个?
决定使用哪个选项取决于具体情况(参见下面的示例)。通常一个老式的可变字典或不可变的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)
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)
如果不关心内存占用,那么dict,namedtuple,dataclass或仅带有__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*)
个字节。