函数来打印传递变量的名称

时间:2015-07-11 14:44:39

标签: python

我最初的目标是创建一个函数,它将打印给定对象的类型和内存地址。为了尽可能地普及,我还想包含变量名,如下所示:

>>> a=10
>>> print type_addr(a)
a: int, 0x13b8080

为此,我需要知道传递给该函数的变量的名称。这个page建议使用以下代码(它有点修改后的版本,但想法保持不变,迭代locals().iteritems()。我知道它不安全,并且在给定链接上提到了几个陷阱,但我的计划是改进它):

#!/usr/bin/python

a = b = c = 10
b = 11

for k, v in list(locals().iteritems()):
  if v is b:
  # if id(v) == id(b):
    print "k: %s" % k
    print "v: %s" % v
    print "a: %s" % hex(id(k))

上述代码的输出是:

k: b
v: 11
a: 0x7fece0f305f8

我的下一个目标是制作能给我想要结果的子程序,所以我试着把它包装成子程序:

#!/usr/bin/python

a = b = c = 10
b = 11

def addr_type(obj):
  for k, v in list(locals().iteritems()):
    # if id(v) == id(a):
    if v is obj:
      print "k: %s" % k
      print "v: %s" % v
      print "a: %s" % hex(id(k))

for k, v in list(locals().iteritems()):
  if v is b:
  # if id(v) == id(b):
    print "k: %s" % k
    print "v: %s" % v
    print "a: %s" % hex(id(k))

print "#################"

addr_type(b)

上述代码的输出为:

k: b
v: 11
a: 0x7fc9253715f8
#################
k: obj
v: 11
a: 0x7fc9253198a0

如您所见,变量名称和地址都不相同。然后我开始深入挖掘并尝试跟随:

#!/usr/bin/python
a = b = c = 10
b = 11

for k, v in list(locals().iteritems()):
   print "k: %s" % k
   print "v: %s" % v
   print "a: %s" % hex(id(k))
   print "##############"


if a is b:
    print "a and b is the same objects"
else:
    print "a and b is NOT the same objects"


if a is c:
    print "a and c is the same objects"
else:
    print "a and c is NOT the same objects"


if b is c:
    print "b and c is the same objects"
else:
    print "b and c is NOT the same objects"

返回了:

k: a
v: 10
a: 0x7ff07d54b5d0
##############
k: c
v: 10
a: 0x7ff07d54bbe8
##############
k: b
v: 11
a: 0x7ff07d54b5f8
##############
<Some loaded modules here but nothing interesting>
##############
a and b is NOT the same objects
a and c is the same objects
b and c is NOT the same objects

问题:

  1. 如何重写工作代码并制作将打印传递变量名称的函数?
  2. 为什么相同的对象有不同的地址?

2 个答案:

答案 0 :(得分:2)

<强> TL; DR:由于名称绑定在Python中的工作原理,通常不能获取传递给函数的变量的名称。某些Python对象 do 具有name属性,但这与绑定到赋值语句中的对象的名称不同。

当您打印id时,您的代码会给您带来误导性信息。您实际上并未打印id个对象,而是在id locals()中打印名称字符串的dict

此外,当你在函数中得到locals()时,它会显示函数本地的东西。因此,要获取有关函数外部的本地对象的信息,您需要为函数访问您感兴趣的实际locals() dict。

以下是代码的修改版本,用于修复id内容,并将locals()数据的副本传递给addr_type函数。

请注意,当您调用ac的函数时,它会打印两个名称的信息。

我还添加了几行,显示了如何使用其__name__属性打印函数名称。请注意,当我们打印new_name.__name__时,它只会打印addr_type,因为这是函数的__name__属性的值,我们也将它绑定到new_name这一事实无关紧要

#!/usr/bin/env python

def addr_type(context, obj):
    for k, v in context:
        # if id(v) == id(a):
        if v is obj:
            print "k: %s" % k
            print "v: %s" % v
            print "a: %s" % hex(id(v))
            print
    print 15 * "-"


a = b = c = 10
b = 11

for k, v in list(locals().iteritems()):
    if k.startswith('__'):
        continue
    print "k: %s" % k
    print "v: %s" % v
    print "a: %s" % hex(id(v))
    print "##############"

print

if a is b:
    print "a and b is the same objects"
else:
    print "a and b is NOT the same objects"


if a is c:
    print "a and c is the same objects"
else:
    print "a and c is NOT the same objects"


if b is c:
    print "b and c is the same objects"
else:
    print "b and c is NOT the same objects"

print

context = list(locals().iteritems())
addr_type(context, a)
addr_type(context, b)
addr_type(context, c)

new_name = addr_type
print 'Function names =', addr_type.__name__, new_name.__name__

<强>输出

k: a
v: 10
a: 0x8dafd24
##############
k: c
v: 10
a: 0x8dafd24
##############
k: b
v: 11
a: 0x8dafd18
##############
k: addr_type
v: <function addr_type at 0xb748e17c>
a: 0xb748e17cL
##############

a and b is NOT the same objects
a and c is the same objects
b and c is NOT the same objects

k: a
v: 10
a: 0x8dafd24

k: c
v: 10
a: 0x8dafd24

---------------
k: b
v: 11
a: 0x8dafd18

---------------
k: a
v: 10
a: 0x8dafd24

k: c
v: 10
a: 0x8dafd24

---------------
Function names = addr_type addr_type

你可能会发现研究由Stack Overflow资深人士Ned Batchelder撰写的优秀文章Facts and myths about Python names and values会很有帮助。

更新

这是一个简单的函数show,它打印您传递的名称,以及您传递它的字典中该名称的值。通过传递locals()字典,它允许它在本地范围内按名称查找对象。在函数内部,这是函数的局部变量。在函数外部,这是所有全局变量。

def show(*args, names):
    for s in args:
        print(s, names.get(s, 'Not found!'))

def test(t):
    a = 1
    b = 2
    c = 3
    show('a', 'b', 'c', 't', names=locals())

test(42)

<强>输出

a 1
b 2
c 3
t 42

答案 1 :(得分:1)

我从问题的第二部分开始。问题在于,您正在打印hex(id(k))。您应该改为打印hex(id(v))

locals()

中搜索名称不是一个好主意
  

更新并返回表示当前本地符号表的字典。

如果在函数内部调用locals(),则只能获取此范围中定义的变量。这就是打印的原因

k: obj
v: 11
a: 0x7fc9253198a0

您必须将locals()字典传递给type_addr()才能获得变量来源范围的一些信息。

a = 7
type_addr(a, locals())

另一方面,如果您有多个具有相同值的变量,您很可能会得到错误的名称(如果您不打印所有这些名称)。

所以关注The Zen of Python

  

明确比隐含更好。

我建议将名称传递给显式打印。

def type_addr(obj, msg):
    print '%s: %s %s' % (msg, type(obj).__name__, hex(id(obj)))

a = 11
type_addr(a, 'a')
相关问题