通常无法做到这一点,尽管这可以通过使用内省和用于调试程序的工具来实现。代码必须从“.py”文件运行,而不是从编译的字节码或压缩模块内部运行 - 因为它依赖于文件源代码的读取,从应该找到“它在哪里”的方法中运行”。
诀窍是访问初始化对象的执行框架——使用inspect.currentframe——框架对象有一个“f_lineno”值,它表示调用对象方法的行号(在这种情况下,@ 987654321@) 已被调用。函数inspect.filename 允许检索文件的源代码,并获取适当的行号。
一个简单的解析然后查看“=”符号之前的部分,并假设它是包含对象的变量。
from inspect import currentframe, getfile
class A(object):
def __init__(self):
f = currentframe(1)
filename = getfile(f)
code_line = open(filename).readlines()[f.f_lineno - 1]
assigned_variable = code_line.split("=")[0].strip()
print assigned_variable
my_name = A()
other_name = A()
这不适用于多个分配,在进行分配之前与对象组成的表达式,将对象附加到列表或添加到字典或集合,for 循环初始化中的对象实例化,天知道还有哪些情况——
请记住,在第一个属性之后,该对象也可以被任何其他变量引用。
底线:它是可能的,但作为一个玩具 - 它不能在生产代码中使用 -
只需在对象初始化期间将变量名称作为字符串传递,就像在创建 collections.namedtuple 时所做的那样@
如果您需要名称,“正确的方法”是将名称作为字符串参数显式传递给对象初始化,例如:
class A(object):
def __init__(self, name):
self.name = name
x = A("x")
而且,如果绝对需要只键入一次对象的名称,还有另一种方法 - 继续阅读。
由于 Python 的语法,一些不使用“=”运算符的特殊赋值允许对象知道它被分配了名称。因此,在 Python 中执行赋值的其他 statemtns 是 for、with、def 和 class 关键字 - 可能会滥用这一点,因为具体而言,类创建和函数定义是创建“知道”其名称的对象的赋值语句。
让我们关注def 语句。它通常创建一个函数。但是使用装饰器,您可以使用“def”来创建任何类型的对象 - 并将名称用于构造函数可用的函数:
class MyObject(object):
def __new__(cls, func):
# Calls the superclass constructor and actually instantiates the object:
self = object.__new__(cls)
#retrieve the function name:
self.name = func.func_name
#returns an instance of this class, instead of a decorated function:
return self
def __init__(self, func):
print "My name is ", self.name
#and the catch is that you can't use "=" to create this object, you have to do:
@MyObject
def my_name(): pass
(这最后一种方法可以在生产代码中使用,不像求助于读取源文件的方法)