为什么Python的inspect.isclass误认为实例是类?

7 投票
2 回答
3008 浏览
提问于 2025-04-16 06:27

给定以下模块:

class Dummy(dict):
    def __init__(self, data):
        for key, value in data.iteritems():
            self.__setattr__(key, value)

    def __getattr__(self, attr):
        return self.get(attr, None)
    __setattr__=dict.__setitem__
    __delattr__=dict.__delitem__


foo=Dummy({"one":1, "two":2})

为什么在执行 inspect.getmembers(..., predicate=inspect.isclass) 时,foo 会出现在输出中呢?

$ python2.5
Python 2.5.2 (r252:60911, Aug 28 2008, 13:13:37) 
[GCC 4.1.2 20071124 (Red Hat 4.1.2-42)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import junk
>>> import inspect
>>> inspect.getmembers(junk, predicate=inspect.isclass)
[('Dummy', <class 'junk.Dummy'>), ('foo', {'two': 2, 'one': 1})]
>>> inspect.isclass(junk.foo)
True

我原本以为 inspect 只会返回 Dummy,因为这是模块中唯一的类定义。但显然,在 inspect 模块看来,junk.foo 也是一个类。为什么会这样呢?

2 个回答

6

首先,Jon-Eric的回答非常棒,我只是想补充一些内容:

如果你在ipython中做这个(真是个好工具):

%psource inspect.isclass

你会得到:

return isinstance(object, types.ClassType) or hasattr(object, '__bases__')

这就是Jon-Eric所说的内容。

不过我猜你使用的是python 2.6以下的版本,而这个bug已经在2.7版本中修复了,下面是python 2.7中inspect.isclass()的代码:

return isinstance(object, (type, types.ClassType))
11

在Python 2.7之前,inspect.isclass这个函数简单地认为,只要有__bases__属性的东西就一定是一个类。

Dummy__getattr__方法让Dummy的实例看起来好像拥有所有的属性(值都是None)。

因此,对于inspect.isclass来说,foo看起来就像是一个类。

注意:__getattr__在被请求一个它不知道的属性时应该抛出AttributeError错误。(这和返回None是完全不同的。)

撰写回答