我希望能够以字符串的形式获取变量的名称,但是我不知道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}


但是我想要比这更自动的东西。 >

评论

由于人们似乎对要求的内容感到困惑,因此在此将其重述,因为这是一个有趣的问题。给定一个数组[foo,bar,baz],您想要一个像{'foo':foo,'bar':bar,'baz':baz}这样的字典,而您不知道数组中有什么变量。所以发问者问您如何在python中获取变量的名称作为字符串。现在希望人们可以浏览这些可怕的答案,找到一些您可以了解为什么这在python中并不是一个好主意的地方。

可能重复:stackoverflow.com/questions/544919/…

该技术的一种用途是简化字符串格式化调用:'{var} {foo} {bar}'。format(** named(var,foo,bar)),其中“ named”是返回dict( 'var':var),如下所述。

我认为这实际上是一个不好的问题,因为名称已映射到对象,您可以有多个名称指向同一对象,而且我从未见过需要实现反转该映射的目标。因此,此处接受错误答案的事实是没有意义的-如果Google搜索将您带到这里,您显然是在问一个错误的问题。

这是调试的好主意!

#1 楼

您是否要这样做?

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}


评论


rlotun更接近它的初始“精神”,因为它可以发现名字。我会用你们两个人的。或者也许只是用我该死的手打字。有些事情只是没有被自动化。

– e-satis
10 Mar 31 '10在14:08

@ e-satis:要使@rlotun正常工作,您必须提供变量列表。如果您有变量列表,那么“发现”它们的名称有什么意义?

– S.Lott
2010-3-31 14:11

为什么选择eval而不是显式使用locals和globals?

–罗杰·佩特
10 Mar 31 '10在14:14

@Roger Pate:因为我不知道整个练习的重点是什么。

– S.Lott
2010年3月31日下午14:19

该答案不能回答所提出的问题。如果您有变量列表,那么“发现”它们的名称有什么意义?为了避免重复,以至于代替print('x:'+ x)可以编写magic_print(x)并具有相同的输出,而无需两次写入变量名称。

–彼得·多布罗格斯特(Piotr Dobrogost)
13年5月1日在10:46



#2 楼

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


评论


这种想法有其优点,但是请注意,如果两个变量名引用相同的值(例如True),则可能会返回意外的变量名。

–unutbu
10 Mar 31 '10在13:57

为什么id(v)== id(a)而不是v是a?对于绑定到多个变量(例如int,字符串和任何类似实现的用户定义类型)的对象,此操作将失败。

–罗杰·佩特
2010年3月31日14:02



是的,v是一个更好的选择。是的,考虑到可能出现的所有潜在陷阱,肯定是危险的! ;-)

–rlotun
2010年3月31日下午14:15

@ e-satis我很惊讶您没有将此答案标记为答案,因为我同意您的意见,即rlotun更接近其最初的“精神”,因为它可以发现名称。此外,S.Lott的回答根本不会回答您的问题...

–彼得·多布罗格斯特(Piotr Dobrogost)
13年5月1日在10:45



“过度杀伤和危险” ...并且使用eval是不是?

–bug
2014年1月16日19:27

#3 楼

我已经很想这样做了。此hack非常类似于rlotun的建议,但它是单行代码,对我来说很重要:
blah = 1
blah_name = [ k for k,v in locals().iteritems() if v is blah][0]


评论


@keflavich我非常喜欢这种方法,并且现在不时使用它。但是我不能让它在函数内部工作。我猜有很多“更好”的方法可以做到,但是没有一个像nbubis所说的那样简单。您已经能够在keflavich函数中使用它吗?我在这里问这个问题。

–狮子座
2013年9月9日19:31



请注意,在Python 3中,iteritems()替换为items()

–乔纳森·惠勒(Jonathan Wheeler)
16 Dec 25 '18:16

这是不可靠的:垃圾邮件= 1;等等= 1; blah_name = [如果v为blah,则在locals()。items()中为k,v表示k] [0]; print(blah_name)输出垃圾邮件

– andreasdr
18年1月29日在14:01



@andreasdr是因为垃圾邮件= 1,等等= 1;断言是垃圾邮件。比较原始数据类型时,解决方案中断了。

– JYun
'18 Feb 1在9:00



#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}


请注意,此hack很脆弱:

make_dict(bar,
          foo)


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

而不是尝试从值foobar生成dict,
从字符串变量名称'foo''bar'生成dict会更加Pythonic:

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


评论


+1为智能骇客。当然,回溯速度非常慢,因此使用它可能会比较缓慢。

– e-satis
10 Mar 31 '10在14:03

