如果班级有__dict__变量,可以检查obj .__ dict__吗?

时间:2011-09-22 08:15:49

标签: python class inheritance introspection internals

我感兴趣的是,有没有办法可靠地内省Python实例以查看其__dict__,尽管程序员可能会遇到任何障碍,因为这会帮助我调试非预期的引用循环等问题和开放文件等悬空资源。

一个更简单的例子是:如果程序员隐藏了dict后面的类,我怎么能看到keys()子类的键?解决方法是手动调用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__的这个错误值不会干扰实际的属性设置和获取,但它会隐藏dir()a误导b并将fake显示为对象的实例变量。

同样,我的目标是编写一个工具,当我想知道为什么一组类实例占用如此多的内存或者打开如此多的文件时,我会自我反省类实例以查看“实际发生了什么” - 以及即使上面的情况极其恶劣,找到解决办法的方法也会让这个工具一直工作,而不是说“效果很好,除非你正在看的课程有...... [上述特殊情况的描述]。” p>

我曾经以为我能够通过以下方式无懈可击地抓住__dict__

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

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

任何想法,任何人? :)

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:0)

这个是基于Jerub在本主题中的回答: What is a metaclass in 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输出是一个字符串。它可以做得更好,但这就是想法本身。