如果存在某些类(按字符串名称),如何检入python?

时间:2015-05-27 12:47:12

标签: python class dynamic

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

有什么办法吗?

编辑:我也明白你可以从某个模块中获取所有方法,在我的情况下我不确定并且实际上并不关心该方法的模块。它可以来自任何进口声明,我可能不知道究竟在哪里。

3 个答案:

答案 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