如果 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?.
是否可以检查某些 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?.