2012-05-23 3 views
1

Я не совсем понимаю, что происходит с переменной «current_label», которая для меня кажется определяемой в прилагаемом коде функции «ts_r», который сделает ее видимой изнутри «ts_r»? Но когда я запускаю код ниже, он жалуется, что перед назначением ссылается локальная переменная current_label. Обратите внимание, что она не жалуется на 'visited' или 'f' и что она не будет жаловаться, если я инициализирую 'current_label' с [len (g)].Аргумент, проходящий в Python

def topological_sort(g): 

    visited = zeros((len(g)), dtype='int32') 
    f = zeros((len(g)), dtype='int32') 
    current_label = len(g) # [] so it is seen inside ts_r 

    def ts_r(n): 
     for nn in [v for v in g[n] if not visited[v]]: 
      visited[nn] = 1 
      ts_r(nn) 
     f[n] = current_label 
     current_label -= 1 

    for i in range(len(g)): 
     if not visited[i]: 
      ts_r(i) 

    return f 
+2

Позор на кого писал затемненные имена переменных и методов в Python! – mVChr

+0

Я попытался исправить ваши отступы, но я понял, что все еще странно. Можете ли вы исправить это форматирование? – jdi

+0

Готово. Теперь лучше выглядеть. – Frank

ответ

3

В случае visited или fизменить изменяемые переменные. В случае current_label вы пытаетесь повторно назначить значение глобальной переменной, не указав, что оно глобально.

Изменение переменных из внешних областей не требует объявления их глобальными, но переназначение значения глобальной переменной требует объявления, что оно является глобальным - в противном случае оно рассматривается как локальное (и в случае ссылки перед назначением вы получаете такие ошибки) ,

Давайте посмотрим на код:

1. def ts_r(n): 
2.  for nn in [v for v in g[n] if not visited[v]]: 
3.   visited[nn] = 1 
4.   ts_r(nn) 
5.  f[n] = current_label 
6.  current_label -= 1 

В строке 5 присвоенным глобальную переменную значение f[n], но позже, в строке 6 вы пытаетесь присвоить этой глобальной переменной значение. Вы не сказали Python, что он глобальный, поэтому он предполагает, что он локальный. Но если он локальный, вы не можете назначить его раньше.

У вас есть два варианта:

  1. (вероятно, не один вы ищете) использовать его как локальный:

    def ts_r(n): 
        current_label = len(g) # initialize local variable 
        for nn in [v for v in g[n] if not visited[v]]: 
         visited[nn] = 1 
         ts_r(nn) 
        f[n] = current_label 
        current_label -= 1 
    
  2. Скажите Python это глобальная переменная, и вы хотели бы значение глобального изменения переменной:

    def ts_r(n): 
        global current_label # current_label is now global 
        for nn in [v for v in g[n] if not visited[v]]: 
         visited[nn] = 1 
         ts_r(nn) 
        f[n] = current_label 
        current_label -= 1 
    

EDIT

После того как ваш вопрос был обновлен, я видел вложенные функции вместо функций, определенных в глобальной области. Таким образом, решение с global не будет работать.

В Python 3.x у вас есть ключевое слово nonlocal, но вам нужно найти walkaround в случае Python 2.x. Опять же, у вас есть по крайней мере две возможности:

  1. Используйте изменяемые переменные ограждающих неизменны вы хотите изменить (например, список с одним целым числом в нем.). Затем, когда вы просто ссылаетесь на (и изменяете) первый элемент списка. Попробуй.

  2. Другим решением является добавление атрибута для функции обертывания (функция также является изменяемой, поэтому вы можете ее изменить, но вы не будете загрязнять глобальное пространство имен). Пример: http://ideone.com/7jGvM. В вашем случае это может выглядеть следующим образом:

    def topological_sort(g): 
    
        visited = zeros((len(g)), dtype='int32') 
        f = zeros((len(g)), dtype='int32') 
        topological_sort.current_label = len(g) # [] so it is seen inside ts_r 
    
        def ts_r(n): 
         for nn in [v for v in g[n] if not visited[v]]: 
          visited[nn] = 1 
          ts_r(nn) 
         f[n] = topological_sort.current_label 
         topological_sort.current_label -= 1 
    
        for i in range(len(g)): 
         if not visited[i]: 
          ts_r(i) 
    
        return f 
    
+0

Считаете ли вы, что даже в этой ситуации необходимо иметь локальную функцию закрытия? – jdi

+0

@jdl: Если вы имеете в виду 'ts_r', то у меня недостаточно информации. Может быть это. Попробуем объяснить ошибку OP. – Tadeck

+0

Хмммм ... Во-первых, ничто в синтаксическом намеке на current_label не отличается от f в точке объявления. Почему current_label тоже не считается изменяемой переменной? - Во-вторых, если я не хочу загрязнять глобальное пространство имен, могу ли я держать область current_label в целом топологическим_сортиром, но не за ее пределами? – Frank

Смежные вопросы