web-dev-qa-db-ja.com

別々の変数の辞書を作成するためのより簡単な方法は?

変数の名前を文字列として取得したいのですが、Pythonがそれほど多くのイントロスペクション機能を持っているかどうかわかりません。何かのようなもの:

>>> print(my_var.__name__)
'my_var'

それをやりたいのは、たくさんの変数があるからです。

bar = True
foo = False
>>> my_dict = dict(bar=bar, foo=foo)
>>> print my_dict 
{'foo': False, 'bar': True}

しかし、私はそれよりもっと自動化したものが欲しいのです。

Pythonにはlocals()vars()があるので、方法があると思います。

216
e-satis

あなたはこれをやろうとしていますか?

dict( (name,eval(name)) for name in ['some','list','of','vars'] )

>>> some= 1
>>> list= 2
>>> of= 3
>>> vars= 4
>>> dict( (name,eval(name)) for name in ['some','list','of','vars'] )
{'list': 2, 'some': 1, 'vars': 4, 'of': 3}
47
S.Lott

巻き戻しが言ったように、これは実際にPythonですることではありません - 変数は実際にはオブジェクトへの名前マッピングです。

ただし、これを試して実行する1つの方法があります。

 >>> a = 1
 >>> for k, v in list(locals().iteritems()):
         if v is a:
             a_as_str = k
 >>> a_as_str
 a
 >>> type(a_as_str)
 'str'
130
rlotun

私はこれをかなりたくさんやりたかった。このハックはrlotunの提案と非常によく似ていますが、これはワンライナーです。これは私にとって重要です。

blah = 1
blah_name = [ k for k,v in locals().iteritems() if v is blah][0]

Python 3+

blah = 1
blah_name = [ k for k,v in locals().items() if v is blah][0]
61
keflavich

これはハックです。すべてのPython実装ディストリビューション(特にtraceback.extract_stackを持たないディストリビューション)では動作しません。

import traceback

def make_dict(*expr):
    (filename,line_number,function_name,text)=traceback.extract_stack()[-2]
    begin=text.find('make_dict(')+len('make_dict(')
    end=text.find(')',begin)
    text=[name.strip() for name in text[begin:end].split(',')]
    return dict(Zip(text,expr))

bar=True
foo=False
print(make_dict(bar,foo))
# {'foo': False, 'bar': True}

このハックは壊れやすいことに注意してください。

make_dict(bar,
          foo)

(2行でmake_dictを呼び出す)は機能しません。

valuesfoobarから辞書を生成するのではなく、文字列変数名'foo''bar'から辞書を生成する方がはるかにPythonicになります。

dict([(name,locals()[name]) for name in ('foo','bar')])
17
unutbu

これはPythonでは不可能で、実際には「変数」がありません。 Pythonには名前があり、同じオブジェクトに複数の名前を付けることができます。

14
unwind

私は私の問題がなぜこの質問が役に立つのかを説明するのに役立つと思います、そしてそれはそれにどう答えるかについてもう少し洞察を与えるかもしれません。私は自分のコードの中のさまざまな変数を簡単にインラインヘッドチェックするための小さな関数を書きました。基本的には、変数名、データ型、サイズ、その他の属性がリストされているので、自分が行った間違いをすぐに見つけることができます。コードは簡単です:

def details(val):
  vn = val.__                #  If such a thing existed
  vs = str(val)
  print("The Value of "+ str(vn) + " is " + vs)
  print("The data type of " + vn + " is " + str(type(val)))

あなたが複雑な辞書/リスト/タプルの状況を抱えているのであれば、インタプリタがあなたが割り当てた変数名を返すようにすることは非常に役に立つでしょう。例えば、これは奇妙な辞書です:

m = 'abracadabra'
mm=[]    
for n in m:
  mm.append(n)
mydic = {'first':(0,1,2,3,4,5,6),'second':mm,'third':np.arange(0.,10)}



details(mydic)

The Value of mydic is {'second': ['a', 'b', 'r', 'a', 'c', 'a', 'd', 'a', 'b', 'r', 'a'], 'third': array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9.]), 'first': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}
The data type of mydic is <type 'dict'>

