017. Python中是否可以获取类的所有实例

转载请注明出处,https://www.cnblogs.com/wuxianfeng023

出处

 https://docs.python.org/zh-cn/3.9/faq/programming.html#faq-multidimensional-list

  • 官方回答:Python 不会记录类(或内置类型)的实例。可以在类的构造函数中编写代码,通过保留每个实例的弱引用列表来跟踪所有实例

  • 所以答案是不可以?可以?

  • 准确的说是python不提供这样的接口(没做好)给你,但你要自己实现是么有问题的。

实现代码

  • 方式一

    class A:
    instances = []
    def __init__(self,name):
    self.name = name
    self.__class__.instances.append(self)
    class B:
    instances = {}
    def __init__(self,name):
    self.__class__.instances[self] = name a1 = A('a1')
    a2 = A('a2')
    print(A.instances) # [<__main__.A object at 0x00000250F285FAC0>, <__main__.A object at 0x00000250F285F7F0>]
    print(A.instances[0].name) # a1 b1 = B('b1')
    b2 = B('b2')
    print(B.instances) # {<__main__.B object at 0x00000250F285F0A0>: 'b1', <__main__.B object at 0x00000250F285FEE0>: 'b2'}

  • 方式一有点问题

  • 比如你来个c = A('c1'),你处理的是实例化传递的c1,如果 你要获取c这个变量名是做不到的

  • 方式二

    from inspect import stack
    class A:
    instances = [] def __init__(self):
    name = stack()[1].code_context[0].split('=')[0].strip()
    self.instances.append(name) a = A()
    b = A()
    print(A.instances) # ['a','b']
  • 你会发现关键是stack(),而这是inspect中的

  • 详细你可以参考:https://docs.python.org/zh-cn/3.9/library/inspect.html?highlight=inspect

  • inspect.stack()

    inspect.stack(context=1)
    返回调用者的栈的帧记录列表。第一个记录代表调用者,最后一个记录代表了栈上最外层的调用。 在 3.5 版更改: 返回一个 具名元组 FrameInfo(frame, filename, lineno, function, code_context, index) 的列表。 具名元组:named tuple 可以参考 https://docs.python.org/zh-cn/3.9/glossary.html#term-named-tuple

  • 方式二一样有问题

  • 比如你对实例进行了del操作(这可能是显式的,也可能是隐式的),那你的处理是有问题的

    from inspect import stack
    class A:
    instances = [] def __init__(self):
    name = stack()[1].code_context[0].split('=')[0].strip()
    self.instances.append(name) a = A()
    del a
    print(A.instances) # ['a'] # 没错你仍然能得到这个a
  • 回到最开始的官方回答:通过保留每个实例的弱引用列表来跟踪所有实例,弱引用是啥?

  • 你可能要去看下官网

    https://docs.python.org/zh-cn/3.9/library/weakref.html
  • 简而言之是:对对象的弱引用不能保证对象存活:当对象的引用只剩弱引用时, garbage collection 可以销毁引用并将其内存重用于其他内容。但是,在实际销毁对象之前,即使没有强引用,弱引用也一直能返回该对象。术语 referent 表示由弱引用引用的对象。

  • 实现弱引用的模块是weakref

  • weakref返回一个类似其他语言指针的东西,在不影响python内建gc垃圾收集的情况下,创建一个指向该instance的弱引用。你可以理解python的gc机制类似于检测当前有没有任何引用该实例的对象,其中weakref就是创建一个新的引用,但这个引用在gc机制看来是“不存在”的,当只剩下weakref的时候gc就可以回收这块内存了

  • 方式三


    from inspect import stack
    from weakref import proxy class A:
    instances = [] def __init__(self):
    self.name = stack()[1].code_context[0].split('=')[0].strip()
    self.instances.append((self.name,proxy(self)))
    def __del__(self):
    try:
    for name_instance in self.instances:
    if name_instance[1] == self:
    A.instances.remove(name_instance)
    except ReferenceError:
    print('引用被删了')
    # for name_instance in self.instances:
    # if name_instance[1] == self:
    # A.instances.remove(name_instance)
    # ReferenceError: weakly-referenced object no longer exists
    a1 = A()
    del a1 # 显式的删除 ,但del是不一定会触发__del__的,因为可能还有别的引用
    def func():
    a2 = A() # a2 也是一个实例,但它出了这个函数也不会存在
    func()
    a3 = A()
    print(A.instances) # 只有a3
    # [('a3', <weakproxy at 0x0000013C5A7A43B0 to A at 0x0000013C5A5FF760>)]

