如果类有 __dict__ 变量,可以检查 obj.__dict__ 吗?

发布于 2024-12-06 02:08:29 字数 1558 浏览 1 评论 0原文

我感兴趣的是是否有一种方法可以无误地内省 Python 实例以查看其 __dict__,尽管程序员可能会遇到任何障碍,因为这将帮助我调试诸如意外引用循环之类的问题以及悬空资源,例如打开的文件。

一个更简单的例子是:如果程序员将 keys() 隐藏在自己的类后面,我如何才能看到 dict 子类的键?解决方法是手动调用 dict keys() 方法,而不是让继承调用该方法的子类版本:

# Simple example of getting to the real info
# about an instance

class KeyHidingDict(dict):
    def keys(self):
        return []  # there are no keys here!

khd = KeyHidingDict(a=1, b=2, c=3)
khd.keys()       # drat, returns []
dict.keys(khd)   # aha! returns ['a', 'b', 'c']

现在我的实际问题是,我怎样才能看到实例的 __dict__ ,无论程序员可能做了什么来向我隐藏它?如果他们设置了一个 __dict__ 类变量,那么它似乎会隐藏从该类继承的任何对象的实际 __dict__ :

# My actual question

class DunderDictHider(object):
    __dict__ = {'fake': 'dict'}

ddh = DunderDictHider()
ddh.a = 1
ddh.b = 2
print ddh.a        # prints out 1
print ddh.__dict__ # drat, prints {'fake': 'dict'}

这个 __dict__ 的错误值确实正如您所看到的,不会干扰实际的属性设置和获取,但它确实通过隐藏 ab 并显示来误导 dir() fake 作为对象的实例变量 反而。

同样,我的目标是编写一个工具,当我想知道为什么一组类实例占用如此多的内存或打开如此多的文件时,可以帮助我内省类实例以了解“到底发生了什么” - 即使上面的情况是非常人为的,找到一种解决方法可以让该工具一直工作,而不是说“工作很好,除非您正在查看的类有......[上面特殊情况的描述]”。

我原以为我能够通过以下方式准确无误地获取 __dict__:

dict_descr = object.__dict__['__dict__']
print dict_descr(ddh, DunderDictHider)

但事实证明,object 没有 __dict__ 描述符。相反,subtype_dict() C 函数似乎单独附加到程序员创建的 object 的每个子类;没有集中的方法来命名或获取描述符,以便可以将其手动应用于其类隐藏它的对象。

有什么想法吗? :)

I am interested in whether there is a way to introspect a Python instance infallibly to see its __dict__ despite any obstacles that the programmer might have thrown in the way, because that would help me debug problems like unintended reference loops and dangling resources like open files.

A simpler example is: how can I see the keys of a dict subclass if the programmer has hidden keys() behind a class of its own? The way around that is to manually call the dict keys() method instead of letting inheritance call the subclass's version of the method:

# Simple example of getting to the real info
# about an instance

class KeyHidingDict(dict):
    def keys(self):
        return []  # there are no keys here!

khd = KeyHidingDict(a=1, b=2, c=3)
khd.keys()       # drat, returns []
dict.keys(khd)   # aha! returns ['a', 'b', 'c']

Now my actual question is, how can I see the __dict__ of an instance, no matter what the programmer might have done to hide it from me? If they set a __dict__ class variable then it seems to shadow the actual __dict__ of any objects inherited from that class:

# My actual question

class DunderDictHider(object):
    __dict__ = {'fake': 'dict'}

ddh = DunderDictHider()
ddh.a = 1
ddh.b = 2
print ddh.a        # prints out 1
print ddh.__dict__ # drat, prints {'fake': 'dict'}

This false value for __dict__ does not, as you can see, interfere with actual attribute setting and getting, but it does mislead dir() by hiding a and b and displaying fake as the object's instance variable instead.

Again, my goal is to write a tool that helps me introspect class instances to see “what is really going on” when I am wondering why a set of class instances is taking so much memory or holding so many files open — and even though the situation above is extremely contrived, finding a way around it would let the tool work all the time instead of saying “works great, unless the class you are looking at has… [description of the exceptional situation above].”

I had thought I would be able to infallibly grab the __dict__ with something like:

dict_descr = object.__dict__['__dict__']
print dict_descr(ddh, DunderDictHider)

But it turns out that object does not have a __dict__ descriptor. Instead, the subtype_dict() C function seems to get separately attached to each subclass of object that the programmer creates; there is no central way to name or fetch the descriptor so that it can be manually applied to objects whose class shadows it.

Any ideas, anyone? :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

