4

私はyieldを使用して、正規表現とre.sub()を使用して抽出されている文字列のチャンクを返すジェネレーターを作成しています。うまくいくアプローチを見つけましたが、以下に示すように、なぜそれが一方向に機能するのに別の方法では機能しないのかについて少し混乱しています。

これは機能しません(processchunk()はsplitmsgで宣言されたチャンクに割り当てられていません):

def splitmsg(msg):
    chunk = None
    def processchunk(match):
        chunk = match.group(1)
        return ""
    while True:
        chunk = None
        msg = re.sub(reCHUNK,processchunk,msg,1)
        if chunk:
            yield chunk
        else:
            break     

これは機能します(チャンクである唯一の違いはリストチャンクであることに注意してください):

def splitmsg(msg):
    chunks = [ None, ]
    def processchunk(match):
        chunks[0] = match.group(1)
        return ""
    while True:
        chunks[0] = None
        msg = re.sub(reCHUNK,processchunk,msg,1)
        if chunks[0]:
            yield chunks[0]
        else:
            break

私の質問は基本的に、チャンク/チャンク変数のスコープがプレーン変数であるかリストであるかに依存しているように見えるのはなぜですか?

4

2 に答える 2

5

Pythonでは、変数は、から読み取られた場合、周囲のスコープから「プル」できます。したがって、以下が機能します。

def foo():
    spam = 'eggs'
    def bar():
        print spam
foo()

変数「spam」が周囲のスコープで検索されているため、foo関数。

ただし、周囲のスコープの値を変更することはできません。グローバル変数を変更することはできますが(関数内で宣言した場合)、上記の関数globalの変数に対しては変更できません。spam

(Python 3はこれを変更し、新しいキーワードを追加しnonlocalます。insidespamとして定義すると、その変数にnonlocalinsidebarの新しい値を割り当てることができますbar。)

今あなたのリストに。そこで何が起こるかというと、変数chunksをまったく変更していないということです。コード全体で、chunks1つのリストを指し、そのリストのみを指します。Pythonに関する限り、chunks変数はprocesschunk関数内で変更されません。

リストの内容を変更するとどうなりますか。に新しい値を自由に割り当てることができます。これは変数ではなく、最初のインデックスによって参照されるリストであるためです。Pythonはこれを許可します。これは、変数の割り当てではなく、代わりにリスト操作であるためです。chunks[0]chunkschunks

したがって、多少あいまいな場合でも、「回避策」は正しいです。Python 3を使用している場合はchunksnonlocalprocesschunkで宣言すると、リストがなくても機能します。

于 2012-08-24T20:32:42.567 に答える
1

最初のケースでは、と呼ばれる新しいローカル変数を作成していますchunk。関数内で変数を割り当てると、変数は関数に対してローカルとして扱われます。2番目のケースでは、外部変数によって参照されるリストを変更していますchunk。この変数には割り当てないため、ローカルとしては扱われません。たとえば、この前の質問を参照してください。

Python()でベアネームに割り当てることは、someName = ...他のものと同じではありません。特に、アイテムの割り当て()と同じではありませんsomeName[0] = ...。後者は、リストを変更するために内部でメソッドを呼び出しています。

于 2012-08-24T20:34:26.760 に答える