Pythonのglobals関数で動的変数を生成する方法6選

globals関数の徹底解説Python
この記事は約20分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればサンプルコードを活用して機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

●globals関数とは?

Pythonのglobals関数は、現在のグローバルシンボルテーブルを表す辞書を返す組み込み関数です。

グローバルシンボルテーブルとは、プログラムのグローバルな名前空間に存在する変数や関数の情報を格納している辞書のことです。

つまり、globals関数を使うことで、現在のグローバルな変数や関数の情報を取得することができるのです。

globals関数は、プログラムのデバッグやメタプログラミングなどの高度な用途で使用されることが多いですが、動的に変数を生成する際にも非常に便利な関数です。

動的に変数を生成するとは、プログラムの実行時に変数名や変数の値を決定することを指します。

これで、より柔軟性の高いプログラムを書くことができます。

私は、実際の開発現場でもglobals関数を使って動的に変数を生成することで、コードの可読性や保守性を高めたことがあります。

特に、設定ファイルから読み込んだ値を変数として使用する場合や、ユーザーからの入力に基づいて変数を生成する場合などには、globals関数が非常に役立ちました。

○globals関数の基本的な使い方

では、globals関数の基本的な使い方について見ていきましょう。

globals関数は引数を取らず、現在のグローバルシンボルテーブルを表す辞書を返します。

print(globals())

実行結果:

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

このように、globals関数を呼び出すと、現在のグローバルシンボルテーブルが辞書形式で返されます。

辞書のキーは変数名や関数名、値はそれらの値や関数オブジェクトになります。

○サンプルコード1:globals関数で変数を動的に生成する

それでは、globals関数を使って変数を動的に生成する方法を見ていきましょう。

次のサンプルコードでは、変数名を文字列で指定し、その変数に値を代入しています。

var_name = "dynamic_var"
value = 42

globals()[var_name] = value

print(dynamic_var)

実行結果:

42

このコードでは、まずvar_nameという変数に”dynamic_var”という文字列を代入しています。

次に、valueという変数に42という値を代入しています。

そして、globals()[var_name] = valueという行で、globals()関数を使ってグローバルシンボルテーブルを取得し、var_nameの値である”dynamic_var”をキーとして、valueの値である42を代入しています。

これで、”dynamic_var”という名前のグローバル変数が動的に生成され、42という値が代入されます。

最後に、print(dynamic_var)という行で、動的に生成された”dynamic_var”変数の値を出力しています。

実行結果から、動的に生成された変数の値が正しく取得できていることがわかります。

●動的変数の活用シーン

globals関数を使って動的に変数を生成することは、プログラムの柔軟性を高める上で非常に有効な手段だと考えています。

特に、ユーザーからの入力に基づいて変数を生成する場合や、設定ファイルから読み込んだ値を変数として使用する場合、外部データに基づいて変数を生成する場合など、様々な場面で活用できます。

それでは、具体的なサンプルコードを見ながら、動的変数の活用シーンについて詳しく見ていきましょう。

○サンプルコード2:ユーザー入力に基づいた変数の生成

まず、ユーザーからの入力に基づいて変数を生成する方法について見ていきます。

次のサンプルコードでは、ユーザーに変数名と値を入力してもらい、その変数を動的に生成しています。

var_name = input("変数名を入力してください: ")
value = input("値を入力してください: ")

globals()[var_name] = value

print(f"{var_name} = {globals()[var_name]}")

実行結果

変数名を入力してください: user_input
値を入力してください: Hello, World!
user_input = Hello, World!

このコードでは、input関数を使ってユーザーに変数名と値を入力してもらっています。

入力された変数名はvar_nameに、値はvalueに格納されます。

そして、globals()[var_name] = valueという行で、globals()関数を使ってグローバルシンボルテーブルを取得し、var_nameの値をキーとして、valueの値を代入しています。

こうすることで、ユーザーが入力した変数名と値を持つ変数が動的に生成されます。

最後に、print(f"{var_name} = {globals()[var_name]}")という行で、動的に生成された変数の名前と値を出力しています。

実行結果から、ユーザーが入力した変数名と値が正しく取得できていることがわかります。

○サンプルコード3:設定ファイルからの変数の生成

次に、設定ファイルから読み込んだ値を変数として使用する方法について見ていきます。

次のサンプルコードでは、JSON形式の設定ファイルから値を読み込み、その値を持つ変数を動的に生成しています。

import json

with open("config.json") as f:
    config = json.load(f)

for key, value in config.items():
    globals()[key] = value

