issubclass在第一个参数不是类时引发异常
我正在开发一个Python应用程序,需要多次检查一个对象是否是数据库模型的子类。
为此,我自己写了一个函数:
def isModel(obj):
return isinstance(obj, type) and issubclass(obj, Model)
issubclass
这个函数如果传入的对象不是一个类,就会抛出异常,但我希望它能直接返回False,而不是报错。
我觉得还是写一个新的函数来替代内置的issubclass
比较好:
def _issubclass(obj, Klass):
return isinstance(obj, type) and issubclass(obj, Klass)
但是为什么内置的issubclass
没有这样设计呢?有什么原因吗?我是不是遗漏了什么?
更新:
我有一些模型:
class BaseModel(object):
id = Field(...)
class MyModel(BaseModel):
deleted = Field(...)
在一个函数中,我想检查一个参数是否是BaseModel
:
def update_model(model):
assert isinstance(model, type) and issubclass(model, BaseModel), 'Must be a model'
issubclass
这个函数是用来判断一个对象是否是某个类的子类。如果传入的对象是一个类的实例,那么我觉得答案应该是'不,你的对象不是BaseModel的子类,因为它根本不是一个类'。
在Python中,通常我们会用if something
来代替if something is not None or len(something) != 0
,这样不会引发任何TypeError
。那么如果issubclass
的第一个参数不是一个类,抛出TypeError有什么用呢?
举个例子,有人问一只狗:'你是解决这个任务的合适人选吗?',结果狗没有直接回答'不是',而是说'我不是人'。这样我问了一个问题(是否是子类),但它没有回答我的问题。
3 个回答
请查看关于 isinstance
和 issubclass
的文档,它们解释得很清楚。
你是说“一个对象是数据库模型的子类”,对吧?也就是说它应该是一个类,而不是类的实例?那么这不正是 issubclass
的作用吗?为什么还要纠结于 isinstance
呢? – Chris Morgan 刚刚编辑
我找到了一种更优雅的方法,使用元类(因为我的模型本来就用到了元类):
Python 2.7.2+ (default, Oct 4 2011, 20:06:09)
[GCC 4.6.1] on linux2
>>> class ModelMeta(type):
... "Metaclass for models"
...
>>> class Model(object):
... "DB model"
... __metaclass__ = ModelMeta
...
>>> class MyModel(Model):
... "A real model"
...
>>> isinstance(MyModel, type) and issubclass(MyModel, Model)
True
>>> myModelInstance = Model()
>>> issubclass(MyModel, Model)
True
>>> issubclass(myModelInstance, Model)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: issubclass() arg 1 must be a class
>>> isinstance(MyModel, type) and issubclass(MyModel, Model)
True
>>> isinstance(myModelInstance, type) and issubclass(myModelInstance, Model)
False
>>> isinstance(MyModel, ModelMeta)
True
>>> isinstance(myModelInstance, ModelMeta)
False
>>>
所以,现在我使用的是 isinstance(MyModel, ModelMeta)
。
使用isinstance可能正是你想要的功能。isinstance(obj, Klass)
会在obj是Klass类的一个实例时返回True,也就是说,如果obj是Klass的子类的实例,它也会返回True。
>>> class A(object):
... pass
...
>>> class B(A):
... pass
...
>>> obj = B()
>>>
>>> isinstance(obj, A)
True
“如果issubclass的第一个参数不是一个类,抛出TypeError有什么用?”
明确的错误比模糊的错误要好。你把一个不是类的东西传给issubclass,这说明你做错了什么。因此,系统会给你一个错误提示。如果你真的想把实例传给issubclass,你可以捕捉这个错误:
try:
isbasemodel = False
if issubclass(x, BaseModel):
isbasemodel = True
except TypeError:
# Accept that we test non-classes:
pass
当然,你也可以像现在这样:做一个额外的检查。
但是,如果没有抛出错误,那就没办法发现你传入了一个实例的错误。
根据我的理解,你想在一个API或类似的地方检查传入的对象是否是BaseModel的子类,并且不允许用户传入实例。在我看来,正确的做法是如果他们传入了错误的东西,就抛出一个TypeError。像这样:
def update_model(model):
if not issubclass(model, BaseModel):
raise TypeError('Must be a model')
在这里做一个断言只会掩盖传入错误类型的事实。