web-dev-qa-db-ja.com

変数名を文字列に変換しますか?

python変数名を示されているように同等の文字列に変換したいと思います。

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

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

これは、エラーが発生した場合、デバッグモードなどの状況で辞書の任意のリストを「ダンプ」するのに役立ちます。

必要なのは、eval()関数の逆です:

_get_indentifier_name_missing_function()
_

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


以下の現状を考慮してください。

_random_function(argument_data)
_

識別子名(「関数」、「変数」、「辞書」など)_argument_data_をrandom_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. 「識別子名」として機能する(表示、ログ、文字列の分割/連結など)
  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()関数にほとんど何も、特にフィルタリングされていない外部入力データを与えないように注意する必要があります。

39
Petru Zaharia

これは不可能です。

Pythonでは、実際には「変数」などはありません。 Pythonに実際にあるのは、オブジェクトをバインドできる「名前」です。オブジェクトに名前が付けられていても、それがバインドされているオブジェクトに違いはありません。異なる名前、またはなし。

この例を考えてみましょう:

foo = 1
bar = 1
baz = 1

ここで、値1の整数オブジェクトがあり、逆方向に作業してその名前を見つけたいとします。何を印刷しますか? 3つの異なる名前にはそのオブジェクトがバインドされており、すべて同じように有効です。

Pythonでは、名前はオブジェクトにアクセスする方法であるため、名前を直接操作する方法はありません。 Pythonバイトコードまたは名前の値を取得するための何かをハックする巧妙な方法があるかもしれませんが、それはせいぜいパーラーのトリックです。

print foo"foo"を出力させたいことがわかっている場合は、最初にprint "foo"を実行することもできます。

編集:私はこれをより明確にするために言葉遣いをわずかに変更しました。また、これはさらに良い例です。

foo = 1
bar = foo
baz = foo

実際には、Pythonは0または1などの一般的な値を持つ整数に同じオブジェクトを再利用するため、最初の例では同じオブジェクトを3つの名前すべてにバインドする必要があります。オブジェクトはfoo、bar、およびbazにバインドされます。

9
steveha

この質問を検索したのは、Pythonプログラムがプログラム内のいくつかの変数の割り当てステートメントを出力するようにしたかったためです。たとえば、 "foo = 3、bar = 21、baz =印刷関数は、文字列形式の変数名を必要とします。文字列「foo」、「bar」、および「baz」をコードに提供することもできますが、それは自分自身を繰り返すように感じました。前の答えを読んだ後、以下のソリューションを開発しました。

Globals()関数は、変数名(文字列形式)をキーとする辞書のように動作します。 globals()から各変数の値に対応するキーを取得したかった。メソッドglobals()。items()は、タプルのリストを返します。各タプルでは、​​最初の項目は変数名(文字列として)で、2番目は変数値です。私のvariablename()関数は、そのリストを検索して、文字列形式で名前が必要な変数の値に対応する変数名を見つけます。

関数itertools.ifilter()は、関数lambda x: var is globals()[x[0]]を使用してglobals()。items()リスト内の各Tupleをテストすることにより検索を行います。その関数でxはテストされるタプルです。 x [0]は(文字列としての)変数名で、x [1]は値です。ラムダ関数は、テストされた変数の値がvariablename()に渡された変数の値と同じかどうかをテストします。実際、is演算子を使用して、ラムダ関数は、テストされた変数の名前がvariablename()に渡された変数とまったく同じオブジェクトにバインドされているかどうかをテストします。その場合、タプルはテストに合格し、ifilter()によって返されます。

Itertools.ifilter()関数は、適切に呼び出されるまで結果を返さないイテレーターを実際に返します。適切に呼び出されるように、リスト内包表記[tpl[0] for tpl ... globals().items())]内に配置します。リスト内包表記では、変数値を無視して、変数名tpl[0]のみが保存されます。作成されるリストには、variablename()に渡される変数の値にバインドされる1つ以上の名前(ストリングとして)が含まれます。

以下に示すvariablename()の使用では、目的の文字列がリスト内の要素として返されます。多くの場合、それはリスト内の唯一のアイテムです。ただし、別の変数名に同じ値が割り当てられている場合、リストは長くなります。

>>> def variablename(var):
...     import itertools
...     return [tpl[0] for tpl in 
...     itertools.ifilter(lambda x: var is x[1], globals().items())]
... 
>>> var = {}
>>> variablename(var)
['var']
>>> something_else = 3
>>> variablename(something_else)
['something_else']
>>> yet_another = 3
>>> variablename(something_else)
['yet_another', 'something_else']
9
Ken Manly

技術的には情報は利用可能ですが、他の人が尋ねたように、どのように賢明な方法でそれを利用しますか?