details(mydic['first'])
The Value of mydic['first'] is (0, 1, 2, 3, 4, 5, 6)]
The data type of mydic['first'] is <type 'list'>

details(mydic.keys())
The Value of mydic.keys() is ['second', 'third', 'first']
The data type of mydic.keys() is <type 'Tuple'>

details(mydic['second'][0])
The Value of mydic['second'][0] is a
The data type of mydic['second'][0] is <type 'str'>

これを適切な場所に配置したかどうかはわかりませんが、役立つ可能性があると思いました。私はそれが願っています。

10
TheProletariat

私はこの質問への答えに基づいて、きちんとしたちょっと便利な機能を書きました。私はそれが役に立つ場合に備えてここに置いています。

def what(obj, callingLocals=locals()):
    """
    quick function to print name of input and value. 
    If not for the default-Valued callingLocals, the function would always
    get the name as "obj", which is not what I want.    
    """
    for k, v in list(callingLocals.items()):
         if v is obj:
            name = k
    print(name, "=", obj)

使用法:

>> a = 4
>> what(a)
a = 4
>>|
8
aquirdturtle

Python 3ではこれは簡単です

myVariable = 5
for v in locals():
  if id(v) == id("myVariable"):
    print(v, locals()[v])

これは印刷されます:

myVariable 5

6
officialhopsof

もしあなたがすでに特定の値のリストを持っているのであれば、それは@ Sで説明されている方法です。ロッツは最高です。しかし、以下に説明する方法は、すべての変数とクラスをコード全体に追加するのに適しています。WITHOUT変数名を指定する必要はありますが、必要に応じて指定できます。コードはクラスを除外するように拡張できます。

import types
import math  # mainly showing that you could import what you will before d

# Everything after this counts
d = dict(globals())

def kv_test(k,v):
    return (k not in d and 
            k not in ['d','args'] and
            type(v) is not types.FunctionType)

def magic_print(*args):
    if len(args) == 0: 
        return {k:v for k,v in globals().iteritems() if kv_test(k,v)}
    else:
        return {k:v for k,v in magic_print().iteritems() if k in args}

if __== '__main__':
    foo = 1
    bar = 2
    baz = 3
    print magic_print()
    print magic_print('foo')
    print magic_print('foo','bar')

出力:

{'baz': 3, 'foo': 1, 'bar': 2}
{'foo': 1}
{'foo': 1, 'bar': 2}
6
cdhagmann

これが私が変数名を読むために作成した関数です。より一般的で、さまざまな用途に使用できます。

def get_variable_name(*variable):
    '''gets string of variable name
    inputs
        variable (str)
    returns
        string
    '''
    if len(variable) != 1:
        raise Exception('len of variables inputed must be 1')
    try:
        return [k for k, v in locals().items() if v is variable[0]][0]
    except:
        return [k for k, v in globals().items() if v is variable[0]][0]

指定された質問でそれを使用するには:

>>> foo = False
>>> bar = True
>>> my_dict = {get_variable_name(foo):foo, 
               get_variable_name(bar):bar}
>>> my_dict
{'bar': True, 'foo': False}
5
Anna

Python 3 inspectを使って呼び出し側のローカル名前空間を捉え、それからここで提示されたアイデアを使います。指摘されているように、複数の回答を返すことができます。

def varname(var):
  import inspect
  frame = inspect.currentframe()
  var_id = id(var)
  for name in frame.f_back.f_locals.keys():
    try:
      if id(eval(name)) == var_id:
        return(name)
    except:
      pass
5
vvxxii

スレッドを読んでいるとき、私はひどい摩擦を見ました。悪い答えを出し、それから誰かに正しい答えを出させるのは十分簡単です。とにかく、これが私が見つけたものです。

