创建单独变量字典的更简单方法?

2024-12-17 08:30:00
admin
原创
127
摘要:问题描述:我希望能够以字符串形式获取变量的名称,但我不知道 Python 是否具有那么多的自省功能。类似于:>>> print(my_var.__name__) 'my_var' 我想这样做是因为我有一堆变量想转换成字典,例如:bar = True foo = False >>&...

问题描述:

我希望能够以字符串形式获取变量的名称,但我不知道 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(),所以我想有一种方法。


解决方案 1:

正如 unwind 所说,这实际上并不是您在 Python 中所做的事情 - 变量实际上是到对象的名称映射。

但是,这里有一种方法可以尝试:

 >>> 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'

解决方案 2:

我一直想这么做。这个 hack 与 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]

解决方案 3:

你想这么做吗?

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}

解决方案 4:

这是一种 hack。它不适用于所有 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)

(在两行上调用 make_dict)将不起作用。

不要尝试从值 foo生成字典bar,而是用字符串变量名 'foo'和生成字典,这样更符合 Python 风格'bar'

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

解决方案 5:

这在 Python 中是不可能的,因为 Python 实际上没有“变量”。Python 有名称,并且同一个对象可以有多个名称。

解决方案 6:

我认为我的问题将有助于说明为什么这个问题很有用,并且可能对如何回答它提供更多见解。我编写了一个小函数来快速内联检查代码中的各种变量。基本上,它列出了变量名称、数据类型、大小和其他属性,这样我就可以快速发现我犯的任何错误。代码很简单:

def details(val):
  vn = val.__name__                 #  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'>

我不确定我是否把这个放在了正确的地方,但我认为它可能会有帮助。我希望如此。

解决方案 7:

我根据这个问题的答案编写了一个简洁实用的小函数。我把它放在这里以防它有用。

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:

我发现,如果您已经有了特定的值列表,那么 @S. Lotts 描述的方法是最好的;但是,下面描述的方法可以很好地在整个代码中添加所有变量和类,无需提供变量名,尽管您可以根据需要指定它们。可以扩展代码以排除类。

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 __name__ == '__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}

解决方案 9:

在 Python 3 中这很容易

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

这将打印:

我的变量 5

解决方案 10:

Python3。使用检查来捕获调用本地命名空间,然后使用此处介绍的想法。正如所指出的那样,可以返回多个答案。

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

解决方案 11:

这是我创建的用于读取变量名称的函数。它更通用,可用于不同的应用程序:

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}

解决方案 12:

在阅读该帖子时,我看到了很多摩擦。很容易给出错误的答案,然后让别人给出正确的答案。无论如何,以下是我发现的。

来自:[effbot.org](http://effbot.org/zone/python-objects.htm#names

名称有点不同 - 它们实际上不是对象的属性,并且对象本身也不知道它叫什么。

*一个对象可以有任意数量的名称,或者根本没有名称。

名称存在于命名空间中(例如模块命名空间、实例命名空间、函数的本地命名空间)。*
注意:它说对象本身不知道它叫什么,所以这就是线索。Python 对象不是自引用的。然后它说,名称存在于命名空间中。我们在 TCL/TK 中有这个。所以也许我的回答会有所帮助(但它确实帮助了我)


    jj = 123
    打印 eval(“'” + str(id(jj)) + “'”)
    打印目录()

166707048
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'jj']

因此列表末尾有“jj”。

将代码重写为:


    jj = 123
    打印 eval(“'” + str(id(jj)) + “'”)
    对于 dir() 中的 x:
        打印 id(eval(x))

161922920
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'jj']
3077447796
136515736
3077408320
3077656800
136515736
161922920

这段令人讨厌的代码是变量/对象/随便你怎么称呼它的名称。

就是这样。当我们直接查找“jj”时,它的内存地址与在全局名称空间中进行字典查找时相同。我相信您可以创建一个函数来执行此操作。只需记住您的变量/对象/wypci 位于哪个名称空间中。

已证明。

解决方案 13:

我编写了sorcery包来强大地实现这种魔法。你可以这样写:

