Pythonのlocals関数を使って現在のローカル変数の一覧をdictとして出力する方法

スポンサーリンク

今日は、Pythonの locals() 関数の使い方について見ていきましょう。

これはプログラムのデバッグに非常に便利なユーティリティ関数です。

locals()関数は、現在のローカルシンボルテーブルを辞書として提供してくれます。

さて、ローカル・シンボル・テーブルとはいったい何なのか、よくわからないという人は、このまま読み進めてください。

シンボルテーブルの定義から順を追って説明しましょう。


スポンサーリンク

シンボルテーブルとは?

シンボルテーブルとは、さまざまなシンボルに関する情報を集めたテーブルのことです。

ここで、シンボルとは、変数名、キーワード、関数名など、あらゆるものを意味します。

プログラム中のすべての変数、クラス、関数の名前を表しています。

一般に、シンボルテーブルはこれらのオブジェクトの名前だけでなく、オブジェクトの型やスコープなど、他の有用な情報からも構成されています。

さて、シンボルテーブルの意味が分かったところで、シンボルテーブルのクラスについて説明しましょう。

Pythonのプログラムでは、2種類のシンボルテーブルがあります。

  • グローバルシンボルテーブル -> プログラムのグローバルスコープに関連する情報を格納します。
  • ローカルシンボルテーブル —— プログラムのローカル(現在の)スコープに関連する情報を格納します。

以上、グローバルスコープとローカル(カレント)スコープに基づいて、2つのシンボルテーブルを定義しました。

ローカル・シンボル・テーブルとは、インタープリタがコードを一行ずつ実行したときに、現在のスコープにあるすべての情報を指します。

Pythonのlocals()関数は具体的に何をするのでしょうか?

さて、locals()関数が行うことは、locals()が呼ばれたスコープ上のローカルシンボルテーブルの情報をコンソールに貼り付けるだけです!

つまり、Pythonの locals() の出力は、当然ながら、すべての変数名と属性、スコープなどの辞書となります。

例えば、main.pyというファイルがあったとします。

ここで、locals() を唯一のステートメントとして記述し、何が起こるか見てみましょう。

すると、main スコープ(この場合、グローバルスコープと同じ)にあるすべての関連情報が得られるはずです。

# main.py
print(locals())

可能な出力

{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x12ba85542>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': '/Users/askpython/home/locals_example.py', '__cached__': None}

さて、main モジュールの属性(Global Scope)を見ることができました。

すぐにお気づきの方もいらっしゃると思いますが、これは globals() と同じで、どちらも同じグローバルスコープを参照しているためです。


ローカルスコープから locals() を呼び出す

では、ローカルスコープの中で、関数から locals() を呼び出すことを考えてみましょう。

関数内部でlocals()を呼び出す場合

二つの引数 ab を受け取り、その和を返す単純な関数 fun(a, b) を考えてみましょう。

関数が戻る直前に locals() を呼び出すことにします。

# Global variable
global_var = 1234
 
def fun(a, b):
    global global_var
    temp = 100
    print(f"locals() inside fun(a, b) = {locals()}")
    return a + b
 
if __name__ == '__main__':
    print(f"locals() outside fun(a, b) = {locals()}")
    print(fun(10, 20))

結果は以下の通りです。

locals() outside fun(a, b) = {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7f7023e1ff60>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'locals_example.py', '__cached__': None, 'global_var': 1234, 'fun': <function fun at 0x7f7023e5b1e0>}
locals() inside fun(a, b) = {'a': 10, 'b': 20, 'temp': 100}
30

ここで、 fun(a, b) 内から顕著な変化があります。

ここでは、ローカルシンボル表はこの関数に関連する名前だけから構成されています。

ローカルスコープはパッケージの一部ではないので、パッケージの情報はなく、関数に関連する変数と引数だけが含まれています。

また、グローバル変数 global_var はグローバルシンボルテーブルの一部であり、結果的にローカルシンボルテーブルには存在しないことに注意してください!

クラス内部でlocals()を呼び出す

これは関数から呼び出すのと似ていますが、すべてのクラスメソッドと関連する属性が含まれます。

早速、例題を使って見てみましょう。

class Student():
    def __init__(self, name):
        self.name = name
    def get_name(self):
        return self.name
    print(f"Calling locals() from inside a class => {locals()}")
    print(f"Calling globals() from inside a class => {globals()}")
 
if __name__ == '__main__':
    s = Student('Amit')
    print(s.get_name())

ここでは、すべてのクラスメソッドを定義した後に、クラスの内部で locals() を呼び出すことになります。

したがって、これらのクラスメソッドもローカルシンボルテーブルの一部である必要があります。

結果は以下の通りです。

Calling locals() from inside a class => {'__module__': '__main__', '__qualname__': 'Student', '__init__': <function Student.__init__ at 0x7fe2672f0c80>, 'get_name': <function Student.get_name at 0x7fe2672f0d08>}
 
Calling globals() from inside a class => {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7fe2673cff28>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'locals_class.py', '__cached__': None}
Amit

確かに、見ての通り、locals()は関連するメソッドを与えています!

クラス本体から locals() を呼び出すと、モジュール名、クラス名、クラス変数が得られます。

グローバルシンボルテーブルには、予想通りこのようなものはありません。


まとめ

この記事では、locals() 関数を使用してローカルスコープから情報を取得する方法を学びました。

これはローカルシンボルテーブルから有用な名前と属性の辞書を返すもので、デバッグに非常に便利です。

参考文献

  • Python locals() 関数に関する StackOverflow の質問
  • Python locals() に関する Python 公式ドキュメント
  • Python locals() についての JournalDev の記事。

タイトルとURLをコピーしました