在 Python 中将字符串转换为 Class 对象

要将字符串转换为类对象:

  1. 使用 sys.modules 字典获取当前模块。
  2. 可以在模块的属性中访问该类。
  3. 将字符串传递给 getattr() 函数以获取类对象。
import sys


class Employee():
    pass


def get_class(class_name):
    return getattr(sys.modules[__name__], class_name)


cls = get_class('Employee')
print(cls)  # 👉️ <class '__main__.Employee'>

该示例假定该类是在同一模块中定义的。 如果该类是在不同的模块中定义的,请向下滚动到最后一个子标题并使用 importlib.import_module() 方法。

Sys.modules 是一个字典,将模块名称映射到已经加载的模块。

__name__ 全局变量存储模块的名称。

import sys

# ?️ <module '__main__' from '/Users/zadmei/workspace/python/study/main.py'>
print(sys.modules[__name__])

获得模块对象后,使用 getattr() 方法将字符串转换为类对象。

import sys


class Employee():
    pass


def get_class(class_name):
    return getattr(sys.modules[__name__], class_name)


cls = get_class('Employee')
print(cls)  # 👉️ <class '__main__.Employee'>

getattr 函数返回对象提供的属性的值。

该函数采用以下参数:

  • object 应检索其属性的对象
  • name 命名属性的名称
  • default 对象上不存在该属性时的默认值

如果具有指定名称的类不存在,我们将收到 AttributeError

如果需要指定默认值,可以将第三个参数传递给 getattr() 方法。

import sys


def get_class(class_name):
    # 👇️ returns None if class with given name doesn't exist
    return getattr(sys.modules[__name__], class_name, None)


cls = get_class('ABC123')
print(cls)  # 👉️ None

或者,我们可以使用 eval() 函数。


使用 eval() 将字符串转换为 Class 对象

使用 eval() 函数将字符串转换为类对象,例如 eval(class_name)。 eval() 函数将获取字符串并将其作为返回类的 Python 表达式求值。

class Employee():
    pass

def get_class(class_name):
    return eval(class_name)


print(get_class('Employee'))  # 👉️ <class '__main__.Employee'>

eval() 函数接受一个表达式,将其解析并评估为 Python 表达式,使用 globals 和 locals 字典作为全局和本地命名空间。

eval() 函数只能用于受信任的代码。 不要将 eval() 用于用户生成的数据。

eval() 函数基本上试图运行给定的表达式,所以它不应该与不受信任的代码一起使用。

如果在使用 eval() 时出现 linting 错误,请改用 globals() 字典。


使用 globals() 将字符串转换为 Class 对象

要将字符串转换为类对象:

  1. 使用 globals() 函数获取包含当前作用域的全局变量的字典。
  2. 使用字符串作为字典键来访问类对象。
# ✅ if the class is in the same module

class Employee():
    pass

def get_class(class_name):
    return globals()[class_name]


print(get_class('Employee'))  # 👉️ <class '__main__.Employee'>

globals() 函数返回一个实现当前模块命名空间的字典。

class Employee():
    pass

# {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x10a24e810>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': '/Users/zadmei/workspace/python/study/main.py', '__cached__': None, 'Employee': <class '__main__.Employee'>}
print(globals())

最后一步是使用字符串来访问字典的键。

有一个带有类名的键指向类对象。

如果模块中不存在具有给定名称的类,则会出现 KeyError 异常。

前 3 种方法仅适用于在同一模块中定义类的情况。

如果该类是在不同的模块中定义的,请使用 importlib 模块。

使用 importlib.import_module() 将字符串转换为 Class 对象

当类在不同的模块中定义时,将字符串转换为类对象:

  1. 使用 importlib.import_module() 方法导入模块。
  2. 可以在模块的属性中访问该类。
  3. 将字符串传递给 getattr() 函数以获取类对象。
import importlib


def get_class(module_name, class_name):
    module = importlib.import_module(module_name)
    return getattr(module, class_name)


print(get_class('another', 'Employee'))  # 👉️ <class 'another.Employee'>

该示例假定在包含 Employee 类的同一目录中存在一个名为 another.py 的模块。

another.py

class Employee():
    pass

importlib.import_module() 方法采用模块的名称并导入它。

name 参数可以是绝对的或相对的,例如 pkg.module 或 ..module

如果您使用相对包名称,例如 ..module,我们必须将第二个参数传递给 import_module() 方法,例如 import_module('..module', pkg.subpkg') 导入 pkg.module。

一旦我们导入了模块,我们就可以使用 getattr() 函数从给定的字符串中获取类对象。

getattr() 函数采用可选的第三个参数,该参数用作对象上不存在该属性时的默认值。