2016-04-16 3 views
0

Я думал, что я понял область переменной Python довольно хорошо, но затем я столкнулся с этим кодом сегодня.Strange Python Scope Issue

from __future__ import print_function 

def main(): 
    v_Matrix =[[1, 2, 3], 
       [4, 5, 6], 
       [7, 8, 9]] 

    print(v_Matrix) 
    print() 

    f_Rotate(v_Matrix) 
    print(v_Matrix) 

    hh = 3 
    f_This(hh) 
    print(hh) 

def f_Swap(v_Matrix, r1, c1, r2, c2): 
    v_Matrix[r1][c1], v_Matrix[r2][c2] = v_Matrix[r2][c2], v_Matrix[r1][c1] 

def f_Transpose(v_Matrix): 
    for row in range(len(v_Matrix)): 
     for col in range(row): 
      f_Swap(v_Matrix, row, col, col, row) 

def f_FlipVertical(v_Matrix): 
    v_Size = len(v_Matrix) 
    for row in range(v_Size // 2): 
     for col in range(v_Size): 
      f_Swap(v_Matrix, row, col, v_Size - row - 1, col) 

def f_Rotate(v_Matrix): 
    f_Transpose(v_Matrix) 
    f_FlipVertical(v_Matrix) 

def f_This(hh): 
    hh = hh * 2 

if __name__ == '__main__': 
    main() 

При запуске, переменная v_Matrix, кажется, ведут себя, как если бы глобальный характер. Однако тестовая переменная hh ведет себя как ожидалось с одной областью в main(), а другая в f_This.

v_Matrix не является глобальным, модифицируется в различных функциях, но не передается между этими функциями и даже возвращается к main(). Тем не менее изменения значений, применяемые к v_Matrix в этих функциях, доступны в области main(), как видно из выходов. Однако, как и ожидалось, значение тестовой переменной hh не изменяется в области main(), только в рамках функции.

Что дает?

+0

Это потому, что списки изменчивы. Для подробного обсуждения см. Https://docs.python.org/2/reference/datamodel.html#objects-values-and-types. – Selcuk

+0

И Python передает указатель на изменяемый объект в качестве параметра при вызове функции, а не на создание копии объекта. Как и в указателях типа C, вы можете изменить содержимое объекта, на который указана, но не может заставить вызывающего объекта указать новый объект, назначив его. –

+0

@Selcuk Хорошо, мало упоминалось о сфере видимости в вашей ссылке. Тем не менее, ваш комментарий помог мне указать на то, что изменяемые объекты, особенно списки, имеют другое поведение в отношении области, основанной на «внешних», «против» внутренних контейнерах и т. Д. Я все еще не понимаю все это, но я буду , Наверное, я пропустил этот факт, когда изучил масштаб. Спасибо. – JayJay123

ответ

1

list - изменяемая структура данных. Это означает, что вы можете изменить его значение, сохраняя при этом id(). если вы проходите вокруг переменной, которая именует таким объектом, как у этого же id, это тот же объект, о котором вы говорите в разных частях кода. Поэтому, если вы меняете его везде, он мутирует навсегда.

Таким образом, решение есть, не проходит мимо. Скорее keep it и использовать в преобразованиях данных (не мутации). Создайте еще один или лучше, но используйте генераторы и оценивайте только окончательный требуемый список.

+0

Спасибо за ответ и информацию. – JayJay123

2

Все в Python - это объект, и объекты передаются в функции одинаково, независимо от того, являются ли они изменяемыми или неизменяемыми. Однако изменения в изменяемых объектах можно увидеть вне функции.

Пример:

def f(c,d): 
    print('Inside f()') 
    print(' id(a) =',id(a),'value =',a) 
    print(' id(b) =',id(b),'value =',b) 
    print(' id(c) =',id(c),'value =',c) 
    print(' id(d) =',id(d),'value =',d) 
    c = 4  # local name c is assigned a new object. 
    d[0] = 5 # local name d's object is mutated 
    print(' id(a) =',id(a),'value =',a) 
    print(' id(b) =',id(b),'value =',b) # b and d objects are same, so b changed 
    print(' id(c) =',id(c),'value =',c) # id changed, not same as a 
    print(' id(d) =',id(d),'value =',d) # id did not change, still same as b 
    d = [6] # local name d is assigned a new object. 
    print(' id(d) =',id(d),'value =',d) # id changed, not same as b 
a = 3 # immutable 
b = [3] # mutable 
print('Before f()') 
print(' id(a) =',id(a),'value =',a) 
print(' id(b) =',id(b),'value =',b) 
f(a,b) 
print('After f()') 
print(' id(a) =',id(a),'value =',a) 
print(' id(b) =',id(b),'value =',b) 

Аннотированный Выход:

Before f() 
    id(a) = 507107264 value = 3 
    id(b) = 67001608 value = [3] 
Inside f() 
    id(a) = 507107264 value = 3 
    id(b) = 67001608 value = [3] 
    id(c) = 507107264 value = 3 # id(c) == id(a) 
    id(d) = 67001608 value = [3] # id(d) == id(b) 
    id(a) = 507107264 value = 3 
    id(b) = 67001608 value = [5] # id(d)==id(b), so b changed when d did 
    id(c) = 507107296 value = 4 # c was reassigned, id(c) != id(a) 
    id(d) = 67001608 value = [5] # id(d) == id(b)...object mutated 
    id(d) = 65761864 value = [6] # d was reassigned, id(d) != id(b) 
After f() 
    id(a) = 507107264 value = 3 # immutable a unaffected 
    id(b) = 67001608 value = [5] # sees mutation of list contents from d[0]=5 
+0

Благодарим вас за подробный ответ. – JayJay123