为什么Python的inspect.isclass误认为实例是类?
给定以下模块:
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
是完全不同的。)