2014-10-29 1 views
1

В python 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'] = [[]]?

ответ

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] 

As вы можете видеть все подсписок - это точно такой же список. Все ссылки одинаковы. Поэтому, когда вы добавляете к одному из этих подписок, то, что вы действительно делаете, это изменение одного и того же подсписок.

Решение может создать именно количество списков вершин, как это:

>>> 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] 
+0

Благодарим вас за примеры! Это для меня полезно, и я должен быть более осторожным при написании кода на Python. – deeenes

2

Моя первая, незначительная проблема возникает здесь: присвоение вторым способом ссылки (то есть имя атрибута> индекс вершин) не работает

Это не работает, потому что g.vs["foo"] возвращает копию списка, в котором хранится значение атрибута foo, а не самого списка. Поэтому g.vs["foo"][0] = ["bar"] изменяет копию и не фактический график.

+0

Хорошо, теперь я понимаю. Спасибо, Тамас, за это! – deeenes