如何在python中检查某个类(按字符串名称)是否存在?

如何在python中检查某个类(按字符串名称)是否存在?,python,class,dynamic,Python,Class,Dynamic,是否可以检查某个类是否存在?我在json配置文件中有类名。 我知道我可以简单地尝试通过类名字符串创建一个对象,但这实际上是一个坏主意,因为类构造函数可以做一些意想不到的事情,而此时我只想检查我的配置是否有效,以及所有提到的类是否可用 有什么办法吗 编辑:我也知道你可以从某个模块中获得所有的方法,在我的情况下,我不确定,也不关心方法来自哪个模块。它可以来自任何import语句,我可能不知道它的确切来源。您可以解析源代码以获取所有类名: from ast import ClassDef, parse

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

有什么办法吗


编辑:我也知道你可以从某个模块中获得所有的方法,在我的情况下,我不确定,也不关心方法来自哪个模块。它可以来自任何import语句,我可能不知道它的确切来源。

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

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
from test2 import Foobar, Barbar, foo  

class Foo(object):
   pass

class Bar(object):
    pass
输出:

['Foo', 'Bar']
['Foobar', 'Barbar', '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)
输入:

class Foo(object):
   pass

class Bar(object):
    pass
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
输出:

['Foo', 'Bar']
['Foobar', 'Barbar', 'Foo', 'Bar']
我尝试了,这对我来说很有效,但可能有一种更为类似于python的方法来测试类的存在性:

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
功能是一个很好的后门开启器。有一种更可靠(但也更紧凑)。

使用
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
导入系统 def str_至_类(str): 返回reduce(getattr,str.split(“.”),sys.modules[\uu\u name\uu]) 尝试: cls=str_to_class() 除属性错误外: cls=无 如果是cls: obj=cls(…) 其他: #与此抗争 这避免了使用
eval
,并得到了多个SO用户的批准。
解决方案类似于。

您的意思是,如果一个类正确导入并在命名空间中可用,还是有一个创建了特定名称的类实例?如果您已经导入了所有可用的ObjeTC,您只需检查它即可。您可以编写一个
try-except-namererror
块。关于进一步的信息,我们需要您方面的一些努力。您可以尝试
if locals().get('ClassName',False):…
这不是工作的一半吗?如果类存在,它是如何实例化的?谢谢!成功了。它比遍历模块寻找可用类要容易得多。你救了我一天:)只要对任何尝试这个的人说一句话:确保你导入了类本身,而不仅仅是包含它的模块。否则,如果在模块Y中定义类X,检查将失败。我可能应该尝试使用class_exist('Y.X'),但这并不重要。如果您执行“从Y导入X”,您的类将可用,并且测试将正常进行使用
eval()
为任意代码执行敞开大门,为了安全起见,应该避免这种情况。@Alexandr使用自己的打印函数
injectme()
class\u exist(“injectme()”
)。当然,攻击者无法轻松创建函数对象。但这应该指出,无意的代码可能会被执行。@wenzul是的,我知道这一点,这就是为什么我问。如果我使用这种方法,我会严格避免对用户输入进行评估。我添加了一个链接到您的解决方案的免责声明。正如我在回答中指出的(我现在必须研究这个)。但也许你的解决方案比问题更一般?同时,您要求的其他信息还没有到达……因为我的项目中的str_to_类方法在一些utils文件中定义,我对它进行了一些修改,以检查类在顶层(从那里调用)是否存在。所以现在它看起来像:def str_to_class(str):frame=inspect.stack()[-1]module=inspect.getmodule(frame[0])返回reduce(getattr,str.split(“.”),sys.modules[module。。。但对于当前的任务,它是好的。。。