Python——检查对象是不是是某个模块中任何类的实例
Posted
技术标签:
【中文标题】Python——检查对象是不是是某个模块中任何类的实例【英文标题】:Python -- Check if object is instance of any class from a certain modulePython——检查对象是否是某个模块中任何类的实例 【发布时间】:2013-01-12 07:24:58 【问题描述】:需要一种方法来检查一个对象是否是某个特定模块中任何类的实例。
我知道我可以通过从该模块显式导入每个类并使用元组检查来做到这一点:
from my_module import ClassOne, ClassTwo
>>> isinstance(my_obj, (ClassOne, ClassTwo))
True
但实际上,我从中导入的模块中有大量的类,并且显式地导入它们似乎是不必要的冗长,使用它们来构建一个巨大的元组,并对它进行类型检查。我尝试了一些方法来避免这种情况:
import my_module
# Test my_obj against the module itself
>>> isinstance(my_obj, my_module)
TypeError: isinstance() arg 2 must be a class, type, or tuple of classes and types
# Try to test against a wildcard attribute on my_module
>>> isinstance(my_obj, my_module.*)
SyntaxError: invalid syntax
#Try to build a tuple of clases with iteration to check against
>>> for klass in my_module:
TypeError: 'module' object is not iterable
有没有一种方法可以对 my_module 中的所有类进行类型检查,而无需在元组中明确命名它们?
可选背景信息: 我可能忽略了解决问题的更好方法——如果您想知道,情况如下:
我们正在将数据从 Google App Engine 应用程序导出到我们在 Rackspace 上托管的应用程序。我们正在使用pickle
序列化数据,然后使用 HTTP 请求将其发送到我们的 Rackspace 服务器。
Google App Engine 数据库中的一些数据属于 GAE 特定的数据类型,从 google.appengine.api.datastore_types 导入。如果这些数据类型中的任何一种通过网络连接到我们的 Rackspace 服务器,它们将引发错误 depickling,因为我们的 Rackspace 应用程序没有所需的 GAE 库。因此,在退出 GAE 的过程中,我正在检查是否有任何传出对象具有来自 google.appengine.api.datastore_types 的类型。如果是这样,我要么将它们转换为内置数据类型,要么从对象中删除该字段。
【问题讨论】:
附带说明——这种检查对我来说似乎完全没有必要。我看不出你想要这个的原因......虽然我下面的解决方案会起作用,但我很想听听更多关于你的用例的信息——可能有更好的方法来完成你正在尝试的任何事情做... 编辑问题以说明情况。 【参考方案1】:您可以使用inspect.getmembers
获取模块中的所有类:
inspect.getmembers(my_module,inspect.isclass)
这将返回名称-类对的列表。你只想要课程:
my_module_classes = tuple(x[1] for x in inspect.getmembers(my_module,inspect.isclass))
当我最初写这个答案时,我设法忽略的一件事是检查类的__module__
属性的能力。您可以检查__module__
是否符合您的预期:
from somewhere import module
if getattr(obj, '__module__', None) == module.__name__:
# obj is from module.
这可能比 isinstance
检查大量的类名要便宜。
【讨论】:
+1 我不禁怀疑isinstance(my_obj, my_module_classes)
是否比if any(isinstance(my_obj, x[1]) for x in inspect.getmembers(my_module, inspect.isclass))
好
@kojiro -- 如果any
解决方案比直接的isinstance
解决方案更好,我会感到震惊。我看不出isinstance
不会短路的任何原因,它可以将 all 的代码推送到优化的后端(C
用于 cpython),而使用生成器你有创建生成器表达式然后在 python 中迭代的开销......虽然,我以前对这些东西错了;-)
@mgilson:嗯,他说的是“更好”,而不是“更快”。我怀疑性能在任何实际代码中是否真的很重要,尤其是像这样动态的代码。所以问题是哪个更具可读性。但是......我认为你的版本仍然会赢,只要你可以依靠你的观众知道isinstance
需要tuple
(考虑到OP的问题,我认为你可以),因为它允许你给一个名字到类的集合。
也许我不明白您所说的将所有代码推送到优化的后端是什么意思,但我基本上想知道创建整个类元组的成本(tuple()
cast 本身需要一个生成器表达式参数,不是吗?)。
@abarnert -- 我想我假设我的版本从一开始就更容易阅读。 kojiro 的解决方案更好的一种情况是,如果人们正在修补猴子的东西——那么我的静态版本可能不会削减它。【参考方案2】:
我用过@mgilson 简单的解决方案:
from somewhere import module
if getattr(obj, '__module__', None) == module.__name__:
# obj is from module.
并注意到如果你有一个模块树,并且你想确保它来自基本模块,你必须这样做:
from somewhere import module
if getattr(obj, '__module__', None).split('.')[0] == module.__name__:
# obj is from module.
但是,如果您的 object
来自内置,则会引发异常,所以我会:
from somewhere import module
module_tree = getattr(obj, '__module__', None)
parent = module_tree.split('.')[0] if module_tree else None
if parent == module.__name__:
# obj is from module.
【讨论】:
以上是关于Python——检查对象是不是是某个模块中任何类的实例的主要内容,如果未能解决你的问题,请参考以下文章
如何检查 Python 包中的任何模块是不是从另一个包导入?