何时在Python中使用字典和元组


31

想到的特定示例是文件名及其大小的列表。我不能决定列表中的每个项目是否应该是这样的形式{"filename": "blabla", "size": 123},或者只是("blabla", 123)。字典对我来说似乎更合乎逻辑,因为例如访问大小file["size"]file[1]... 更具解释性,但是我不确定。有什么想法吗?


作为附录,如果您担心元组的可读性,请考虑对元组进行拆包 - fname, file_size = file如果数据在元组上方,则该元组将被删除file[1]并替换为file_size。当然,这取决于良好的文档。
nlsdfnbch

2
这取决于您要构建什么数据结构,以及打算如何访问它?(按文件名?按索引?还是两者??)这只是一个废弃的变量/数据结构,还是您可能要添加其他项(/属性)以及大小?结构是否需要记住命令?您要排序大小列表还是按位置访问列表(例如“前n个最大/最小文件”)?取决于答案,“最佳”答案可能是dict,OrderedDict,namedtuple,普通旧列表或您自己的自定义类。需要您提供更多背景信息。
smci

Answers:


78

我会使用namedtuple

from collections import namedtuple
Filesize = namedtuple('Filesize', 'filename size')
file = Filesize(filename="blabla", size=123)

现在,您可以在程序中使用file.sizefile.filename,这是恕我直言最易读的形式。注namedtuple会建立像元组不可变对象,和他们比字典更轻巧,描述在这里


1
谢谢,好主意,今天之前从未听说过它们(我对Python相当了解)。问题:如果代码中其他地方的人也定义了相同的“类”,可能会稍有不同,该怎么办?例如,在其他一些源文件中,同事Bob拥有Filesize = namedtuple('Filesize', 'filepath kilobytes')
user949300 '17

您还可以使用非常好的attrs模块(可以通过找到它pip或只是搜索它),它使您具有与命名元组非常相似的语法便利,但可以赋予您可变性(但也可以使其不可变)。功能上的主要区别是attrs-made类与namedtuples 相比不等于普通元组。
mtraceur

3
@DocBrown Python没有声明的概念。classdef=都将覆盖以前的所有用法。repl.it
Challenger5

@ Challenger5:是的,我的错,所以正确的答案是:最新定义很重要,Python运行时没有错误,但行为与其他变量相似。
布朗

8
请注意,这namedtuple实际上是具有不可变属性的新类型的简短说明。这意味着答案实际上是“既不是a tuple也不是a dict,而是an” object。+1
jpmc26

18

{“ filename”:“ blabla”,“ size”:123},或者只是(“ blabla”,123)

这是对带内或带外格式/模式进行编码的古老问题。

您需要权衡一些内存,以从在数据中正确表达数据格式来获得可读性和可移植性。如果您不这样做,则必须知道第一个字段是文件名,第二个字段是大小,必须将其保留在其他位置。这样可以节省内存,但会降低可读性和可移植性。哪个会花费您的公司更多的钱?

至于不可变的问题,记住不可变并不意味着面对变化就没有用。这意味着我们需要获取更多的内存,在副本中进行更改,然后使用新副本。这不是免费的,但通常不是交易突破者。我们始终使用不可变的字符串来更改内容。

另一个考虑因素是可扩展性。当您仅按位置存储数据而没有对格式信息进行编码时,那么您将只能使用单继承,这实际上只是在已建立的字段之后串联其他字段的做法。我可以将第三个字段定义为创建日期,并且仍然与您的格式兼容,因为我以相同的方式定义了第一和第二个字段。

但是,我不能做的是将两个独立定义的格式组合在一起,这些格式具有一些重叠的字段,有些则没有,将它们存储为一种格式,并且对仅了解一种或另一种格式的东西很有用。

为此,我需要从一开始就对格式信息进行编码。我需要说“此字段是文件名”。这样做可以实现多重继承。

您可能习惯了仅在对象的上下文中表示继承,但是相同的思想也适用于数据格式,因为对象存储在数据格式中。这是完全一样的问题。

因此,请使用您认为最需要的东西。除非我有充分的理由不这样做,否则我会保持灵活性。


3
坦白地说,我怀疑不确定使用带内还是带外格式的人对性能的要求如此严格,以至于他们需要使用带外格式
亚历山大-恢复莫妮卡

2
@亚历山大非常正确。我更喜欢教人们有关信息,以便他们在面对带外解决方案时了解他们在看什么。二进制格式通常出于混淆的原因而这样做。并非每个人都希望便携。由于性能原因,如果真的很重要,请在进行带外处理之前考虑进行压缩。
candied_orange

请记住,OP使用的是Python,因此他们可能不太在意性能。最高级的代码在编写时应首先考虑可读性。过早的优化是万恶之源。
Dagrooms

@Dagrooms不会讨厌Python。在许多情况下,它的性能都很好。但除此之外,我同意您所说的一切。我的意思是说“这就是人们这样做的原因。这就是为什么您可能不在乎的原因”。
candied_orange

@CandiedOrange我不讨厌这种语言,我在日常工作中使用它。我不喜欢人们使用它的方式。
Dagrooms

7

我将使用具有两个属性的类。file.sizefile[1]或更好file["size"]

简单胜于复杂。


如果有人想知道:对于生成JSON,两者都可以很好地工作:file = Filesize(filename='stuff.txt', size=222)并且filetup = ("stuff.txt", 222)都生成相同的JSON:json.dumps(file)json.dumps(filetup)导致:'["stuff.txt", 222]'
Juha Untinen

5

文件名是否唯一?如果是这样,您可以完全删除列表,而仅对所有文件使用纯字典。例如(假设的网站)

{ 
  "/index.html" : 5467,
  "/about.html" : 3425,
  "/css/main.css" : 9876
}

等等...

现在,您无需使用“名称”和“大小”,而只使用键和值,但这通常更自然。YMMV。

如果您确实需要一个“大小”来简化说明,或者该文件需要多个值,则:

{ 
   "/index.html" : { "size": 5467, "mime_type" : "foo" },
   "/about.html" : { "size": 3425, "mime_type" : "foo" }
   "/css/main.css" : { "size": 9876, "mime_type" : "bar" }
}

0

在python中,字典是可变对象。另一方面,元组是不可变的对象。

如果您需要经常或每次更改字典键,值对。我建议使用字典。

如果您有固定/静态数据,我建议使用元组。

# dictionary define.
a = {}
a['test'] = 'first value'

# tuple define.
b = ()
b = b+(1,)

# here, we can change dictionary value for key 'test'
a['test'] = 'second'

但是,不能使用赋值运算符更改元组数据。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.