如何为python igraph列表属性的各个元素赋值?

时间:2014-10-29 19:44:15

标签: python graph igraph

在python igraph中,顶点和边缘属性可以是任何类型的python对象,例如列表,词典。我创建了一个顶点属性,其中每个顶点都有一个列表值:

import igraph
g = igraph.Graph.Barabasi(10,5)
g.vs['foo'] = [[]]

然后我有每个顶点的(空)列表:

print g.vs['foo']
# [[], [], [], [], [], [], [], [], [], []]

各个顶点的属性值可以通过两种方式引用:

print g.vs[0]['foo']
# []
print g.vs['foo'][0]
# []

如果我想做价值分配,可能就是这样:

g.vs[0]['foo'] = ['bar']
g.vs['foo'][0] = ['bar']

结果,正如我所料,顶点数0的值为['bar'],而其他顶点的属性保持不变:

print g.vs[0]['foo']
# ['bar']
print g.vs['foo']
# [['bar'], [], [], [], [], [], [], [], [], []]

我的第一个小问题来自于:使用第二种引用方式(即属性名称>顶点索引)的分配不起作用:

g.vs['foo'] = [[]]
g.vs['foo'][0] = ['bar']
print g.vs['foo'][0]
# []
print g.vs['foo']
# [[], [], [], [], [], [], [], [], [], []]

但我的主要问题是修改一个顶点的列表会产生奇怪的结果:

g.vs['foo'] = [[]]
g.vs[0]['foo'].append('bar')
print g.vs['foo']
# [['bar'], ['bar'], ['bar'], ['bar'], ['bar'], ['bar'], ['bar'], ['bar'], ['bar'], ['bar']]
g.vs['foo'] = [[]]
g.vs[0]['foo'] += ['bar']
print g.vs['foo']
# [['bar'], ['bar'], ['bar'], ['bar'], ['bar'], ['bar'], ['bar'], ['bar'], ['bar'], ['bar']]

不仅顶点数为0的属性,而且所有顶点都是'属性已被附加值!这不是我所期望的。我可以用这种方式给各个顶点的属性赋值:

g.vs['foo'] = [[]]
g.vs[0]['foo'] = g.vs[0]['foo'] + ['bar']
print g.vs['foo']
# [['bar'], [], [], [], [], [], [], [], [], []]

但不是append()

g.vs['foo'] = [[]]
g.vs[0]['foo'] = g.vs[0]['foo'].append('bar')
print g.vs['foo']
# [None, ['bar'], ['bar'], ['bar'], ['bar'], ['bar'], ['bar'], ['bar'], ['bar'], ['bar']]

这真的很令人惊讶,值0变为None,而其他所有值都包含附加元素的列表。我认为这种行为是因为python中的指针属性。如果我单独初始化每个值,一切都按照我的预期直观地进行:

for v in g.vs:
    v['foo'] = []
g.vs[0]['foo'].append('bar')
print g.vs['foo']
# [['bar'], [], [], [], [], [], [], [], [], []]

那么在列表顶点属性上应用append()的推荐方法是什么?如果添加顶点,属性将初始化为None。在这种情况下,用户需要编写自定义帮助函数来保持属性类型的一致性?我们是否应该完全避免以这种方式初始化属性:g.vs['foo'] = [[]]

2 个答案:

答案 0 :(得分:3)

您似乎正在使用*运算符体验列表初始化的python列表。

>>> g.vs['foo'] = [[]]

似乎正在做这样的事情(在特定情况下为10个顶点数):

>>> g.vs['foo'] = [[]] * 10

这可能无法正常工作:

>>> [id(i) for i in g.vs['foo']]
[4348211640, 4348211640, 4348211640, 4348211640, 4348211640, 4348211640, 4348211640, 4348211640, 4348211640, 4348211640]

如您所见所有,子列表完全相同。所有参考文献都是相同的。因此,当您附加到其中一个子列表时,您真正在做的是修改相同的子列表。

解决方案可能是创建精确数量的顶点列表,如下所示:

>>> g.vs['foo'] = [[] for _ in range(10)]

然后,如果您打印引用,您将看到它们实际上是不同的子列表:

>>> [id(i) for i in g.vs['foo']]
[4348211784, 4348212576, 4348212648, 4348212720, 4348212792, 4348212864, 4348212936, 4348213008, 4348213080, 4348213152]

答案 1 :(得分:2)

  

我的第一个小问题来自:使用第二种引用方式(即属性名称>顶点索引)的分配不起作用

它不起作用,因为g.vs["foo"]返回存储foo属性值的列表的副本,而不是列表本身。因此,g.vs["foo"][0] = ["bar"]将修改副本,不会实际图形。