在类__init __()中获取实例名称

时间:2021-01-12 18:21:36

While building a new class object in python, I want to be able to create a default value based on the instance name of the class without passing in an extra argument. How can I accomplish this? Here's the basic pseudo-code I'm trying for:

在python中构建一个新的类对象时,我希望能够根据类的实例名创建一个默认值,而不需要传递额外的参数。我怎么能做到这一点?这是我正在尝试的基本伪代码:

class SomeObject():
    defined_name = u""

    def __init__(self, def_name=None):
        if def_name == None:
            def_name = u"%s" % (<INSTANCE NAME>)
        self.defined_name = def_name

ThisObject = SomeObject()
print ThisObject.defined_name   # Should print "ThisObject"

10 个解决方案

#1


20  

Instances don't have names. By the time the global name ThisObject gets bound to the instance created by evaluating the SomeObject constructor, the constructor has finished running.

实例没有名称。当全局名称ThisObject绑定到通过评估SomeObject构造函数创建的实例时,构造函数已完成运行。

If you want an object to have a name, just pass the name along in the constructor.

如果希望对象具有名称,只需在构造函数中传递名称即可。

def __init__(self, name):
    self.name = name

#2


20  

Well, there is almost a way to do it:

好吧,几乎有办法做到这一点:

#!/usr/bin/env python
import traceback
class SomeObject():
    def __init__(self, def_name=None):
        if def_name == None:
            (filename,line_number,function_name,text)=traceback.extract_stack()[-2]
            def_name = text[:text.find('=')].strip()
        self.defined_name = def_name

ThisObject = SomeObject()
print ThisObject.defined_name 
# ThisObject

The traceback module allows you to peek at the code used to call SomeObject(). With a little string wrangling, text[:text.find('=')].strip() you can guess what the def_name should be.

回溯模块允许您查看用于调用SomeObject()的代码。通过一个小字符串争论,text [:text.find('=')]。strip()你可以猜出def_name应该是什么。

However, this hack is brittle. For example, this doesn't work so well:

但是,这个黑客很脆弱。例如,这不能很好地工作:

ThisObject,ThatObject = SomeObject(),SomeObject()
print ThisObject.defined_name
# ThisObject,ThatObject
print ThatObject.defined_name 
# ThisObject,ThatObject

So if you were to use this hack, you have to bear in mind that you must call SomeObject() using simple python statement:

因此,如果你要使用这个hack,你必须记住你必须使用简单的python语句调用SomeObject():

ThisObject = SomeObject()

By the way, as a further example of using traceback, if you define

顺便说一句,作为使用追溯的另一个例子,如果你定义

def pv(var):
    # stack is a list of 4-tuples: (filename, line number, function name, text)
    # see http://docs.python.org/library/traceback.html#module-traceback
    #
    (filename,line_number,function_name,text)=traceback.extract_stack()[-2]
    # ('x_traceback.py', 18, 'f', 'print_var(y)')
    print('%s: %s'%(text[text.find('(')+1:-1],var))

then you can call

然后你可以打电话

x=3.14
pv(x)
# x: 3.14

to print both the variable name and its value.

打印变量名称及其值。

#3


6  

You can create a method inside your class that check all variables in the current frame and use hash() to look for the self variable.

您可以在类中创建一个方法,检查当前帧中的所有变量,并使用hash()查找自变量。

The solution proposed here will return all the variables pointing to the instance object.

这里提出的解决方案将返回指向实例对象的所有变量。

In the class below, isinstance() is used to avoid problems when applying hash(), since some objects like a numpy.array or a list, for example, are unhashable.

在下面的类中,isinstance()用于避免在应用hash()时出现问题,因为某些对象(例如numpy.array或list)是不可删除的。

import inspect
class A(object):
    def get_my_name(self):
        ans = []
        frame = inspect.currentframe().f_back
        tmp = dict(frame.f_globals.items() + frame.f_locals.items())
        for k, var in tmp.items():
            if isinstance(var, self.__class__):
                if hash(self) == hash(var):
                    ans.append(k)
        return ans

The following test has been done:

已完成以下测试:

def test():
    a = A()
    b = a
    c = b
    print c.get_my_name()

The result is:

结果是:

