Можно ли создать экземпляр класса из строковой переменной в Python? - PullRequest
0 голосов
/ 19 января 2019

Допустим, у меня есть строка, которая содержит допустимый класс 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 голосов
/ 19 января 2019

упомянутый комментатор 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 просто недостаточно мощна), но быстро становится очень хитрой в использовании: я даже не упомянул, как import сработало бы еще. Существуют и другие приемы (декораторы функций, метаклассы), которые могут позволить вам делать то, что вы хотите делать, и требуют меньше усилий, но иногда exec действительно является единственным вариантом.

...