-1

How can I instantiate the class stored in the raw string my_class without having to save this string into a file first?

my_class = r'''class A:
    def print(self):
        print('Hello World')
    '''

my_class_object = string_to_class()

my_class_object.print()

In the code above, I'm looking for an implementation of the function string_to_class() that returns an object of the class inside my_class.

The expected output of the code above is Hello World.

ihavenoidea
  • 629
  • 1
  • 7
  • 26

2 Answers2

2

You just need to use exec: it supports dynamic execution of Python code.

import re 
def string_to_object(str_class, *args, **kwargs):
    exec(str_class)
    class_name = re.search("class ([a-zA-Z_][a-zA-Z0-9_]*)", str_class).group(1)
    return locals()[class_name](*args, **kwargs)

You can use the string_to_object function to automatically create an object of the specified class:

my_class = '''
class A:
    def print(self):
        print("Hello World")
'''
a = string_to_object(my_class)
a.print() # Hello World

You can also build something more complicated:

my_class = '''
class B:
    def __init__(self, a, b, c=0, d=1):
        self.a = a
        self.b = b
        self.c = c
        self.d = d
'''
b = string_to_object(my_class, 4, 5, c=7)
print(b.a) # 4
print(b.b) # 5
print(b.c) # 7
print(b.d) # 1

And also:

class C:
    pass

my_class = '''
class D(C):
    pass
'''

d = string_to_object(my_class)
Riccardo Bucco
  • 13,980
  • 4
  • 22
  • 50
  • This answer does not help me in returning an `A` object as far as I'm concerned. Is it possible to do this by using `exec()`? – ihavenoidea Apr 24 '20 at 17:23
  • exec is the same as if you'd written the code in python, so `A` becomes part of the namespace you executed it in. i.e. after riccardo's answer, you could do something like `A().print()` – acushner Apr 24 '20 at 17:42
  • @ihavenoidea i updated my answer by allowing you to build any object on any class, even with parameters. Let me know if this is what you need. – Riccardo Bucco Apr 24 '20 at 19:00
  • @RiccardoBuccoThis is great! Thanks a lot :) I'm having an issue though. My original example is a simplified one from my real problem. Your code fails if the class inside `my_class` inherits from another. Using your examples, if we have a `class B: pass` in the current namespace and the class inside `my_class` is for example, `class A(B)`, it gives me an error `KeyError: 'A(B)'`. Can you figure why? – ihavenoidea Apr 24 '20 at 19:16
  • It works! In the meantime I came up with another solution by using partition() `re.search("class (.*):", str_class).group(1).partition("(")[0]` which as far as my tests went, it worked as well. Thanks again @RiccardoBucco – ihavenoidea Apr 24 '20 at 19:37
2

What about editing the string a bit?

my_class_with_new_object = my_class + "\nnew_object = A()"

my_class_with_new_object will be:

class A:
    def print(self):
        print('Hello World')

new_object = A()

The call exec(my_class_with_new_object) and it will create an object new_object of type A

Then just call new_object.print()

Andres
  • 4,323
  • 7
  • 39
  • 53