>>> x = 52
>>> globals()
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', 
'x': 52, '__doc__': None, '__package__': None}

これは、変数名がglobals()辞書に文字列として存在することを示しています。

>>> globals().keys()[2]
'x'

この場合、それはたまたま3番目のキーですが、指定された変数名がどこで終わるかを知る信頼できる方法はありません

>>> for k in globals().keys():
...   if not k.startswith("_"):
...     print k
...
x
>>>

このようなシステム変数を除外することもできますが、それでも独自のアイテムをすべて取得することになります。上記のコードを実行するだけで、辞書の「x」の位置を変更する別の変数「k」が作成されました。

しかし、これはあなたにとって有益な出発点かもしれません。この機能の目的を教えていただければ、さらに役立つ情報が提供される可能性があります。

7
Todd

それが変数であり、2番目のクラスではない限り、これはここで機能します:

def print_var_name(variable):
 for name in globals():
     if eval(name) == variable:
        print name
foo = 123
print_var_name(foo)
>>>foo

これはクラスメンバーに対して発生します。

class xyz:
     def __init__(self):
         pass
member = xyz()
print_var_name(member)
>>>member

これはクラスの場合(例として):

abc = xyz
print_var_name(abc)
>>>abc
>>>xyz

クラスの場合、名前とプロパティを提供します

4
Alice

何を達成しようとしていますか?説明したことを実行する理由はまったくありません。解決しようとしている問題に対するより良い解決策が存在する可能性があります。

要求するものの最も明白な代替手段は辞書です。例えば:

>>> my_data = {'var': 'something'}
>>> my_data['something_else'] = 'something'
>>> print my_data.keys()
['var', 'something_else']
>>> print my_data['var']
something

主に挑戦として、私はあなたの希望する出力を実装しました。このコードは使用しないでください!

#!/usr/bin/env python2.6
class NewLocals:
    """Please don't ever use this code.."""
    def __init__(self, initial_locals):
        self.prev_locals = list(initial_locals.keys())

    def show_new(self, new_locals):
        output = ", ".join(list(set(new_locals) - set(self.prev_locals)))
        self.prev_locals = list(new_locals.keys())
        return output
# Set up
eww = None
eww = NewLocals(locals())

# "Working" requested code

var = {}

print eww.show_new(locals())  # Outputs: var

something_else = 3
print eww.show_new(locals()) # Outputs: something_else

# Further testing

another_variable = 4
and_a_final_one = 5

print eww.show_new(locals()) # Outputs: another_variable, and_a_final_one
3
dbr

名前を出力する変数を何らかの方法で参照する必要があります。したがって、次のようになります。

print varname(something_else)

そのような機能はありませんが、もしあったとしてもそれは無意味です。入力する必要がありますsomething_elseのように、引用符をその左右に入力するだけで、名前を文字列として出力できます。

print "something_else"
3
sth

任意のディレクトリを指定できる簡潔なバリエーションを次に示します。ディレクトリを使用して何かを検索する際の問題は、複数の変数が同じ値を持つ可能性があることです。したがって、このコードは可能な変数のリストを返します。

def varname( var, dir=locals()):
  return [ key for key, val in dir.items() if id( val) == id( var)]
2
ZevGriner

これはクールな解決策だと思うし、あなたが手に入れることができる最高のものだと思う。しかし、あいまいな結果を処理する方法はありますか? "is"演算子が整数で予期せず動作する が示すように、同じ値の低整数と文字列はpythonによってキャッシュされるため、variablename-functionは、私の場合、デコレータを作成して、変数に渡す変数によってクラスに新しい変数を追加します。

def inject(klass, dependency):
klass.__dict__["__"+variablename(dependency)]=dependency

しかし、メソッドがあいまいな結果を返す場合、追加した変数の名前を知るにはどうすればよいですか?

var any_var="myvarcontent"
var myvar="myvarcontent"
@inject(myvar)
class myclasss():
    def myclass_method(self):
        print self.__myvar    #I can not be sure, that this variable will be set...

ローカルリストもチェックする場合は、少なくとも「依存関係」変数をリストから削除できますが、これは信頼できる結果にはなりません。

2
fonzy

Djangoは、フィールド名を生成するときにこれを行いませんか?

http://docs.djangoproject.com/en/dev//topics/db/models/#verbose-field-names

理にかなっているようだ。

2
Joe

これは、単純なデータ型(str、int、float、listなど)で機能します。

 >>> def my_print(var_str):
 print var_str + ':'、globals()[var_str] 
 >>> a = 5 
 >>> b = ['hello'、 '、world!'] 
 >>> my_print( 'a')
 a:5 
 >>> my_print( 'b')
 b:['hello'、 '、world!'] 
0
Hadsbjerg