拓展

  • 在stackoverflow上很早就有人问过类似的问题

    https://stackoverflow.com/questions/328851/printing-all-instances-of-a-class
    https://stackoverflow.com/questions/54000173/how-to-get-all-instances-of-a-class
  • 有一些有趣的代码你可以看下(稍作更改)

    def get_obj_instance_nums(dest_obj):
    '''
    获取对象的个数
    '''
    import gc
    obj_instance = []
    for obj in gc.get_objects():
    if isinstance(obj, dest_obj):
    obj_instance.append(obj)
    return len(obj_instance) class A:
    pass
    a1 = A()
    a2 = A()
    del a1 # 你如果删了,那返回1,不删就返回2
    print(get_obj_instance_nums(A)) # 1
  • 弱引用的另外一个示例

    from collections import defaultdict
    import weakref class KeepRefs(object):
    __refs__ = defaultdict(list)
    def __init__(self):
    self.__refs__[self.__class__].append(weakref.ref(self)) @classmethod
    def get_instances(cls):
    for inst_ref in cls.__refs__[cls]:
    inst = inst_ref()
    if inst is not None:
    yield inst class X(KeepRefs):
    def __init__(self, name):
    super(X, self).__init__()
    self.name = name x = X("x")
    y = X("y")
    for r in X.get_instances():
    print r.name
    del y
    for r in X.get_instances():
    print r.name

Python常见面试题017: Python中是否可以获取类的所有实例的更多相关文章

  1. 整理的最全 python常见面试题(基本必考)

    整理的最全 python常见面试题(基本必考) python 2018-05-17 作者 大蛇王 1.大数据的文件读取 ① 利用生成器generator ②迭代器进行迭代遍历:for line in ...

  2. 整理的最全 python常见面试题

      整理的最全 python常见面试题(基本必考)① ②③④⑤⑥⑦⑧⑨⑩ 1.大数据的文件读取: ① 利用生成器generator: ②迭代器进行迭代遍历:for line in file; 2.迭代 ...

  3. 【转载】常见面试题:C#中String和string的区别分析

    在很多人面试C#开发工程师的时候,会遇到一个面试题,就是C#中String和string有啥区别.其实针对这个问题C#中String和string没有本质上的区别,两者在程序中都可使用,稍微的一个区别 ...

  4. 【python常见面试题】之python 中对list去重的多种方法

    在python相关职位的面试过程中,会对列表list的去重进行考察.(注意有时会要求保证去重的顺序性) 1.直观方法 li=[1,2,3,4,5,1,2,3] new_li=[] for i in l ...

  5. Python常见面试题

    Q 1:Python 有哪些特点和优点? 作为一门编程入门语言,Python 主要有以下特点和优点: ● 可解释● 具有动态特性● 面向对象● 简明简单● 开源● 具有强大的社区支持当然,实际上 Py ...

  6. python常见面试题(三)

    问题1 到底什么是Python?你可以在回答中与其他技术进行对比(也鼓励这样做). 答案 下面是一些关键点: Python是一种解释型语言.这就是说,与C语言和C的衍生语言不同,Python代码在运行 ...

  7. 常见面试题整理--Python概念篇

    希望此文可以长期更新并作为一篇Python的面试宝典.每一道题目都附有详细解答,以及更加详细的回答链接.此篇是概念篇,下一篇会更新面试题代码篇. (一).这两个参数是什么意思:*args,**kwar ...

  8. python常见面试题(二)

    1. 到底什么是Python?你可以在回答中与其他技术进行对比(也鼓励这样做). 下面是一些关键点: Python是一种解释型语言.这就是说,与C语言和C的衍生语言不同,Python代码在运行之前不需 ...

  9. python常见面试题(mark)

    1.大数据的文件读取 ① 利用生成器generator ②迭代器进行迭代遍历:for line in file 2.迭代器和生成器的区别 1)迭代器是一个更抽象的概念,任何对象,如果它的类有next方 ...

  10. python常见面试题(一)

    1.Python是如何进行内存管理的? 答:从三个方面来说,一对象的引用计数机制,二垃圾回收机制,三内存池机制 一.对象的引用计数机制 Python内部使用引用计数,来保持追踪内存中的对象,所有对象都 ...

