获取类 __init__() 中的实例名称[重复]

2025-02-28 08:22:00
admin
原创
84
摘要:问题描述:在 python 中构建新的类对象时,我希望能够根据类的实例名称创建默认值,而无需传入额外的参数。我该如何实现这一点?以下是我正在尝试的基本伪代码:class SomeObject(): defined_name = u"" def __init__(self,...

问题描述:

在 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"

解决方案 1:

嗯,几乎有一种方法可以做到这一点:

#!/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

traceback 模块允许你查看调用 SomeObject() 的代码。通过一些字符串处理,text[:text.find('=')].strip()你可以猜出 def_name 应该是什么。

但是,这种 hack 很脆弱。例如,下面的代码效果不太好:

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

所以如果你要使用这个技巧,你必须记住你必须使用简单的 python 语句调用 SomeObject():

ThisObject = SomeObject()

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

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

然后你可以打电话

x=3.14
pv(x)
# x: 3.14

打印变量名称及其值。

解决方案 2:

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

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

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

解决方案 3:

您可以在类内部创建一个方法,检查当前框架中的所有变量并用来hash()查找该self变量。

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

在下面的类中,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

已完成以下测试:

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

结果是:

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

解决方案 4:

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

解决方案 5:

实现这一目标的一个非常非常糟糕的方法就是颠倒责任:

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

SomeObject("ThisObject")
print ThisObject.defined_name

如果您想要支持除全球范围之外的其他内容,您就必须做一些更可怕的事情。

解决方案 6:

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

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

考虑这个例子:

foo = 1
bar = foo
baz = foo

现在,假设您有一个值为 1 的整数对象,并且您想反向查找其名称。您会打印什么?三个不同的名称都与该对象绑定,并且它们都同样有效。

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

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

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

有一篇著名的演讲叫做《像 Pythonista 一样编码》,将这种情况总结为“其他语言有‘变量’”,而“Python 有‘名称’”

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

解决方案 7:

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

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

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

解决方案 8:

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

“根据类的实例名称创建默认值,而无需传递额外的参数。”

当创建此类或子类的实例时,它执行以下操作:

  1. 沿帧堆栈向上移动,直到第一个不属于当前实例的方法的帧。

  2. 检查此框架以获取属性self.creation_(name/file/module/function/line/text)

  3. 执行额外的检查,确定具有名称的对象是否self.creation_name实际在框架的 locals() 命名空间中定义,以 100% 确保找到的 creation_name 是正确的,否则引发错误。

守则:

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, \n            self.creation_text = \n            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(
                "
Creation name not found in creation frame.
creation_file: "
                "%s 
creation_line: %s 
creation_text: %s
creation_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

一个简单的例子:

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()
instance.print_creation_info()
#out: instance, __main__, <module>, 68, instance = MySubclass()

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

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

解决方案 9:

我认为,如果名称是指向任何对象的指针,那么名称就很重要。无论以下情况如何:

foo = 1
bar = foo

我知道 foo 指向 1,bar 指向同一个内存空间中的同一个值 1。但假设我想创建一个类,其中有一个可以向其添加对象的函数。

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

因此,当我像下面这样实例化类包时:

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

解决方案 10:

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

如果您从命令行使用“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]

如果您使用“exec”命令创建实例,则可以这样处理:

if cmd[0:4] == 'exec': self.name = re.split('\'|=| ',cmd)[1]     # if command performed using 'exec'
else: self.name = re.split('=| ',cmd)[0]
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2941  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1803  
  PLM(产品生命周期管理)系统在企业的产品研发、生产与管理过程中扮演着至关重要的角色。然而,在实际运行中,资源冲突是经常会遇到的难题。资源冲突可能导致项目进度延迟、成本增加以及产品质量下降等一系列问题,严重影响企业的效益与竞争力。因此,如何有效应对PLM系统中的资源冲突,成为众多企业关注的焦点。接下来,我们将详细探讨5...
plm项目管理系统   31  
  敏捷项目管理与产品生命周期管理(PLM)的融合,正成为企业在复杂多变的市场环境中提升研发效率、增强竞争力的关键举措。随着技术的飞速发展和市场需求的快速更迭,传统的研发流程面临着诸多挑战,而将敏捷项目管理理念融入PLM,有望在2025年实现研发流程的深度优化,为企业创造更大的价值。理解敏捷项目管理与PLM的核心概念敏捷项...
plm项目   31  
  模块化设计在现代产品开发中扮演着至关重要的角色,它能够提升产品开发效率、降低成本、增强产品的可维护性与可扩展性。而产品生命周期管理(PLM)系统作为整合产品全生命周期信息的关键平台,对模块化设计有着强大的支持能力。随着技术的不断发展,到 2025 年,PLM 系统在支持模块化设计方面将有一系列令人瞩目的技术实践。数字化...
plm软件   28  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用