test()
#['a', 'c', 'b']

#4


3  

This cannot work, just imagine this: a = b = TheMagicObjet(). Names have no effect on Values, they just point to them.

这不可行,想象一下:a = b = TheMagicObjet()。名称对值没有影响,只是指向它们。

#5


2  

One horrible, horrible way to accomplish this is to reverse the responsibilities:

实现这一目标的一种可怕而可怕的方法是扭转责任:

class SomeObject():
    def __init__(self, def_name):
        self.defined_name = def_name
        globals()[def_name] = self

SomeObject("ThisObject")
print ThisObject.defined_name

If you wanted to support something other than global scope, you'd have to do something even more awful.

如果你想支持全局范围以外的东西,你必须做一些更糟糕的事情。

#6


2  

In Python, all data is stored in objects. Additionally, a name can be bound with an object, after which that name can be used to look up that object.

在Python中,所有数据都存储在对象中。此外,名称可以与对象绑定,之后该名称可用于查找该对象。

It makes no difference to the object what names, if any, it might be bound to. It might be bound to dozens of different names, or none. Also, Python does not have any "back links" that point from an object to a name.

它对象可以绑定什么名称(如果有的话)没有区别。它可能会绑定几十个不同的名称,或者没有。此外,Python没有任何从对象指向名称的“反向链接”。

Consider this example:

考虑这个例子:

foo = 1
bar = foo
baz = foo

Now, suppose you have the integer object with value 1, and you want to work backwards and find its name. What would you print? Three different names have that object bound to them, and all are equally valid.

现在,假设您有一个值为1的整数对象,并且您想要向后工作并找到它的名称。你会打印什么?三个不同的名称将该对象绑定到它们,并且所有这些都同样有效。

print(bar is foo) # prints True
print(baz is foo) # prints True

In Python, a name is a way to access an object, so there is no way to work with names directly. You could search through various name spaces until you find a name that is bound with the object of interest, but I don't recommend this.

在Python中,名称是访问对象的一种方式,因此无法直接使用名称。您可以搜索各种名称空间,直到找到与感兴趣对象绑定的名称,但我不建议这样做。

How do I get the string representation of a variable in python?

如何在python中获取变量的字符串表示?

There is a famous presentation called "Code Like a Pythonista" that summarizes this situation as "Other languages have 'variables'" and "Python has 'names'"

有一个名为“Code like a Pythonista”的着名演示文稿将这种情况概括为“其他语言有'变量'”和“Python有'名字'”

http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#other-languages-have-variables

http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#other-languages-have-variables

#7


0  

I think that names matters if they are the pointers to any object.. no matters if:

我认为,如果它们是指向任何对象的指针,那么名称很重要......如果:

foo = 1
bar = foo

I know that foo points to 1 and bar points to the same value 1 into the same memory space. but supose that I want to create a class with a function that adds a object to it.

我知道foo指向1并且bar指向相同的值1进入相同的内存空间。但是我希望创建一个带有向其添加对象的函数的类。

Class Bag(object):
   def __init__(self):
       some code here...
   def addItem(self,item):
       self.__dict__[somewaytogetItemName] = item

So, when I instantiate the class bag like below:

所以,当我像下面那样实例化类包:

newObj1 = Bag()
newObj2 = Bag()
newObj1.addItem(newObj2)I can do this to get an attribute of newObj1:
newObj1.newObj2

#8


0  

If you want an unique instance name for a class, try __repr__() or id(self)

如果您想要一个类的唯一实例名称,请尝试__repr __()或id(self)

class Some:
    def __init__(self):
        print(self.__repr__())  # = hex(id(self))
        print(id(self))

It will print the memory address of the instance, which is unique.

它将打印实例的内存地址,这是唯一的。

#9


0  

Inspired by the answers of unutbu and Saullo Castro, I have created a more sophisticated class that can even be subclassed. It solves what was asked for in the question.

受到unutbu和Saullo Castro的答案的启发,我创造了一个更复杂的类,甚至可以进行子类化。它解决了问题中的要求。

"create a default value based on the instance name of the class without passing in an extra argument."

“根据类的实例名称创建一个默认值,而不传入额外的参数。”

Here's what it does, when an instance of this class or a subclass is created:

