使用列表名称作为字符串来访问列表

4

我有一个数据文件,想根据第一列的值将其分成不同的列表。我知道第一列中可能出现哪些值,但它们不是任何漂亮的数学进度。是否有更简短的方法来编写以下代码?

x0=[]
y0=[]
x2=[]
y2=[]
x16=[]
y16=[]
# etc.

for line in file:
    words=line.split()
    if words[0] == '0':
        x0.append(words[1])
        y0.append(words[2])
    elif words[0] == '2':
        x2.append(words[1])
        y2.append(words[2])
    elif words[0] == '16':
        x16.append(words[1])
        y16.append(words[2])
    # etc.

我的思路如下,但是我定义的字符串(x和y)显然是字符串,而不是我想要引用的列表。

x0=[]
y0=[]
x2=[]
y2=[]
x16=[]
y16=[]
# etc

for line in file:
    words=line.split()
    x='x'+words[0]
    y='y'+words[0]
    x.append(words[1])
    y.append(words[2])

更新:我意识到可以用字典来实现这一点,其中我的值将是一个列表的列表,但主要是我好奇是否有一种符合上述思路的Pythonic方式来编写此代码。

5个回答

6

使用defaultdict代替一堆单独的值。

from collections import defaultdict
extracted_values = defaultdict(list)
for line in file:
    words = line.split()
    extracted_values['x' + words[0]].append(words[1])
    extracted_values['y' + words[0]].append(words[2])

那么你只需要通过字典键来访问你的值,而不是变量名。
extracted_values['x0']
extracted_values['y1']

5
我建议您转向:

在IT技术方面,我建议您转向:

x0=[]
x2=[]
x16=[]

将它们合并到一个字典中:
x={'0':[], '2':[], '16':[]}

您可以通过 x['0'], x['2'] 等方式引用各个列表。

特别地,您可以将 for 循环重写为以下形式:

for line in file:
    words = line.split()
    x[words[0]].append(words[1])
    y[words[0]].append(words[2])

谢谢!这就是我最终采取的方法。在我发布问题后大约20秒钟,我意识到这将是最简单的方法(每个人都会遇到这种情况),但那时我只是好奇还有其他可能性。我一直在努力扩展我的Python知识。 - user2162302

0
你可以使用 globals() 字典,如下所示:
x0=[]
y0=[]
x2=[]
y2=[]
x16=[]
y16=[]
# etc

for line in file:
    words=line.split()
    x=globals()['x'+words[0]]
    y=globals()['y'+words[0]]
    x.append(words[1])
    y.append(words[2])

2
从技术上讲是对的,但这只是从自己造成的伤口中恢复的一种方式。正如该人所说,请勿在变量名称中包含数据。 - DSM
可以这样做。Python提供了许多方法使您的代码难以阅读。当然,可以并不代表应该... - Silas Ray
OP问的是他是否能够做到,而不是他是否应该这样做。 - Robᵩ

0

有些人会大声喊叫,但我仍然不明白为什么他们对使用globals()感到不满。

for line in file:
    words=line.split()
    zx,zy = 'x%d' % words[0], 'y%d' % words[0]
    if zx not in globals():
        globals()[zx] = []
        globals()[zy] = []
    globals()[zx].append(words[1])
    globals()[zy].append(words[2])

1
“globals”是一个巨大的、不受控制的命名空间。如果你打算与任何其他代码协作,使用它是不好的。它会破坏封装性,使代码几乎无法跟踪,并且除非你非常小心地自己清理它,否则它会为Python带来所有内存泄漏和空指针的问题,而没有任何好处。使用“globals”真的没有什么好处。 - Silas Ray
1
@ sr2222已经遇到了封装问题(使用locals()的等效技巧在函数中无法工作,因此我们必须使用globals()),那么现在怎么办?在全局命名空间中有x0x2x16,您可以对它们进行什么操作?您可以显式地引用它们(意味着对列表的任何类似操作都将以三重方式编写),或者您必须将它们的引用存储在列表/元组或字典中以便循环引用它们,在这种情况下,为什么我们不一开始就这样做呢? - DSM
它由解释器或其他实体控制,我不太擅长Python - x2 = [ ]globals()['x2'] = [ ]之间有什么区别?-“如果您打算与任何其他代码友好相处”,请举例。-什么是破坏封装?请给出一些解释的教程或博客的链接。-无法跟随=无法阅读吗?我没有这种感觉。-我想知道如何通过使用globals()生成内存泄漏-空指针? - eyquem
(1)x2 = [] 可以在函数中声明局部变量;显然修改 globals() 不行。(2)如果另一个函数也使用了相同的技巧呢?你的 x2 可能会遮盖其他人的 x2。这就是不友好的表现,即(3)破坏封装——你无法隔离自己的行为(“把它们放在胶囊里”)。(4)至于不可能遵循的问题——很难举出一个好的例子,因为没有人在真正的代码中这样做。但想象一下,如果每个函数都使用相同的变量名称,就像之前那样,或者(如我之前所问),想象一下接下来要做什么。 - DSM
除了玩具示例之外,任何代码都不可能跟踪globals中的任何值,因为任何地方的任何代码都可以轻松地添加、修改或删除它们,而无需通知。如果您在模块A中设置全局变量,然后在模块B中使用它,则以后与代码一起工作的人唯一的追踪该值被设置的方法是逐行查看代码。至于封装,请阅读面向对象设计相关内容。 - Silas Ray

0

是的,你应该使用字典。但是为了回答你的问题,你可以使用 locals(),或者更灵活地,组装你想要的命令并使用 eval 执行它。例如,如果你的数据都是数字:

words = line.split()
eval("x%s.append(%s)" % (words[0], words[1]))
eval("y%s.append(%s)" % (words[0], words[2]))

请注意,line.split()会给你字符串,即使它们只包含数字。因此使用%s而不是%d
但无论如何,不要这样做。使用字典。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接