淡写薰衣草的香 2024-12-13 02:08:29

我不确定我对这有多简单感到满意:

>>> class DunderDictHider(object):
...     __dict__ = {'fake': 'dict'}
... 
>>> ddh = DunderDictHider()
>>> ddh.a = 1
>>> ddh.b = 2
>>> 
>>> print ddh.a
1
>>> print ddh.__dict__
{'fake': 'dict'}

问题是班级作弊?解决这个问题!

>>> class DictUnhider(object):
...     pass
... 
>>> ddh.__class__ = DictUnhider
>>> print ddh.a
1
>>> print ddh.__dict__
{'a': 1, 'b': 2}

就是这样。但是,如果该类定义了任何插槽,则这完全失败。

>>> class DoesntHaveDict(object):
...     __slots__ = ['a', 'b']
... 
>>> dhd = DoesntHaveDict()
>>> dhd.a = 1
>>> dhd.b = 2
>>> 
>>> print dhd.a
1
>>> dhd.__class__ = DictUnhider
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __class__ assignment: 'DoesntHaveDict' object layout differs from 'DictUnhider'
>>> 

I'm not sure I'm happy with how simple this is:

>>> class DunderDictHider(object):
...     __dict__ = {'fake': 'dict'}
... 
>>> ddh = DunderDictHider()
>>> ddh.a = 1
>>> ddh.b = 2
>>> 
>>> print ddh.a
1
>>> print ddh.__dict__
{'fake': 'dict'}

The problem is that the class is cheating? Fix that!

>>> class DictUnhider(object):
...     pass
... 
>>> ddh.__class__ = DictUnhider
>>> print ddh.a
1
>>> print ddh.__dict__
{'a': 1, 'b': 2}

And there it is. This completely fails though, if the class defines any slots.

>>> class DoesntHaveDict(object):
...     __slots__ = ['a', 'b']
... 
>>> dhd = DoesntHaveDict()
>>> dhd.a = 1
>>> dhd.b = 2
>>> 
>>> print dhd.a
1
>>> dhd.__class__ = DictUnhider
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __class__ assignment: 'DoesntHaveDict' object layout differs from 'DictUnhider'
>>> 
梦一生花开无言 2024-12-13 02:08:29

这是基于 Jerub 在本主题中的回答:
Python 中的元类是什么?

您可以实现您想要的目标与元类。

首先,您需要创建一个元类:

def test_metaclass(name, bases, dict):
    print 'The Class Name is', name
    print 'The Class Bases are', bases
    print 'The dict has', len(dict), 'elems, the keys are', dict.keys()

    return dict

当然打印不是必需的。

然后让我介绍一下您的新 DunderDictHider:

class DunderDictHider(object):
    __metaclass__ = test_metaclass
    __dict__ = {'fake': 'dict'}

现在您可以通过 repr(DunderDictHider) 访问所有初始化的元素

输出(使用 print repr(DunderDictHider) 行):

The Class Name is DunderDictHider
The Class Bases are (<type 'object'>,)
The dict has 3 elems, the keys are ['__dict__', '__module__', '__metaclass__']
{'__dict__': {'fake': 'dict'}, '__module__': '__main__', '__metaclass__': <function test_metaclass at 0x1001df758>}

每次您可以尝试

if '__dict__' in repr(DunderDictHider)

知道这个类是否试图隐藏它的__dict__。请记住,repr 输出是一个字符串。它可以做得更好,但这就是想法本身。

This one is based on Jerub answer in this topic:
What is a metaclass in Python?

You can achieve what you're looking for with metaclasses.

First you need to create a metaclass:

def test_metaclass(name, bases, dict):
    print 'The Class Name is', name
    print 'The Class Bases are', bases
    print 'The dict has', len(dict), 'elems, the keys are', dict.keys()

    return dict

of course the prints are not necessery.

Then let me introduce your new DunderDictHider:

class DunderDictHider(object):
    __metaclass__ = test_metaclass
    __dict__ = {'fake': 'dict'}

Now you have access to all initialized elems by repr(DunderDictHider)

The output (with print repr(DunderDictHider) line):

The Class Name is DunderDictHider
The Class Bases are (<type 'object'>,)
The dict has 3 elems, the keys are ['__dict__', '__module__', '__metaclass__']
{'__dict__': {'fake': 'dict'}, '__module__': '__main__', '__metaclass__': <function test_metaclass at 0x1001df758>}

Each time you can try

if '__dict__' in repr(DunderDictHider)

to know whether this class tries to hide its __dict__ or not. Remember, that repr output is a string. It can be done better, but that's the idea itself.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文