当创建此类或子类的实例时,它就是这样做的:

  1. Go up in the frame stack until the first frame which does not belong to a method of the current instance.
  2. 向上移动到帧堆栈,直到第一帧不属于当前实例的方法。
  3. Inspect this frame to get the attributes self.creation_(name/file/module/function/line/text).
  4. 检查此框架以获取self.creation_(name / file / module / function / line / text)属性。
  5. Perform an an additional check whether an object with name self.creation_name was actually defined in the frame's locals() namespace to make 100% sure the found creation_name is correct or raise an error otherwise.
  6. 执行另外的检查是否在框架的locals()命名空间中实际定义了名为self.creation_name的对象,以使100%确定找到的creation_name是正确的,否则引发错误。

The Code:

代码:

import traceback, threading, time

class InstanceCreationError(Exception):
    pass

class RememberInstanceCreationInfo:
    def __init__(self):
        for frame, line in traceback.walk_stack(None):
            varnames = frame.f_code.co_varnames
            if varnames is ():
                break
            if frame.f_locals[varnames[0]] not in (self, self.__class__):
                break
                # if the frame is inside a method of this instance,
                # the first argument usually contains either the instance or
                #  its class
                # we want to find the first frame, where this is not the case
        else:
            raise InstanceCreationError("No suitable outer frame found.")
        self._outer_frame = frame
        self.creation_module = frame.f_globals["__name__"]
        self.creation_file, self.creation_line, self.creation_function, \
            self.creation_text = \
            traceback.extract_stack(frame, 1)[0]
        self.creation_name = self.creation_text.split("=")[0].strip()
        super().__init__()
        threading.Thread(target=self._check_existence_after_creation).start()

    def _check_existence_after_creation(self):
        while self._outer_frame.f_lineno == self.creation_line:
            time.sleep(0.01)
        # this is executed as soon as the line number changes
        # now we can be sure the instance was actually created
        error = InstanceCreationError(
                "\nCreation name not found in creation frame.\ncreation_file: "
                "%s \ncreation_line: %s \ncreation_text: %s\ncreation_name ("
                "might be wrong): %s" % (
                    self.creation_file, self.creation_line, self.creation_text,
                    self.creation_name))
        nameparts = self.creation_name.split(".")
        try:
            var = self._outer_frame.f_locals[nameparts[0]]
        except KeyError:
            raise error
        finally:
            del self._outer_frame
        # make sure we have no permament inter frame reference
        # which could hinder garbage collection
        try:
            for name in nameparts[1:]: var = getattr(var, name)
        except AttributeError:
            raise error
        if var is not self: raise error

    def __repr__(self):
        return super().__repr__()[
               :-1] + " with creation_name '%s'>" % self.creation_name

A simple example:

一个简单的例子:

class MySubclass(RememberInstanceCreationInfo):
    def __init__(self):
        super().__init__()

    def print_creation_info(self):
        print(self.creation_name, self.creation_module, self.creation_function,
                self.creation_line, self.creation_text, sep=", ")

instance = MySubclass()
#out: instance, __main__, <module>, 68, instance = MySubclass()

If the creation name cannot be determined properly an error is raised:

如果无法正确确定创建名称,则会引发错误:

variable, another_instance = 2, MySubclass()

# InstanceCreationError: 
# Creation name not found in creation frame.
# creation_file: /.../myfile.py 
# creation_line: 71 
# creation_text: variable, another_instance = 2, MySubclass()
# creation_name (might be wrong): variable, another_instance

#10


-1  

The best way is really to pass the name to the constructor as in the chosen answer. However, if you REALLY want to avoid asking the user to pass the name to the constructor, you can do the following hack:

最好的方法是将名称传递给构造函数,就像在所选答案中一样。但是,如果您真的想避免要求用户将名称传递给构造函数,则可以执行以下操作:

If you are creating the instance with 'ThisObject = SomeObject()' from the command line, you can get the object name from the command string in command history:

如果要从命令行使用“ThisObject = SomeObject()”创建实例,则可以从命令历史记录中的命令字符串中获取对象名称:

import readline
import re

class SomeObject():
    def __init__(self):
        cmd = readline.get_history_item(readline.get_current_history_length())                                                          
        self.name = re.split('=| ',cmd)[0]