投稿者:[effbot.org]( http://effbot.org/zone/python-objects.htm#names

名前は少し異なります - それらは実際にはオブジェクトのプロパティではなく、オブジェクト自体はそれが何を呼んでいるのかを知りません。

オブジェクトは、任意の数の名前を持つことも、まったく名前を付けないこともできます。

名前は名前空間(モジュール名前空間、インスタンス名前空間、関数のローカル名前空間など)にあります。

注:それが言うこと オブジェクト自体はそれが何と呼ばれているのかわからないだから、それが手がかりだった。 Pythonオブジェクトは自己参照的ではありません。それからそれは言う、 名前は名前空間に存在する。これはTCL/TKにあります。だから私の答えが役立つかもしれません(しかしそれは私を助けました)

 
 jj = 123 
 print eval( "'" + str(id(jj))+ "" ")
 print dir()
 ] 
 166707048 
 ['__ builtins__'、 '__ doc _'、 '__file__'、 '__name__'、 '__package__'、 'jj'] 

そのため、リストの最後に 'jj'があります。

コードを次のように書き換えます。

 
 jj = 123 
 print dval()のxに対してeval( "'" + str(id(jj))+ "'")
:[ print id(eval(x))
 
 161922920 
 ['__ builtins__'、 '__ doc _'、 '__file__'、 '__name__'、 '__package__'、 'jj'] 
 3077447796 
 136515736 
 3077408320 
 3077656800 
 136515736 
 161922920 

コードIDのこの厄介な部分は、変数/オブジェクト/あなたの小児科学 - それを呼び出す - それの名前です。

だから、あります。 'jj'のメモリアドレスは、辞書をグローバルネームスペースで検索するときと同じように、直接検索したときと同じです。私はあなたがこれを行うための機能を作ることができると確信しています。あなたの変数/ object/wypciがどの名前空間にあるか覚えておいてください。

QED.

4

私はこの種の魔法を頑健にするためにパッケージ sorcery を書きました。あなたは書ける:

from sorcery import dict_of

my_dict = dict_of(foo, bar)
2
Alex Hall
import re
import traceback

pattren = re.compile(r'[\W+\w+]*get_variable_name\((\w+)\)')
def get_variable_name(x):
    return pattren.match( traceback.extract_stack(limit=2)[0][3]) .group(1)

a = 1
b = a
c = b
print get_variable_name(a)
print get_variable_name(b)
print get_variable_name(c)
2
xmduhan

pypi に解答をアップロードしました。これはC#のnameof関数と同等のものを定義するモジュールです。

呼び出されたフレームのバイトコード命令を繰り返し、渡された変数/属性の名前を取得します。名前は、関数名に続くLOAD命令の.argreprにあります。

2
user7340830

Python 2.7以降では、辞書を理解することもできます。可能であれば、トップアンサーのようにeval(evalは悪)の代わりにgetattrを使用します。自己はあなたが見ている文脈を持っているどんな物でもありえます。それはオブジェクトかlocals = locals()などです。

{name: getattr(self, name) for name in ['some', 'vars', 'here]}
1
yvess

ほとんどのオブジェクトは_ NAME _属性を持っていません。 (クラス、関数、そしてモジュールは持っています;それを持っている他の組み込み型は?)

print(my_var.__name__)以外のprint("my_var")に対して他に何を期待しますか?あなたは単に文字列を直接使うことができますか?

辞書を「スライス」することができます。

def dict_slice(D, keys, default=None):
  return dict((k, D.get(k, default)) for k in keys)

print dict_slice(locals(), ["foo", "bar"])
# or use set literal syntax if you have a recent enough version:
print dict_slice(locals(), {"foo", "bar"})

あるいは

throw = object()  # sentinel
def dict_slice(D, keys, default=throw):
  def get(k):
    v = D.get(k, throw)
    if v is not throw:
      return v
    if default is throw:
      raise KeyError(k)
    return default
  return dict((k, get(k)) for k in keys)
1
Roger Pate

さて、私は数日前に全く同じneedに遭遇しました、そして変数のnameを指していなければなりませんでしたオブジェクト自体.

そして、なぜそれがそれほど必要だったのでしょうか?

要するに私はMaya用のプラグインを作成していました。コアプラグインはC++を使用して構築されていますが、GUIはPythonを使用して描画されています(プロセッサ集約型ではないため)。私はまだ、デフォルトのreturn以外のプラグインからMStatusの複数の値を取得する方法がわからないので、Pythonで辞書を更新するために、GUIを実装するオブジェクトを指す変数の名前を渡す必要がありましたそしてそれは、プラグインに対して、辞書自体を含んでいて、それからMayaのグローバルスコープから辞書を更新するためにMGlobal::executePythonCommand()を使います。

それをするために私がしたことは以下のようなものでした:

import time

class foo(bar):

    def __init__(self):
        super(foo, self).__init__()
        self.time = time.time() #almost guaranteed to be unique on a single computer

    def name(self):
        g = globals()
        for x in g:
            if isinstance(g[x], type(self)):
                if g[x].time == self.time:
                    return x
                    #or you could:
                    #return filter(None,[x if g[x].time == self.time else None for x in g if isinstance(g[x], type(self))])
                    #and return all keys pointing to object itself

私はそれがglobalsで完璧な解決策ではないことを知っています多くのキーが同じobjectを指しているかもしれません。

a = foo()
b = a
b.name()
>>>b
or
>>>a

そしてそのアプローチはスレッドセーフではないということです。間違っていれば訂正してください。

少なくともこのアプローチは、object自体を指しているグローバルスコープ内の任意の変数のnameを取得してプラグインに渡すことによって私の問題を解決しました。 inは、引数として、内部的に使用されるためです。

私はこれをint(プリミティブ整数クラス)で試しましたが、問題はこれらのプリミティブクラスがバイパスされないことです(間違っている場合は使用されている技術用語を修正してください)。 intを再実装してからint = fooを実行することはできますが、a = 3は決してfooのオブジェクトではなくプリミティブのオブジェクトになります。これを克服するには、a = foo(3)を機能させるためにa.name()を使用する必要があります。

1

Python3では、この関数はスタックの最も外側の名前を取得します。

import inspect


def retrieve_name(var):
        """
        Gets the name of var. Does it from the out most frame inner-wards.
        :param var: variable to get name from.
        :return: string
        """
        for fi in reversed(inspect.stack()):
            names = [var_name for var_name, var_val in fi.frame.f_locals.items() if var_val is var]
            if len(names) > 0:
                return names[0]

コードのどこでも役に立ちます。最初の一致を探すために逆スタックをたどります。

1
juan Isaza

私は同様の問題に取り組んでいました。 @ S.Lott氏は、「変数のリストがある場合、それらの名前を「発見」するポイントは何ですか?」そして私の答えは、それが実行できるかどうか、そして何らかの理由であなたの変数をタイプ別にリストにしたいのかどうかを見ることです。とにかく、私の調査で私はこのスレッドに出会いました、そして私の解決策は少し拡張されていて@rlotunソリューションに基づいています。もう1つ、@unutbuは言った、「この考えにはメリットがありますが、2つの変数名が同じ値を参照する場合(Trueなど)、意図しない変数名が返される可能性があります。」この演習ではそれが本当だったので、私はそれぞれの可能性についてこれに似たリスト内包表記を使ってそれを扱いました:isClass = [i for i in isClass if i != 'item']。それがなければ "item"が各リストに現れるでしょう。

__metaclass__ = type

from types import *

class Class_1: pass
class Class_2: pass
list_1 = [1, 2, 3]
list_2 = ['dog', 'cat', 'bird']
Tuple_1 = ('one', 'two', 'three')
Tuple_2 = (1000, 2000, 3000)
dict_1 = {'one': 1, 'two': 2, 'three': 3}
dict_2 = {'dog': 'collie', 'cat': 'calico', 'bird': 'robin'}
x = 23
y = 29
pie = 3.14159
eee = 2.71828
house = 'single story'
cabin = 'cozy'

isClass = []; isList = []; isTuple = []; isDict = []; isInt = []; isFloat = []; isString = []; other = []

mixedDataTypes = [Class_1, list_1, Tuple_1, dict_1, x, pie, house, Class_2, list_2, Tuple_2, dict_2, y, eee, cabin]

print '\nMIXED_DATA_TYPES total count:', len(mixedDataTypes)

for item in mixedDataTypes:
    try:
        # if isinstance(item, ClassType): # use this for old class types (before 3.0)
        if isinstance(item, type):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isClass.append(mapping_as_str)
            isClass = [i for i in isClass if i != 'item']

        Elif isinstance(item, ListType):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isList.append(mapping_as_str)
            isList = [i for i in isList if i != 'item']

        Elif isinstance(item, TupleType):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isTuple.append(mapping_as_str)
            isTuple = [i for i in isTuple if i != 'item']

        Elif isinstance(item, DictType):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isDict.append(mapping_as_str)
            isDict = [i for i in isDict if i != 'item']

        Elif isinstance(item, IntType):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isInt.append(mapping_as_str)
            isInt = [i for i in isInt if i != 'item']

        Elif isinstance(item, FloatType):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isFloat.append(mapping_as_str)
            isFloat = [i for i in isFloat if i != 'item']

        Elif isinstance(item, StringType):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isString.append(mapping_as_str)
            isString = [i for i in isString if i != 'item']

        else:
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    other.append(mapping_as_str)
            other = [i for i in other if i != 'item']

    except (TypeError, AttributeError), e:
        print e

print '\n isClass:', len(isClass), isClass
print '  isList:', len(isList), isList
print ' isTuple:', len(isTuple), isTuple
print '  isDict:', len(isDict), isDict
print '   isInt:', len(isInt), isInt
print ' isFloat:', len(isFloat), isFloat
print 'isString:', len(isString), isString
print '   other:', len(other), other

# my output and the output I wanted
'''
MIXED_DATA_TYPES total count: 14

 isClass: 2 ['Class_1', 'Class_2']
  isList: 2 ['list_1', 'list_2']
 isTuple: 2 ['Tuple_1', 'Tuple_2']
  isDict: 2 ['dict_1', 'dict_2']
   isInt: 2 ['x', 'y']
 isFloat: 2 ['pie', 'eee']
isString: 2 ['house', 'cabin']
   other: 0 []
'''
1
Michael Swartz

たぶん私はこれをひっくり返していますが..

str_l = next((k for k,v in locals().items() if id(l) == id(v)))


>>> bar = True
>>> foo = False
>>> my_dict=dict(bar=bar, foo=foo)
>>> next((k for k,v in locals().items() if id(bar) == id(v)))
'bar'
>>> next((k for k,v in locals().items() if id(foo) == id(v)))
'foo'
>>> next((k for k,v in locals().items() if id(my_dict) == id(v)))
'my_dict'
1
rh0dium

あなたはeasydictを使うことができます

>>> from easydict import EasyDict as edict
>>> d = edict({'foo':3, 'bar':{'x':1, 'y':2}})
>>> d.foo
3
>>> d.bar.x
1
>>> d = edict(foo=3)
>>> d.foo
3

もう一つの例:

>>> d = EasyDict(log=False)
>>> d.debug = True
>>> d.items()
[('debug', True), ('log', False)]
1
Eli

これはおそらくひどい考えですが、rlotunの答えと同じ方向にありますが、正しい結果が返されることが多くなります。

import inspect
def getVarName(getvar):
  frame = inspect.currentframe()
  callerLocals = frame.f_back.f_locals
  for k, v in list(callerLocals.items()):
    if v is getvar():
      callerLocals.pop(k)
      try:
        getvar()
        callerLocals[k] = v
      except NameError:
        callerLocals[k] = v
        del frame
        return k
  del frame

あなたはそれを次のように呼びます。

bar = True
foo = False
bean = False
fooName = getVarName(lambda: foo)
print(fooName) # prints "foo"
0
Phylliida

リストを取得してから戻る

def get_var_name(**kwargs):
    """get variable name
        get_var_name(var = var)
    Returns:
        [str] -- var name
    """
    return list(kwargs.keys())[0]
0
paulg