from sorcery import dict_of

my_dict = dict_of(foo, bar)

解决方案 14:

我可能想太多了但是......

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'

解决方案 15:

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)

解决方案 16:

我已将解决方案上传至pypi。它是一个定义与 C#nameof函数等效的模块。

它遍历调用它的框架的字节码指令,获取传递给它的变量/属性的名称。这些名称位于函数名称后面的指令.argrepr中。LOAD

解决方案 17:

大多数对象没有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)

解决方案 18:

好吧,几天前我遇到了同样的需求,必须获取指向对象*本身的变量名称*。

为什么这如此必要?

简而言之,我正在为Maya构建一个插件。核心插件是使用 C++ 构建的,但 GUI 是通过 Python 绘制的(因为它不占用大量处理器)。由于我目前还不知道如何return从插件中获取除默认值之外的多个值MStatus,因此要更新 Python 中的字典,我必须将指向实现 GUI 并包含字典本身的对象变量的名称传递给插件,然后使用从 MayaMGlobal::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许多键可能指向同一个对象,例如:

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

并且该方法不是线程安全的。如果我错了,请纠正我。

至少这种方法解决了我的问题,通过获取全局范围内指向对象本身的任何变量的名称,并将其作为参数传递给插件,以供其内部使用。

我尝试过int(原始整数类),但问题是这些原始类不会被绕过(如果使用的技术术语有误,请更正)。您可以重新实现int,然后执行int = foo,但a = 3永远不会成为foo原始类的对象。要克服这个问题,您必须a = foo(3)开始a.name()工作。

解决方案 19:

在 python 2.7 及更新版本中,还提供了字典推导,这样可以缩短代码。如果可能的话,我会使用 getattr 而不是 eval(eval 是邪恶的),就像在顶部答案中一样。Self 可以是任何具有您正在查看的上下文的对象。它可以是一个对象或 locals=locals() 等。

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

解决方案 20:

我正在研究一个类似的问题。@S.Lott 说:“如果你有变量列表,‘发现’它们的名字有什么意义?”我的答案只是看看是否可以做到,以及是否出于某种原因你想将变量按类型排序到列表中。所以无论如何,在我的研究中,我偶然发现了这个线程,我的解决方案有点扩展,并且基于@rlotun 解决方案。还有一件事,@unutbu 说:“这个想法有价值,但请注意,如果两个变量名引用相同的值(例如 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 '
MIXED_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 '
 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 []
'''

解决方案 21:

你可以使用 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)]

解决方案 22:

在 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]

它在代码的任何地方都很有用。遍历反转堆栈寻找第一个匹配项。

解决方案 23:

虽然这可能是一个糟糕的想法,但它与 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"

解决方案 24:

应该获取列表然后返回

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

解决方案 25:

它不会返回变量的名称,但您可以轻松地从全局变量创建字典。

class CustomDict(dict):
    def __add__(self, other):
        return CustomDict({**self, **other})

class GlobalBase(type):
    def __getattr__(cls, key):
        return CustomDict({key: globals()[key]})

    def __getitem__(cls, keys):
        return CustomDict({key: globals()[key] for key in keys})

class G(metaclass=GlobalBase):
    pass

x, y, z = 0, 1, 2

print('method 1:', G['x', 'y', 'z']) # Outcome: method 1: {'x': 0, 'y': 1, 'z': 2}
print('method 2:', G.x + G.y + G.z) # Outcome: method 2: {'x': 0, 'y': 1, 'z': 2}

解决方案 26:

有了python-varname它你就能轻松做到:

pip install python-varname

from varname import Wrapper

foo = Wrapper(True)
bar = Wrapper(False)

your_dict = {val.name: val.value for val in (foo, bar)}

print(your_dict)

# {'foo': True, 'bar': False}

免责声明:我是该 python-varname 库的作者。

解决方案 27:

>>> a = 1
>>> b = 1
>>> id(a)
34120408
>>> id(b)
34120408
>>> a is b
True
>>> id(a) == id(b)
True

这样就可以获得可能是“a”或“b”的变量名称。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用