If you are creating the instance using 'exec' command, you can handle this with:

如果使用'exec'命令创建实例,则可以使用以下命令处理:

if cmd[0:4] == 'exec': self.name = re.split('\'|=| ',cmd)[1]     # if command performed using 'exec'
else: self.name = re.split('=| ',cmd)[0]

#1


20  

Instances don't have names. By the time the global name ThisObject gets bound to the instance created by evaluating the SomeObject constructor, the constructor has finished running.

实例没有名称。当全局名称ThisObject绑定到通过评估SomeObject构造函数创建的实例时,构造函数已完成运行。

If you want an object to have a name, just pass the name along in the constructor.

如果希望对象具有名称,只需在构造函数中传递名称即可。

def __init__(self, name):
    self.name = name

#2


20  

Well, there is almost a way to do it:

好吧,几乎有办法做到这一点:

#!/usr/bin/env python
import traceback
class SomeObject():
    def __init__(self, def_name=None):
        if def_name == None:
            (filename,line_number,function_name,text)=traceback.extract_stack()[-2]
            def_name = text[:text.find('=')].strip()
        self.defined_name = def_name

ThisObject = SomeObject()
print ThisObject.defined_name 
# ThisObject

The traceback module allows you to peek at the code used to call SomeObject(). With a little string wrangling, text[:text.find('=')].strip() you can guess what the def_name should be.

回溯模块允许您查看用于调用SomeObject()的代码。通过一个小字符串争论,text [:text.find('=')]。strip()你可以猜出def_name应该是什么。

However, this hack is brittle. For example, this doesn't work so well:

但是,这个黑客很脆弱。例如,这不能很好地工作:

ThisObject,ThatObject = SomeObject(),SomeObject()
print ThisObject.defined_name
# ThisObject,ThatObject
print ThatObject.defined_name 
# ThisObject,ThatObject

So if you were to use this hack, you have to bear in mind that you must call SomeObject() using simple python statement:

因此,如果你要使用这个hack,你必须记住你必须使用简单的python语句调用SomeObject():

ThisObject = SomeObject()

By the way, as a further example of using traceback, if you define

顺便说一句,作为使用追溯的另一个例子,如果你定义

def pv(var):
    # stack is a list of 4-tuples: (filename, line number, function name, text)
    # see http://docs.python.org/library/traceback.html#module-traceback
    #
    (filename,line_number,function_name,text)=traceback.extract_stack()[-2]
    # ('x_traceback.py', 18, 'f', 'print_var(y)')
    print('%s: %s'%(text[text.find('(')+1:-1],var))

then you can call

然后你可以打电话

x=3.14
pv(x)
# x: 3.14

to print both the variable name and its value.

打印变量名称及其值。

#3


6  

You can create a method inside your class that check all variables in the current frame and use hash() to look for the self variable.

您可以在类中创建一个方法,检查当前帧中的所有变量,并使用hash()查找自变量。

The solution proposed here will return all the variables pointing to the instance object.

这里提出的解决方案将返回指向实例对象的所有变量。

In the class below, isinstance() is used to avoid problems when applying hash(), since some objects like a numpy.array or a list, for example, are unhashable.

在下面的类中,isinstance()用于避免在应用hash()时出现问题,因为某些对象(例如numpy.array或list)是不可删除的。

import inspect
class A(object):
    def get_my_name(self):
        ans = []
        frame = inspect.currentframe().f_back
        tmp = dict(frame.f_globals.items() + frame.f_locals.items())
        for k, var in tmp.items():
            if isinstance(var, self.__class__):
                if hash(self) == hash(var):
                    ans.append(k)
        return ans

The following test has been done:

已完成以下测试:

def test():
    a = A()
    b = a
    c = b
    print c.get_my_name()

The result is:

结果是:

test()
#['a', 'c', 'b']

#4


3  

This cannot work, just imagine this: a = b = TheMagicObjet(). Names have no effect on Values, they just point to them.

这不可行,想象一下:a = b = TheMagicObjet()。名称对值没有影响,只是指向它们。

#5


2  

One horrible, horrible way to accomplish this is to reverse the responsibilities:

实现这一目标的一种可怕而可怕的方法是扭转责任:

class SomeObject():
    def __init__(self, def_name):
        self.defined_name = def_name
        globals()[def_name] = self

SomeObject("ThisObject")
print ThisObject.defined_name

If you wanted to support something other than global scope, you'd have to do something even more awful.

如果你想支持全局范围以外的东西,你必须做一些更糟糕的事情。

#6


2  

In Python, all data is stored in objects. Additionally, a name can be bound with an object, after which that name can be used to look up that object.

在Python中,所有数据都存储在对象中。此外,名称可以与对象绑定,之后该名称可用于查找该对象。

It makes no difference to the object what names, if any, it might be bound to. It might be bound to dozens of different names, or none. Also, Python does not have any "back links" that point from an object to a name.

它对象可以绑定什么名称(如果有的话)没有区别。它可能会绑定几十个不同的名称,或者没有。此外,Python没有任何从对象指向名称的“反向链接”。

Consider this example:

考虑这个例子:

foo = 1
bar = foo
baz = foo

Now, suppose you have the integer object with value 1, and you want to work backwards and find its name. What would you print? Three different names have that object bound to them, and all are equally valid.

现在,假设您有一个值为1的整数对象,并且您想要向后工作并找到它的名称。你会打印什么?三个不同的名称将该对象绑定到它们,并且所有这些都同样有效。

print(bar is foo) # prints True
print(baz is foo) # prints True

In Python, a name is a way to access an object, so there is no way to work with names directly. You could search through various name spaces until you find a name that is bound with the object of interest, but I don't recommend this.

在Python中,名称是访问对象的一种方式,因此无法直接使用名称。您可以搜索各种名称空间,直到找到与感兴趣对象绑定的名称,但我不建议这样做。

How do I get the string representation of a variable in python?

如何在python中获取变量的字符串表示?

There is a famous presentation called "Code Like a Pythonista" that summarizes this situation as "Other languages have 'variables'" and "Python has 'names'"

有一个名为“Code like a Pythonista”的着名演示文稿将这种情况概括为“其他语言有'变量'”和“Python有'名字'”

http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#other-languages-have-variables

http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#other-languages-have-variables

#7


0  

I think that names matters if they are the pointers to any object.. no matters if:

我认为,如果它们是指向任何对象的指针,那么名称很重要......如果:

foo = 1
bar = foo

I know that foo points to 1 and bar points to the same value 1 into the same memory space. but supose that I want to create a class with a function that adds a object to it.

我知道foo指向1并且bar指向相同的值1进入相同的内存空间。但是我希望创建一个带有向其添加对象的函数的类。

Class Bag(object):
   def __init__(self):
       some code here...
   def addItem(self,item):
       self.__dict__[somewaytogetItemName] = item

So, when I instantiate the class bag like below:

所以,当我像下面那样实例化类包:

newObj1 = Bag()
newObj2 = Bag()
newObj1.addItem(newObj2)I can do this to get an attribute of newObj1:
newObj1.newObj2

#8


0  

If you want an unique instance name for a class, try __repr__() or id(self)

如果您想要一个类的唯一实例名称,请尝试__repr __()或id(self)

class Some:
    def __init__(self):
        print(self.__repr__())  # = hex(id(self))
        print(id(self))

It will print the memory address of the instance, which is unique.

它将打印实例的内存地址,这是唯一的。

#9


0  

Inspired by the answers of unutbu and Saullo Castro, I have created a more sophisticated class that can even be subclassed. It solves what was asked for in the question.

受到unutbu和Saullo Castro的答案的启发,我创造了一个更复杂的类,甚至可以进行子类化。它解决了问题中的要求。

"create a default value based on the instance name of the class without passing in an extra argument."

“根据类的实例名称创建一个默认值,而不传入额外的参数。”

Here's what it does, when an instance of this class or a subclass is created:

当创建此类或子类的实例时,它就是这样做的:

  1. Go up in the frame stack until the first frame which does not belong to a method of the current instance.
  2. 向上移动到帧堆栈,直到第一帧不属于当前实例的方法。
  3. Inspect this frame to get the attributes self.creation_(name/file/module/function/line/text).
  4. 检查此框架以获取self.creation_(name / file / module / function / line / text)属性。
  5. Perform an an additional check whether an object with name self.creation_name was actually defined in the frame's locals() namespace to make 100% sure the found creation_name is correct or raise an error otherwise.
  6. 执行另外的检查是否在框架的locals()命名空间中实际定义了名为self.creation_name的对象,以使100%确定找到的creation_name是正确的,否则引发错误。

The Code:

代码:

import traceback, threading, time

class InstanceCreationError(Exception):
    pass

class RememberInstanceCreationInfo:
    def __init__(self):
        for frame, line in traceback.walk_stack(None):
            varnames = frame.f_code.co_varnames
            if varnames is ():
                break
            if frame.f_locals[varnames[0]] not in (self, self.__class__):
                break
                # if the frame is inside a method of this instance,
                # the first argument usually contains either the instance or
                #  its class
                # we want to find the first frame, where this is not the case
        else:
            raise InstanceCreationError("No suitable outer frame found.")
        self._outer_frame = frame
        self.creation_module = frame.f_globals["__name__"]
        self.creation_file, self.creation_line, self.creation_function, \
            self.creation_text = \
            traceback.extract_stack(frame, 1)[0]
        self.creation_name = self.creation_text.split("=")[0].strip()
        super().__init__()
        threading.Thread(target=self._check_existence_after_creation).start()

    def _check_existence_after_creation(self):
        while self._outer_frame.f_lineno == self.creation_line:
            time.sleep(0.01)
        # this is executed as soon as the line number changes
        # now we can be sure the instance was actually created
        error = InstanceCreationError(
                "\nCreation name not found in creation frame.\ncreation_file: "
                "%s \ncreation_line: %s \ncreation_text: %s\ncreation_name ("
                "might be wrong): %s" % (
                    self.creation_file, self.creation_line, self.creation_text,
                    self.creation_name))
        nameparts = self.creation_name.split(".")
        try:
            var = self._outer_frame.f_locals[nameparts[0]]
        except KeyError:
            raise error
        finally:
            del self._outer_frame
        # make sure we have no permament inter frame reference
        # which could hinder garbage collection
        try:
            for name in nameparts[1:]: var = getattr(var, name)
        except AttributeError:
            raise error
        if var is not self: raise error

    def __repr__(self):
        return super().__repr__()[
               :-1] + " with creation_name '%s'>" % self.creation_name

A simple example:

一个简单的例子:

class MySubclass(RememberInstanceCreationInfo):
    def __init__(self):
        super().__init__()

    def print_creation_info(self):
        print(self.creation_name, self.creation_module, self.creation_function,
                self.creation_line, self.creation_text, sep=", ")

instance = MySubclass()
#out: instance, __main__, <module>, 68, instance = MySubclass()

If the creation name cannot be determined properly an error is raised:

如果无法正确确定创建名称,则会引发错误:

variable, another_instance = 2, MySubclass()

# InstanceCreationError: 
# Creation name not found in creation frame.
# creation_file: /.../myfile.py 
# creation_line: 71 
# creation_text: variable, another_instance = 2, MySubclass()
# creation_name (might be wrong): variable, another_instance

#10


-1  

The best way is really to pass the name to the constructor as in the chosen answer. However, if you REALLY want to avoid asking the user to pass the name to the constructor, you can do the following hack:

最好的方法是将名称传递给构造函数,就像在所选答案中一样。但是,如果您真的想避免要求用户将名称传递给构造函数,则可以执行以下操作:

If you are creating the instance with 'ThisObject = SomeObject()' from the command line, you can get the object name from the command string in command history:

如果要从命令行使用“ThisObject = SomeObject()”创建实例,则可以从命令历史记录中的命令字符串中获取对象名称:

import readline
import re

class SomeObject():
    def __init__(self):
        cmd = readline.get_history_item(readline.get_current_history_length())                                                          
        self.name = re.split('=| ',cmd)[0]

If you are creating the instance using 'exec' command, you can handle this with:

如果使用'exec'命令创建实例,则可以使用以下命令处理:

if cmd[0:4] == 'exec': self.name = re.split('\'|=| ',cmd)[1]     # if command performed using 'exec'
else: self.name = re.split('=| ',cmd)[0]