print(f"database_url = {database_url}")
print(f"api_key = {api_key}")

設定ファイル(config.json)

{
  "database_url": "mysql://user:password@localhost/db_name",
  "api_key": "abcdefghijklmnop"
}

実行結果

database_url = mysql://user:password@localhost/db_name
api_key = abcdefghijklmnop

このコードでは、jsonモジュールを使ってJSON形式の設定ファイル(config.json)を読み込んでいます。

読み込んだ設定値はconfig辞書に格納されます。

次に、forループを使ってconfig辞書のキーと値を取り出し、globals()[key] = valueという行で、キーを変数名、値を変数の値として、動的に変数を生成しています。

最後に、print関数を使って、動的に生成された変数の値を出力しています。

実行結果から、設定ファイルに記述された値が正しく変数に設定されていることがわかります。

○サンプルコード4:外部データに基づいた変数の生成

最後に、外部データに基づいて変数を生成する方法について見ていきます。

次のサンプルコードでは、CSVファイルからデータを読み込み、そのデータを持つ変数を動的に生成しています。

import csv

with open("data.csv") as f:
    reader = csv.DictReader(f)
    for row in reader:
        for key, value in row.items():
            globals()[key] = value

print(f"name = {name}")
print(f"age = {age}")
print(f"city = {city}")

CSVファイル(data.csv)

name,age,city
Alice,25,New York
Bob,30,London

実行結果

name = Bob
age = 30
city = London

このコードでは、csvモジュールを使ってCSVファイル(data.csv)を読み込んでいます。

csv.DictReaderを使うことで、CSVの1行目をキーとして、各行のデータを辞書形式で取得できます。

forループを使ってCSVの各行を処理し、さらにその中でforループを使って各列のキーと値を取り出しています。

そして、globals()[key] = valueという行で、キーを変数名、値を変数の値として、動的に変数を生成しています。

最後に、print関数を使って、動的に生成された変数の値を出力しています。

実行結果から、CSVファイルの最後の行のデータが変数に設定されていることがわかります。

●動的変数のメリットとデメリット

globals関数を使って動的に変数を生成することには、いくつかのメリットとデメリットがあります。

ここでは、それぞれについて詳しく見ていきましょう。

○メリット

まず、動的変数のメリットについて考えてみます。

動的変数を使うことで、プログラムの柔軟性を高めることができるでしょう。

例えば、ユーザーからの入力やファイルから読み込んだ値に基づいて変数を生成することで、より汎用性の高いプログラムを書くことができます。

また、動的変数を活用することで、コードの重複を減らすことができると思います。

同じような処理を複数の変数に対して行う場合、動的に変数を生成することで、コードの量を削減できるかもしれません。

さらに、動的変数を使うことで、コードの可読性を高められる場合もあります。

変数名を動的に生成することで、より意味のある変数名を付けられるようになるでしょう。

○デメリット

一方で、動的変数にはデメリットもあります。

まず、動的に変数を生成すると、コードの予測可能性が低くなる可能性があります。

変数名や変数の値が動的に決まるため、コードを見ただけでは変数の内容を把握しにくくなるかもしれません。

また、動的変数を乱用すると、かえってコードの可読性が低下する恐れがあります。

多くの変数を動的に生成しすぎると、コードが複雑になり、理解しづらくなってしまうでしょう。

加えて、動的変数を使う際には、名前空間の汚染や変数名の衝突にも注意が必要です。

グローバルな名前空間で変数を動的に生成すると、他の部分で使用されている変数を上書きしてしまう可能性があります。

●globals関数を使う際の注意点

globals関数は非常に便利な機能ですが、使い方を誤ると予期せぬ問題を引き起こす可能性があります。

ここでは、globals関数を使う際の注意点について、具体的なサンプルコードを交えながら解説していきましょう。

○サンプルコード5:名前空間の汚染を避ける

globals関数を使って動的に変数を生成する際は、名前空間の汚染に注意が必要です。

グローバルな名前空間で多くの変数を動的に生成すると、他の部分で使用されている変数を上書きしてしまう恐れがあるのです。

例えば、次のようなコードを考えてみましょう。

for i in range(10):
    globals()[f"var_{i}"] = i

print(var_0)
print(var_1)
print(var_2)

実行結果

0
1
2

このコードでは、forループを使って10個の変数を動的に生成しています。

変数名はvar_0からvar_9までの連番になっています。

一見問題なさそうに見えますが、もし他の部分のコードでvar_0var_1などの変数名を使用していた場合、それらの変数が上書きされてしまう可能性があります。

