导入模块时无法看到全局变量的变化

时间:2013-09-13 07:07:23

标签: python

我想实现与第三版CLRS的问题2-4相关的python代码。问题是“在列表中找到反转的数量”,并且我写了这个代码:

mainCounter = 0
def merg(array,counter):
    if len(array)==1:
            return array
    left = array[:len(array)/2]
    right = array[len(array)/2:]
    return combine(merg(left, counter), merg(right, counter), counter)

def combine(array1, array2, counter):
    global mainCounter
    result = []
    pointer1 = 0
    pointer2 = 0
    while(pointer1 != len(array1) and pointer2 != len(array2)):
            if array1[pointer1] < array2[pointer2]:
                    result.append(array1[pointer1])
                    pointer1 += 1
            elif array1[pointer1] == array2[pointer2]:
                    result.append(array1[pointer1])
                    pointer1 += 1
            else:
                    result.append(array2[pointer2])
                    counter += (len(array1)-pointer1)
                    pointer2 += 1
    if pointer1 == len(array1):
            for i in array2[pointer2:]:
                    result.append(i)
    else:
            for i in array1[pointer1:]:
                    result.append(i)
    mainCounter+=counter
    return result

问题是当我在python控制台中导入此模块时,mainCounter没有改变,但必须更改!!:

Python 2.7.3 (default, Aug  1 2012, 05:16:07) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from mergSort import *
>>> merg([1,4,2,3],0)
0
0
2
[1, 2, 3, 4]
>>> merg([1,4,2,3],0)
2
2
4
[1, 2, 3, 4]
>>> mainCounter
0
>>> merg([1,4,2,3],0)
4
4
6
[1, 2, 3, 4]
>>> merg([1,4,2,3],0)
6
6
8
[1, 2, 3, 4]
>>> merg([1,4,2,3],0)
8
8
10
[1, 2, 3, 4]
>>> mainCounter
0

每次调用merg函数时,我得到的结果都不同,但mainCounter没有改变!哪里错了?

2 个答案:

答案 0 :(得分:4)

tldr:不要使用from module import *

import *没有您想象的那么特别 - 当您使用from mergSort import *导入内容时,请将其视为

import mergSort
mainCounter = mergSort.mainCounter
merg = mergSort.merg
del mergSort

所以你真的只引用了导入时mergSort.mainCounter引用的int对象。 mergSort使用mergSort.mainCounter个;

的方式相同
>>> a = 1
>>> b = a
>>> a += 1 # or a = a + 1 or a = a.__add__(1)
>>> a
2
>>> b
1

我们对整数对象有两个单独的引用,并且递增一个(将引用更改为指向由旧对象上的方法调用生成的新对象)将不会影响另一个。要确认这一点,请尝试

merg.__globals__['mainCounter']

import sys; sys.modules[merg.__module__].mainCounter

这些应该具有merg正在使用的mainCounter值。

sys.modules['mergSort'] is merg.__globals__是真的,它们是相同的字典)

当一个名称在函数中声明为全局时,它将在函数模块的命名空间中查找。

import *经常受到诽谤,因为它很难追踪名称的来源,但这里也很糟糕,因为它破坏了我们对模块的概念 - 只是因为你从模块导入*并不意味着你实际上在它的命名空间中,你刚刚完成了from module import a, b, c, d, e, ...。这更糟糕,因为许多名称在Python中没有重新绑定,但有些名称一直都是,就像通过引用整数作为计数器的名称一样。

答案 1 :(得分:1)

完全不使用import *是一种很好的做法。 您导入的对象对彼此一无所知,并且使用global mainCounter无法提供帮助。

试试这个:

import mergSort

mergSort.merg([1, 4, 2, 3], 0)
print mergSort.mainCounter