是否可以检查是否存在某个类?我在json配置文件中有类名。 我知道我可以简单地尝试通过类名字符串创建一个对象但这实际上是一个坏主意,因为类构造函数可以做一些意想不到的事情,而在这个时候我只想检查我的配置是否有效并且所有提到课程可用。
有什么办法吗?
编辑:我也明白你可以从某个模块中获取所有方法,在我的情况下我不确定并且实际上并不关心该方法的模块。它可以来自任何进口声明,我可能不知道究竟在哪里。答案 0 :(得分:3)
您可以解析源代码以获取所有类名:
from ast import ClassDef, parse
import importlib
import inspect
mod = "test"
mod = importlib.import_module(mod)
p = parse(inspect.getsource(mod))
names = [kls.name for kls in p.body if isinstance(kls, ClassDef)]
输入:
class Foo(object):
pass
class Bar(object):
pass
输出:
['Foo', 'Bar']
只需将配置中的类名与返回的名称进行比较。
{set of names in config}.difference(names)
如果要包含导入的名称,可以解析导入的模块,但根据导入的方式,您仍然可以找到不起作用的案例:
from ast import ClassDef, parse, ImportFrom
import importlib
import inspect
mod = "test"
mod = importlib.import_module(mod)
p = parse(inspect.getsource(mod))
names = []
for node in p.body:
if isinstance(node, ClassDef):
names.append(node.name)
elif isinstance(node, ImportFrom):
names.extend(imp.name for imp in node.names)
print(names)
输入:
from test2 import Foobar, Barbar, foo
class Foo(object):
pass
class Bar(object):
pass
TEST2:
foo = 123
class Foobar(object):
pass
class Barbar(object):
pass
输出:
['Foobar', 'Barbar', 'Foo', 'Bar']
答案 1 :(得分:3)
使用eval()
会打开门以执行任意代码,出于安全考虑,应该避免使用它。
特别是如果你在这里要求解决这样的问题。 然后我们可以假设您不充分了解这些风险。
import sys
def str_to_class(str):
return reduce(getattr, str.split("."), sys.modules[__name__])
try:
cls = str_to_class(<json-fragment-here>)
except AttributeError:
cls = None
if cls:
obj = cls(...)
else:
# fight against this
这可以避免使用eval
,并且已被多个SO用户批准。
解决方案类似于Convert string to Python class object?。
答案 2 :(得分:2)
我尝试了built-in type
function,这对我来说很有用,但是可能有更多的pythonic方法来测试类的存在:
import types
def class_exist(className):
result = False
try:
result = (eval("type("+className+")") == types.ClassType)
except NameError:
pass
return result
# this is a test class, it's only purpose is pure existence:
class X:
pass
print class_exist('X')
print class_exist('Y')
输出
True
False
当然,这是一个基本的解决方案,只能用于众所周知的输入:eval
函数can是一个很好的后门开启者。有一个更可靠(但也很紧凑)solution by wenzul。