Python dynamic class name creation - python

I have the following setup:
test.py
test\
__init__.py
abstract_handler.py
first_handler.py
second_handler.py
first_handler.py and second_handler.py contain classes with the same names that inherit from abstract_handler.
What I want to do in test.py is: given a string containing "first_handler" or any other handler class, create an object of that class.
Most solutions I found assume that the classes are in the same module (test.py), I don't know how to dynamically import the specific required class.

Use the __import__ for importing. Note that if you use submodules, you have to specify the fromlist, otherwise you get the top-level module instead. Thus
__import__('foo.bar', fromlist=['foo']).__dict__['baz_handler']()
Will call foo.bar.baz_handler()

Use a dictionary for this sort of dispatching.
import first_handler
import second_handler
dispatch_dict = {
'first': first_handler.FirstHandler
'second': second_handler.SecondHandler
}
Now, assuming your choice is in choice_string:
instance = dispatch_dict[choice_string]()

You could probably do something like this:
from first_handler import SameName as handler1
from second_handler import SameName as handler2
handlers = {'UniqueName1': handler1,
'UniqueName2': handler2}
instance = handlers['UniqueName1']()

This does the trick:
import abstract_handler
import first_handler
import second_handler
output = globals()['first_handler']()

A broad answer to the question.
To dynamically import use __import__(string) and then you'll find all the objects in .__dict__
This way you can instance based on a strings like:
c = __import__('test.first_handler').__dict__['awesomeclassname']()

Related

How do I dynamically generate module contents in Python?

I know there are ways to perform dynamic import of Python modules themselves, but I would like to know if there's a way to write a module such that it can dynamically create its own module contents on demand. I am imagining a module hook that looks something like:
# In some_module.py:
def __import_name__(name):
return some_object
Such that if I were to write from some_module import foo in a script, Python will call some_module.__import_name__("foo") and let me dynamically create and return the contents.
I haven't found anything that works like this exactly in the documentation, though there are references to an "import protocol" with "finders" and "loaders" and "meta hooks" and "import path hooks" that permit customization of the import logic, and I imagine that such a thing is possible.
I discovered you can modify the behavior of a Module from within itself in arbitrary ways by setting sys.modules[__name__].__class__ to a class that implements whatever your chosen behavior.
import sys
import types
class DynamicModule(types.ModuleType):
# This function is what gets called on `from this_module import whatever`
# or `this_module.whatever` accesses.
def __getattr__(self, name):
# This check ensures we don't intercept special values like __path__
# if they're not set elsewhere.
if name.startswith("__") and name.endswith("__"):
return self.__getattribute__(name)
return make_object(name)
# Helpful to define this here if you need to dynamically construct the
# full set of available attributes.
#property
def __all__(self):
return get_all_objects()
# This ensures the DynamicModule class is used to define the behavior of
# this module.
sys.modules[__name__].__class__ = DynamicModule
Something about this feels like it may not be the intended path to do something like this, though, and that I should be hooking into the importlib machinery.

Python import all * from dynamically created module

I have found many variations for importing dynamically created/named modules by reference to their names as text, but all import the module as a whole and do not seem to facilitate importing all * ....
In my case, the objects within the file are dynamically created and named, so their identities cannot be discovered beforehand.
This works, but is there a better way perhaps using importlib ?
PREFIX = "my_super_new"
active_data_module = "{0}_data_module".format(PREFIX)
exec("from {0} import *".format(active_data_module))
You could use vars with the module. This would return a dictionary of all attributes on the module (I think). Then you can assign the dictionary to the globals dictionary to make it accessible in the current module:
import importlib
PREFIX = "my_super_new"
active_data_module = "{0}_data_module".format(PREFIX)
module = importlib.import_module(active_data_module)
globals().update(vars(module))
Using Peter Wood's answer, I created a small utility function:
import importlib
def import_everything_from_module_by_name(module_name):
globals().update(vars(importlib.import_module(module_name)))
modules_for_import = [
module_a,
module_b,
module_c
]
for module_name in modules_for_import:
import_everything_from_module_by_name(module_name)

Use string to specify `from my_package import my_class as my_custom_name`

I'd like to make the following line dynamic :
from my_package import my_class as my_custom_name
I know how to dynamically import modules via string
import importlib
module_name = "my_package"
my_module = importlib.import_module(module_name)
as suggested here. However it still doesn't let me specify the class I want to import (my_class) and the alias I want to assign to the class name (my_custom_name). I'm using python 3.6
Two steps. Number one, you can reference a module directly using importlib:
importlib.import_module('my_package.my_module') # You can use '.'.join((my_package, my_module))
Your class will be contained in the module itself as an attribute, as in any import. As such, just use
my_custom_name = importlib.import_module('my_package.my_module').__dict__['my_class']
or even better
my_custom_name = getattr(importlib.import_module('my_package.my_module'), 'my_class')

Python import errors

I've written a basic program with a couple of classes, and I've had two issues I would like help with. All of the files are in the same directory, and my classes are in files with the same name as the class.
First, my class files can only import with the format
from module import class
I can't use the format
import module
Second, I've only been able to use my classes if I do the import inside of main. When I import at the beginning of the file, I get an unboundlocalerror when creating an object. I've had these issues (especially the 1st one) on more than one program. Any ideas?
Thanks!
You cannot, as you found out, use
import class
You either have to use
from module import class
And you'd call the class simply as
class # note you don't have the module namespace
Or if you'd like to keep the namespace (which I'd recommend)
import module
Then you can say
module.class
module.otherclass
...etc
As you found, you cannot just type:
import class
as that would lead python to believe that you wanted to import a module named class, when what you want is the class inside the module. That is why
from module import class
does work, as it shows python where 'class' is.

What is the Python syntax for importing the entire contents of a file?

I'm looking to import all the classes from one Python file to the other?
In the class you wish to import from, include a variable called __all__, and fill it with the names of the classes/variables you want.
__all__ = ['Class1', 'Class2', 'variable_i_want']
In the class you wish to import them to, you may use the asterisk to gain access to all of the classes.
from foo import *
As suggested, be careful of name collisions when doing this.
Just import the file like any other
import mythings
Then you can use
myClass = mythings.MyClass()
In addition to what the other people are saying, the file you are importing must exist somewhere in sys.path. (usually your current directory is in there, so same directory imports are no problem) For example, if you want to import from your parent directory:
#want to import ../myotherfile.py
import os
import sys
sys.path.append(os.path.abspath(os.pardir))
import myotherfile
print(myotherfile.func())
from module import *
You must be careful when doing this as you can get name collisions.

Categories

Resources