こうした名前空間の汚染を避けるためには、動的に生成する変数名をユニークなものにするなどの工夫が必要でしょう。

例えば、接頭辞や接尾辞を付けるといった方法が考えられます。

prefix = "dynamic_"

for i in range(10):
    globals()[f"{prefix}var_{i}"] = i

print(dynamic_var_0)
print(dynamic_var_1)
print(dynamic_var_2)

実行結果

0
1
2

このようにすれば、他の部分のコードと変数名が衝突する可能性を減らすことができます。

○サンプルコード6:変数名の衝突を避ける

globals関数で動的に変数を生成する際は、変数名の衝突にも注意が必要です。

特に、ユーザーからの入力をそのまま変数名に使用すると、予期せぬ問題を引き起こす恐れがあります。

例えば、次のようなコードを考えてみましょう。

while True:
    var_name = input("変数名を入力してください(終了する場合はquit): ")
    if var_name == "quit":
        break

    value = input("値を入力してください: ")
    globals()[var_name] = value

print(globals())

実行結果

変数名を入力してください(終了する場合はquit): x
値を入力してください: 10
変数名を入力してください(終了する場合はquit): y
値を入力してください: 20
変数名を入力してください(終了する場合はquit): quit
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7f7a6c0f0bb0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'example.py', '__cached__': None, 'x': '10', 'y': '20'}

このコードでは、ユーザーに変数名と値を入力してもらい、その変数を動的に生成しています。

quitと入力されるまで、変数の生成を繰り返します。

しかし、ユーザーが入力した変数名が既存の変数名と衝突した場合、その変数が上書きされてしまいます。

また、ユーザーが不適切な変数名を入力した場合、エラーが発生する可能性もあります。

こうした変数名の衝突を避けるためには、変数名のチェックを行うなどの対策が必要です。

例えば、予約語や既存の変数名との衝突をチェックし、適切な変数名のみを受け入れるようにするといった方法が考えられます。

import keyword

while True:
    var_name = input("変数名を入力してください(終了する場合はquit): ")
    if var_name == "quit":
        break

    if keyword.iskeyword(var_name) or var_name in globals():
        print("不適切な変数名です。別の名前を入力してください。")
        continue

    value = input("値を入力してください: ")
    globals()[var_name] = value

print(globals())

実行結果

変数名を入力してください(終了する場合はquit): if
不適切な変数名です。別の名前を入力してください。
変数名を入力してください(終了する場合はquit): x
値を入力してください: 10
変数名を入力してください(終了する場合はquit): y
値を入力してください: 20
変数名を入力してください(終了する場合はquit): quit
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7f1a1c0d0bb0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'example.py', '__cached__': None, 'keyword': <module 'keyword' from '/usr/lib/python3.8/keyword.py'>, 'x': '10', 'y': '20'}

このコードでは、keywordモジュールのiskeyword関数を使って予約語との衝突をチェックし、var_name in globals()で既存の変数名との衝突をチェックしています。

不適切な変数名が入力された場合は、エラーメッセージを表示して再入力を促します。

●globals関数の応用例

ここまでglobals関数の基本的な使い方や注意点について見てきましたが、globals関数にはさらに高度な応用例があります。

ここでは、そうした応用例をいくつか紹介しながら、globals関数の可能性を探っていきましょう。

○サンプルコード7:動的なクラス属性の生成

まず、globals関数を使って動的にクラス属性を生成する方法について見ていきます。

次のサンプルコードでは、クラス定義時に動的に属性を追加しています。

class MyClass:
    pass

attr_name = "my_attribute"
attr_value = 42

setattr(MyClass, attr_name, attr_value)

obj = MyClass()
print(obj.my_attribute)

実行結果

42

このコードでは、MyClassというクラスを定義した後、attr_nameattr_valueという変数を使って動的に属性を追加しています。

setattr関数を使うことで、MyClassmy_attributeという名前の属性を追加し、その値として42を設定しています。

その後、MyClassのインスタンスを作成し、my_attribute属性の値を出力しています。

実行結果から、動的に追加された属性の値が正しく取得できていることがわかります。

こうした動的なクラス属性の生成は、設定ファイルから読み込んだ値をクラス属性として設定する場合などに役立ちます。

柔軟なクラス定義を実現できるでしょう。

○サンプルコード8:動的なモジュールのインポート

次に、globals関数を使って動的にモジュールをインポートする方法について見ていきます。

次のサンプルコードでは、ユーザーが入力したモジュール名を動的にインポートしています。