随机推荐

  1. web.xml文件报错'org.springframework.web.filter.CharacterEncodingFilter' is not assignable to 'javax.servlet.Servlet,jakarta.servlet.Servlet'

    在web.xml文件中出现下列错误:'org.springframework.web.filter.CharacterEncodingFilter' is not assignable to 'jav ...

  2. docker 配置 anaconda + jupyter notebook 纪要

    首先,pull官方的镜像,名字叫:continuumio/anaconda3 首先的首先,如果默认还是需要sudo运行docker命令,可以考虑把当前用户加入到docker组(usermod -aG ...

  3. CentOS7安装 Redis5 单实例

    1.下载redis下载地址在:redis.io比如把Redis安装到/usr/local/soft/ cd /usr/local/soft/ wget http://download.redis.io ...

  4. python跨文件之全局变量

    Python中的global关键字,你了解吗? - 知乎 (zhihu.com)  global 关键字 python跟C不一样,c是在一个文件定义后在另一个文件声明下是extern变量就好.pyth ...

  5. 移动服务(f[i] [j] [k],这三个人,位置为a[i],j,k的最小价值)

    移动服务(f[i] [j] [k],这三个人,位置为a[i],j,k的最小价值) 题意 给出点之间到达价值,使用3个人处理一个序列,f[i] [j] [k],这三个人,每次处理序列中一个值,三个人中一 ...

  6. axel多线程下载

    Axel 是一个轻量级下载程序,它和其他加速器一样,对同一个文件建立多个连接,每个连接下载单独的文件片段以更快地完成下载. Axel 通过打开多个 HTTP/FTP 连接来将一个文件进行分段下载,从而 ...

  7. MyBatis-Plus使用SQL语句

    项目中碰到一个必须要使用动态SQL的地方, 想着在xml文件中进行一层一层的判断太麻烦了,也不好理解,要是能在Java代码中组织好SQL,进行查询操作 QueryWrapper<object&g ...

  8. 火狐浏览器调试eval源码

    火狐浏览器调试eval源码 firefox浏览器在网页调试上,有一个没法和chrome一比高下的功能,就是eval脚本的调试,有时前端架构使用了基于eval的方式,有时候可能是自己一个多行函数,每每遇 ...

  9. Javaweb学习笔记第十六弹--Vue、Element

    Vue(一套前端框架,MVVM主要用于实现数据的双向绑定) Vue快速入门 //新建HTML页面,引入Vue.js文件 <script src="js.Vue.js"> ...

  10. 自己动手从零写桌面操作系统GrapeOS系列教程——12.QEMU+GDB调试

    学习操作系统原理最好的方法是自己写一个简单的操作系统. 写程序不免需要调试,写不同的程序调试方式也不同.如果做应用软件开发,相应的程序调试方式是建立在有操作系统支持的基础上的.而我们现在是要开发操作系 ...