3

CLRS の第 3 版の問題 2-4 に関連する python コードを実装したいと考えています。問題は、41 ページの「リスト内のInversionの数を見つける」で、次のコードを記述します。

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 は変更されません! どこが間違っていますか?

4

2 に答える 2

4

tldr: 使用しないでくださいfrom module import *

import *はあなたが思っているほど特別ではありません - で物をインポートするときはfrom mergSort import *

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

したがって、実際にmergSort.mainCounterは、インポートを行ったときに参照した int オブジェクトへの参照があります。mergSort1つを使用しmergSort.mainCounterます。それと同じように

>>> a = 1
>>> b = a
>>> a += 1 # or a = a + 1 or a = a.__add__(1)
>>> a
2
>>> b
1

整数オブジェクトへの 2 つの個別の参照があり、一方をインクリメント (古いオブジェクトのメソッド呼び出しによって生成された新しいオブジェクトを指すように参照を変更) しても、もう一方には影響しません。これを確認するには、試してください

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 では多くの名前が再バインドされないため、これはさらに悪化しますが、整数を参照することでカウンターとして機能する名前のように、一部の名前は常に再バインドされます。

于 2013-09-13T07:14:02.887 に答える
1

まったく使用しないことをお勧めimport *します。インポートされたオブジェクトはお互いについて何も知らず、使用global mainCounterしても役に立ちません。

これを試して:

import mergSort

mergSort.merg([1, 4, 2, 3], 0)
print mergSort.mainCounter
于 2013-09-13T07:45:31.557 に答える