1. ホーム
  2. python

[解決済み] 変数名から文字列への変換は?

2023-03-22 05:59:45

質問

Pythonの変数名を文字列に変換したいのですが、どうすればよいですか?どのようなアイデアがありますか?

var = {}
print ???  # Would like to see 'var'
something_else = 3
print ???  # Would print 'something_else'

どのように解決するのですか?

TL;DR: 不可能です。最後の「結論」をご覧ください。


これが必要になる可能性のある使用シナリオがあります。私は、より良い方法や同じ機能を達成する方法がないと言っているわけではありません。

これは、エラー発生時、デバッグモード、および他の同様の状況で、辞書の任意のリストを「ダンプ」するために有用でしょう。

必要とされるのは、逆方向の eval() 関数の逆です。

get_indentifier_name_missing_function()

は、識別子名('変数'、'辞書'など)を引数として受け取り、識別子の名前を含む文字列を返します。 文字列を返します。


以下のような現状を考えてみましょう。

random_function(argument_data)

識別子名('function'、'variable'、'dictionary'など)を渡す場合 argument_datarandom_function() (別の識別子名) を渡すと、実際に識別子 (例えば <argument_data object at 0xb1ce10> ) を別の識別子 (例えば <function random_function at 0xafff78> ):

<function random_function at 0xafff78>(<argument_data object at 0xb1ce10>)

私の理解では、関数に渡されるのはメモリアドレスのみです。

<function at 0xafff78>(<object at 0xb1ce10>)

そのため、文字列を引数として random_function() に文字列を渡して、その関数が引数の識別子の名前を持つようにする必要があります。

random_function('argument_data')

random_function()の内部

def random_function(first_argument):

の場合、すでに提供されている文字列 'argument_data' にします。

  1. 識別子名」として機能する (表示、ログ、文字列分割/concat などのために)

  2. をフィードします。 eval() 関数に送り、実際の識別子への参照、つまり実際のデータへの参照を取得します。

    print("Currently working on", first_argument)
    some_internal_var = eval(first_argument)
    print("here comes the data: " + str(some_internal_var))
    
    

残念ながら、これはすべてのケースでうまくいくわけではありません。うまくいくのは random_function() を解決できる場合のみです。 'argument_data' の文字列を実際の識別子に解決することができます。すなわち、もし argument_data の中に識別子の名前があれば random_function() の名前空間を使用します。

これは常にそうであるとは限りません。

# main1.py
import some_module1

argument_data = 'my data'

some_module1.random_function('argument_data')


# some_module1.py
def random_function(first_argument):
    print("Currently working on", first_argument)
    some_internal_var = eval(first_argument)
    print("here comes the data: " + str(some_internal_var))
######

期待される結果は、次のようになります。

Currently working on: argument_data
here comes the data: my data

なぜなら argument_data の識別子名は random_function() の名前空間で利用できない場合は、代わりにこれが返されます。

Currently working on argument_data
Traceback (most recent call last):
  File "~/main1.py", line 6, in <module>
    some_module1.random_function('argument_data')
  File "~/some_module1.py", line 4, in random_function
    some_internal_var = eval(first_argument)
  File "<string>", line 1, in <module>
NameError: name 'argument_data' is not defined


では、仮の使い方として get_indentifier_name_missing_function() を使うと、上記のように動作します。

Python 3.0のダミーのコードです。.

# main2.py
import some_module2
some_dictionary_1       = { 'definition_1':'text_1',
                            'definition_2':'text_2',
                            'etc':'etc.' }
some_other_dictionary_2 = { 'key_3':'value_3',
                            'key_4':'value_4', 
                            'etc':'etc.' }
#
# more such stuff
#
some_other_dictionary_n = { 'random_n':'random_n',
                            'etc':'etc.' }

for each_one_of_my_dictionaries in ( some_dictionary_1,
                                     some_other_dictionary_2,
                                     ...,
                                     some_other_dictionary_n ):
    some_module2.some_function(each_one_of_my_dictionaries)


# some_module2.py
def some_function(a_dictionary_object):
    for _key, _value in a_dictionary_object.items():
        print( get_indentifier_name_missing_function(a_dictionary_object)    +
               "    " +
               str(_key) +
               "  =  " +
               str(_value) )
######

期待される結果は、次のようになります。

some_dictionary_1    definition_1  =  text_1
some_dictionary_1    definition_2  =  text_2
some_dictionary_1    etc  =  etc.
some_other_dictionary_2    key_3  =  value_3
some_other_dictionary_2    key_4  =  value_4
some_other_dictionary_2    etc  =  etc.
......
......
......
some_other_dictionary_n    random_n  =  random_n
some_other_dictionary_n    etc  =  etc.

残念ながら get_indentifier_name_missing_function() では、「元の」識別子の名前 ( some_dictionary_ , some_other_dictionary_2 , some_other_dictionary_n ). それは a_dictionary_object という識別子名だけが表示されます。

したがって、本当の結果はむしろ

a_dictionary_object    definition_1  =  text_1
a_dictionary_object    definition_2  =  text_2
a_dictionary_object    etc  =  etc.
a_dictionary_object    key_3  =  value_3
a_dictionary_object    key_4  =  value_4
a_dictionary_object    etc  =  etc.
......
......
......
a_dictionary_object    random_n  =  random_n
a_dictionary_object    etc  =  etc.

では、逆に eval() 関数はこの場合、それほど有用ではないでしょう。


現状では、このようにする必要があるでしょう。

# main2.py same as above, except:

    for each_one_of_my_dictionaries_names in ( 'some_dictionary_1',
                                               'some_other_dictionary_2',
                                               '...',
                                               'some_other_dictionary_n' ):
        some_module2.some_function( { each_one_of_my_dictionaries_names :
                                     eval(each_one_of_my_dictionaries_names) } )
    
    
    # some_module2.py
    def some_function(a_dictionary_name_object_container):
        for _dictionary_name, _dictionary_object in a_dictionary_name_object_container.items():
            for _key, _value in _dictionary_object.items():
                print( str(_dictionary_name) +
                       "    " +
                       str(_key) +
                       "  =  " +
                       str(_value) )
    ######


結論から言うと

  • Pythonは関数への引数としてメモリアドレスのみを渡します。
  • 識別子の名前を表す文字列は、実際の識別子を参照するためにのみ eval() 関数で実際の識別子を参照することができます。
  • の仮想的な逆で eval() 関数は、識別子の名前が呼び出し側のコードから直接見えない場合には、 役に立ちません。たとえば、呼び出された関数の内部などです。
  • 現在、関数に渡す必要があるのは
    1. 識別子の名前を表す文字列
    2. 実際の識別子(メモリアドレス)

を渡すことで、これを実現できます。 'string'eval('string') を同時に呼び出すことができます。これは、任意の関数、モジュール、名前空間にわたってこの卵鶏問題を解決する、コーナーケースのソリューションを使用せずに、最も「一般的」な方法だと思います。唯一の欠点は eval() という関数があり、これは簡単に安全でないコードにつながる可能性があります。を送り込まないように注意する必要があります。 eval() 関数に何もかも、特にフィルタリングされていない外部入力データを与えないように注意する必要があります。