如果 class(按字符串名称)存在,如何检查 python?

How to check in python if some class (by string name) exists?

是否可以检查某些 class 是否存在?我在 json 配置文件中有 class 个名称。 我知道我可以简单地尝试通过 class 名称字符串创建一个对象,但这实际上是一个坏主意,因为 class 构造函数可以做一些意想不到的事情,而此时我只想检查如果我的配置有效并且所有提到的 classes 都可用。

有什么办法吗?

编辑:我也明白你可以从某个模块中获取所有方法,在我的情况下我不确定并且实际上不关心方法来自哪个模块。它可以来自任何导入语句,我可能不知道确切的来源。

您可以解析源代码以获取所有 class 名称:

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']

只需将配置中的 class 名称与返回的名称进行比较。

{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

测试2:

foo = 123

class Foobar(object):
    pass

class Barbar(object):
    pass

输出:

['Foobar', 'Barbar', 'Foo', 'Bar']

我尝试了 built-in type function,它对我有用,但可能有更 pythonic 的方法来测试是否存在 class:

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 be a great a back door opener. There is a more reliable (but also compact)

使用 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?.