是否可以从python中的字符串变量实例化一个类?

时间:2019-01-18 21:59:15

标签: python reflection code-generation

比方说,我有一个包含有效python类(不是类名)的字符串。例如:

class_template = """
class MyClass(object):
    def __init__(self, name):
         self.name = name

    def print_name(self):
        print('My name is: ' + self.name)

    def add_whatever(a, b):
        return a + b
"""

是否可以在python中实现一个函数(在下面的示例中为string_to_class),该函数接收该字符串并从中创建一个python类,以便稍后可以实例化该类?

class_template = """
class MyClass(object):
    def __init__(self, name):
         self.name = name

    def print_name(self):
        print('My name is: ' + self.name)

    def add_whatever(a, b):
        return a + b
"""

MyClass = string_to_class(class_template)
my_class_instance = MyClass('Ben')

print(MyClass.add_whatever(2, 3))
my_class_instance.print_name()

输出应为:

5
My name is: Ben

一种可能的解决方案是将字符串写到MyClass.py文件中,然后使用__import__()进行加载。还有其他(内存中)解决方案吗?

谢谢您的回答。

1 个答案:

答案 0 :(得分:1)

评论者提到exec;这是将其组合在一起的方式:

def string_to_class(python_text):
    local_vars = {}
    exec(python_text, {}, local_vars)
    # assume just a single new symbol was created (the class), and return it
    return list(local_vars.values())[0]

class_template = """
class MyClass(object):
    def __init__(self, name):
         self.name = name

    def print_name(self):
        print('My name is: ' + self.name)

    @staticmethod
    def add_whatever(a, b):
        return a + b
"""

MyClass = string_to_class(class_template)
my_class_instance = MyClass('Ben')

print(MyClass.add_whatever(2, 3))
my_class_instance.print_name()

但是,就像其他评论者提到的那样,它不是一种普遍应用的技术,因此请谨慎使用。随着用例变得越来越复杂,您还将很快遇到问题:

some_string_that_defines_a_base_class = "case Base..."
some_string_that_defines_a_derived_class = "case Derived(Base):..."

Base = string_to_class(some_string_that_defines_a_base_class)
# this will crash because Base isn't defined in the scope that the string
# is being evaluated with
Derived = string_to_class(some_string_that_defines_a_derived_class)

您可以通过直接调用exec来解决此问题(string_to_class函数根本不够强大),但使用起来很快就很棘手:我什至没有提到{{ 1}} s可以工作了。还有其他技术(函数装饰器,元类)可以使您做的事更少痛苦,但是有时候import确实是您唯一的选择。