Reputation: 3380
This question may sound similar to the following, but I'm not sure how to apply their solutions to my use-case:
How to import a module given the full path?
Can you use a string to instantiate a class?
I have a class Foo
defined and imported in my project. However, at runtime I may have a string containing a different definition of Foo
(along with lots of other classes and import
statements). I'd like to be able to replace the already loaded Foo
with the one in my string, in a way that after the operation, anybody who instantiates f = Foo()
would instantiate the definition from my string. At the same time, I'd like to ignore any other definitions/imports in my string. How to do this?
Assume the following project structure and use-case:
project/
__init__.py
mytypes/
__init__.py
foo.py # contains the definition 'class Foo'
another_package/
bar.py
main.py
Inside main.py
and bar.py
I have from mytypes.foo import Foo
. After the replace operation detailed above I want both to use the new definition of Foo
from the replacement string, but no other definition from my string.
Upvotes: 0
Views: 969
Reputation: 32244
The short answer is: don't do this. You will run into all kinds of strange errors that you will not expect
You can use exec
to run some arbitrary code, if you pass a dictionary as the second argument the resulting "globals" from the executed string will be stored in the dictionary
namespace = {}
exec('class Foo:\n x = 10', namespace)
namespace['Foo'] # This will be a class named Foo
You could then assign this to the module
import your_module
your_module.Foo = namespace['Foo']
Now anywhere that your_module.Foo
is accessed you will get the class from your string.
However, your module may have been imported at some time before you have patched it, it's very difficult to be able to say for certain when your module will be imported. Someone may have bound Foo
using from your_module import Foo
, if this has run before your patch then you will not change this Foo
class. Even if you only ever access your_module.Foo
, if an instance has been initialised before your patch then any subsequent instances will not even have the same type!
f = your_module.Foo()
# run your patch
isinstance(f, your_module.Foo) # False
In the case above f
is an instance of a completely different type to the current your_module.Foo
Upvotes: 2