クロージャでローカル変数を書き換えるとエラーになる

Rubyで作ったカウンターをPythonに移植しました。

まずは、Rubyプログラム。

# coding: utf-8
# (ファイル名)
# counter.rb

def get_counter
  cnt = 0
  counter = lambda do
    cnt += 1
  end
end

if $0 == __FILE__
  counter = get_counter
  5.times do
    puts counter.call
  end
end

こいつをPythonで書くと、

def get_counter():
    cnt = 0
    def new_function():
        cnt += 1 # この行でエラーになる。
        return cnt

    return new_function

if __name__ == '__main__':
    counter = get_counter()

    for i in range(5):
        print(counter())

そして実行すると、

$ python3 counter.py
〜省略〜
UnboundLocalError: local variable 'cnt' referenced before assignment

どうやらPythonでは、関数内で初めて出現する変数に何らかの値を代入しようとすると、それはローカル変数とみなされるようです。

そのため、未定義のローカル変数に1を足そうとしてしまい、エラーになってしまいました。

せっかく、クロージャを使えるようになったのに、これではあまりにも悲しすぎます。

一刻も早く、これを解決策を考えなければなりません。

クロージャのローカル変数を書き換えるために [解決策]

普通の変数ではなくリスト変数を使えば、見かけ上、ローカル変数を書き換えられるみたいです。

(変更後)

def get_counter():
    cnt = [0] # 要素数が1のリスト
    def new_function():
        cnt[0] += 1 # cntが参照しているリストの中身を書き換える。
        return cnt[0]

    return new_function
Pythonプログラミング物語 © 2016 Frontier Theme