我最初的目标是创建一个函数,它将打印给定对象的类型和内存地址。为了尽可能地普及,我还想包含变量名,如下所示:
>>> 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
问题:
答案 0 :(得分:2)
<强> TL; DR:由于名称绑定在Python中的工作原理,通常不能获取传递给函数的变量的名称。某些Python对象 do 具有name属性,但这与绑定到赋值语句中的对象的名称不同。
当您打印id
时,您的代码会给您带来误导性信息。您实际上并未打印id
个对象,而是在id
locals()
中打印名称字符串的dict
。
此外,当你在函数中得到locals()
时,它会显示函数本地的东西。因此,要获取有关函数外部的本地对象的信息,您需要为函数访问您感兴趣的实际locals()
dict。
以下是代码的修改版本,用于修复id
内容,并将locals()
数据的副本传递给addr_type
函数。
请注意,当您调用a
或c
的函数时,它会打印两个名称的信息。
我还添加了几行,显示了如何使用其__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()
,则只能获取此范围中定义的变量。这就是打印的原因
k: obj
v: 11
a: 0x7fc9253198a0
您必须将locals()
字典传递给type_addr()
才能获得变量来源范围的一些信息。
a = 7
type_addr(a, locals())
另一方面,如果您有多个具有相同值的变量,您很可能会得到错误的名称(如果您不打印所有这些名称)。
明确比隐含更好。
我建议将名称传递给显式打印。
def type_addr(obj, msg):
print '%s: %s %s' % (msg, type(obj).__name__, hex(id(obj)))
a = 11
type_addr(a, 'a')