+1111111 !!!!是的,它的速度很慢,但是在替换谁需要的print(“ a_very_long_name:{}'。format(a_very_long_name))的时候!

–frnhr
2014年12月5日,下午1:46

#5 楼

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

评论


是的,我知道,我把这个问题简化了,但是我期待更多类似“ get_var_tags(var)[0]”的东西。

– e-satis
2010-3-31在13:49

#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)))


我不确定是否将其放在正确的位置,但我认为这可能会有所帮助。希望能做到。

评论


因此,通过头检查,是否可以说明变量/名称可以在代码中的不同时间指向不同事物的事实?例如,在代码执行中,myconnection可能指向一个布尔值,另一个指向整数,而套接字连接则指向代码执行?

–user4805123
17年5月28日在16:43



#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])


这将打印:

评论


这类似于rlotun的方法,但有点简单

–ficialhopsof
2014年4月4日20:47

-1。打开一个新的解释器窗口,然后在locals()中尝试输入v。

–Air
2014年5月1日20:44



我不确定您的意思吗?

–ficialhopsof
15年10月14日在19:28

这将产生错误:RuntimeError:词典在迭代过程中更改了大小...

– Nizar B.
16/09/1在20:35



但是您可以在list(locals())中为v做:

–菲利达
17/12/21在22:10



#10 楼

Python3。使用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


评论


好的答案,但对我来说最好用... ... id(eval(name,None,frame.f_back.f_locals))== ...

–伊曼纽尔·杜马斯(Emmanuel DUMAS)
2015年9月2日于10:04

#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 楼

在阅读线程时,我看到了很多摩擦。给出一个错误的答案很容易,然后让某人给出正确的答案。无论如何,这就是我发现的东西。
名称有些不同-它们实际上不是对象的属性,并且对象本身也不知道其叫什么。

对象可以具有任意数量的名称,或根本没有名称。

名称存在于命名空间中(例如模块命名空间,实例命名空间,函数的本地命名空间)。



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

>因此列表的末尾有'jj'。


将代码重写为:



    jj = 123
    print eval("'" + str(id(jj)) + "'")
    print dir()




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


这讨厌的代码ID是变量/对象/ what-you-pedantics-call-it的名称。

是。当我们直接查找'jj'的内存地址时,就像在全局名称空间中查找字典时一样。我确定您可以创建一个函数来执行此操作。只要记住您的变量/对象/ wypci位于哪个名称空间即可。

QED。

评论


您在这里有两个eval的疯狂用途。第一个与:print id(jj)完全相同。第二个只是查找名称,并且可以使用vars()更轻松地完成。

– Ned Batchelder
13年2月19日,在1:22

#13 楼

也许我想得太多,但是..

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'


评论


大!这就是我想要的。谢谢@ rh0dium ... \ n变量= 1 \ n [k为k,v在locals()。items()中,如果id(variable)== id(v)] \ n Out [14]:['variable' ]

–马伊迪
18年9月9日14:55



#14 楼

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)


#15 楼

我将解决方案上传到pypi。它是一个模块,定义了C#的nameof函数的等效项。

它通过字节码指令对其所调用的帧进行迭代,以获取传递给它的变量/属性的名称。名称可以在函数名称后面的.argrepr指令的LOAD中找到。

#16 楼

我编写了包裹法术来稳健地执行这种魔术。您可以编写:

from sorcery import dict_of

my_dict = dict_of(foo, bar)


#17 楼

大多数对象没有__name__属性。 (类,函数和模块都可以;还有更多内置类型有吗?)您可以简单地直接使用字符串吗?

您可以“切片”一个字典:

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,但我知道这个名字不存在,为什么每个人都乱扔这种“类似”的东西?您的解决方案无法解决问题,因为我不想混淆名称,因此我会执行我已经在问题中给出的dict解决方案。

– e-satis
2010年3月31日13:51



@ e-satis:如果仅在locals()中使用所有内容即可解决您的问题,那么我不知道您在问什么。我猜您可以调用some_func(var)没问题,所以我试图指出与some_func(“ var”)并不太远,dictslice允许您一次获取多个变量的名称-值映射。

–罗杰·佩特
2010年3月31日14:07



#18 楼

好吧,几天前我遇到了同样的需要,并且不得不获得一个指向对象本身的变量名称。

为什么如此必要?

简而言之,我正在为Maya构建一个插件。核心插件是使用C ++构建的,但GUI是通过Python绘制的(因为它不占用大量处理器)。由于我到目前为止还不知道如何从插件中除默认return之外的多个值MStatus,因此要在Python中更新字典,我必须传递变量名,指向实现GUI的对象并将包含字典本身的字典添加到插件,然后使用MGlobal::executePythonCommand()从Maya的全局范围更新字典。

要做的事情是这样的:

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是邪恶的),就像在最高答案中一样。自我可以是具有您所要查看的上下文的任何对象。它可以是一个对象,也可以是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']。没有它,“项目”将显示在每个列表中。

__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 []
'''


评论


我要解决的问题是名称不是对象的属性。单个对象可能具有多个名称,或者根本没有名称。例如,您在代码中添加了pi = pie,您将在isFloat列表中获得一个额外的条目。如果将tuple_1 [0]添加到blendDataTypes列表中,则尽管在代码中两次输入“ 1”,也不会找到名称(尽管由于字符串插入,它们都将引用同一对象)。

– Blckknght
2013年9月1日14:02在

@Blckknght ---我同意。这只是做某事的本来不应该做的另一种方式。我并不是说它可以带来独特的结果,也不是绝对可靠的。通过这样做,我发现使用pi和e作为变量会导致不必要的输出,这是因为两者都是数学库的一部分。对我来说,这只是一个练习,看看即使最终结果不是完美的,也可以做到。在我对这种语言的学习中,只有一本书能走得通。在我看来,如果您真的想学习该语言,那么您就必须玩“如果...那么想”,然后看看您的想法。

– Michael Swartz
2013年9月2日,1:17

#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


#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'的变量名。