module_name = input("インポートするモジュール名を入力してください: ")

module = __import__(module_name)

globals()[module_name] = module

print(f"{module_name}モジュールをインポートしました")
print(globals())

実行結果

インポートするモジュール名を入力してください: math
mathモジュールをインポートしました
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7fc9f40d0bb0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'example.py', '__cached__': None, 'module_name': 'math', 'module': <module 'math' from '/usr/lib/python3.8/lib-dynload/math.cpython-38-x86_64-linux-gnu.so'>, 'math': <module 'math' from '/usr/lib/python3.8/lib-dynload/math.cpython-38-x86_64-linux-gnu.so'>}

このコードでは、input関数を使ってユーザーにインポートするモジュール名を入力してもらっています。

入力されたモジュール名はmodule_name変数に格納されます。

次に、__import__関数を使って、module_nameの値に基づいてモジュールを動的にインポートしています。

インポートされたモジュールはmodule変数に格納されます。

そして、globals()[module_name] = moduleという行で、インポートされたモジュールをグローバル名前空間に追加しています。

これで、インポートされたモジュールがグローバル変数として扱えるようになります。

最後に、インポートされたモジュールの情報を出力しています。

実行結果から、ユーザーが入力したモジュール名に基づいてモジュールが動的にインポートされ、グローバル名前空間に追加されていることがわかります。

こうした動的なモジュールのインポートは、プラグイン機構の実装などに役立ちます。

必要に応じて柔軟にモジュールを読み込むことができるでしょう。

○サンプルコード9:動的な関数の生成

続いて、globals関数を使って動的に関数を生成する方法について見ていきます。

次のサンプルコードでは、関数の本体を文字列で定義し、その文字列からコンパイルして関数を生成しています。

func_name = "my_func"
func_body = "def my_func(x):\n    return x * 2\n"

exec(func_body, globals())

result = my_func(10)
print(result)

実行結果

20

このコードでは、func_name変数に関数名を、func_body変数に関数の本体を文字列で定義しています。

func_bodyでは、my_funcという名前の関数を定義し、引数xを2倍して返すようにしています。

次に、exec関数を使って、func_bodyの文字列をコンパイルして実行しています。

globals()を第2引数に指定することで、生成された関数がグローバル名前空間に追加されます。

最後に、生成されたmy_func関数を呼び出し、結果を出力しています。

実行結果から、動的に生成された関数が正しく動作していることがわかります。

○サンプルコード10:動的なデコレータの生成

最後に、globals関数を使って動的にデコレータを生成する方法について見ていきます。

次のサンプルコードでは、実行時にデコレータを動的に生成し、関数に適用しています。

def create_decorator(decorator_name):
    def decorator(func):
        def wrapper(*args, **kwargs):
            print(f"{decorator_name} デコレータが適用されました")
            return func(*args, **kwargs)
        return wrapper
    return decorator

decorator_name = "my_decorator"
globals()[decorator_name] = create_decorator(decorator_name)

@my_decorator
def greet(name):
    print(f"こんにちは、{name}さん!")

greet("Alice")

実行結果

my_decorator デコレータが適用されました
こんにちは、Aliceさん!

このコードでは、create_decorator関数を定義しています。

この関数は、デコレータの名前を引数に取り、実際のデコレータ関数を返します。

デコレータ関数内では、関数が呼び出される前にメッセージを出力するようにしています。

次に、decorator_name変数にデコレータの名前を設定し、globals()[decorator_name] = create_decorator(decorator_name)という行で、create_decorator関数を呼び出して動的にデコレータを生成しています。

生成されたデコレータは、グローバル名前空間に追加されます。

そして、@my_decoratorというシンタックスを使って、greet関数にデコレータを適用しています。

最後に、greet関数を呼び出しています。

実行結果から、動的に生成されたデコレータが適用され、関数呼び出し前にメッセージが出力されていることがわかります。

こうした動的なデコレータの生成は、実行時に柔軟にデコレータを適用したい場合に役立ちます。

状況に応じて適切なデコレータを動的に選択することができるでしょう。

まとめ

本記事では、Pythonのglobals関数を使って動的に変数を生成する方法について、初心者から上級者まで役立つ多様なサンプルコードを交えながら詳しく解説してきました。

本記事が、globals関数の理解を深め、Pythonプログラミングのスキルアップに役立つことを願っています。

動的変数を適材適所で活用し、より洗練されたコードを書けるようになってくだされば、この記事を執筆した甲斐あるものです。