Python import that works with directory and package - python

I have two classes (in the same directory), one derived from the other.
ClasssA.py contains the following code:
class ClassA():
def __init__(self):
pass
ClasssB.py contains the following code:
from ClassA import ClassA
class ClassB(ClassA):
def __init__(self):
ClassA.__init__(self)
This works fine when I run scripts from the Python console.
I want to build these into a package, but when I do and try to instantiate ClassB, I get an error:
No module named 'ClassA'
How can I write the import statement and/or __init__.py so the code works in both scenarios.
Thanks for any suggestions.

1) Create a module named classA containing two files init.py(Empty file) and temp.py
temp.py
class ClassA():
def __init__(self):
print('ClassA')
2) ClassB.py
from ClassA.temp import ClassA
class ClassB(ClassA):
def __init__(self):
super.__init__()
All this should in same folder

Use from filename import ClassA to indicate which file in the directory you are importing from.

Related

Register classes in different files to a Class factory

I am trying to register classes that are in different files to the factory class. The factory class has a dictionary called "registry" which hold/maps the a user defined name to the registering class. My issue is that if my factory class and registering classes are in the same .py file everything works as expected but the moment I move the registering classes into their own .py files and import the factory class to apply the register decorator (as described in the question & article below) the "registry" dictionary stays empty, which means that the classes are not getting registered.
They way I am registering these classes is via a decorator. My code looks very much like what we see here:
Registering classes to factory with classes in different files (my question is a duplicate of this, but bumping this question to the top)
https://medium.com/#geoffreykoh/implementing-the-factory-pattern-via-dynamic-registry-and-python-decorators-479fc1537bbe
I would like to know:
What why keeping them in the same file work while splitting them out doest
How can I make the separate file approach work ?
Hopefully the code samples in the articles clarify what I am trying to do and struggling with.
I'm currently exploring a similar problem, and I think I may have found a solution. It is a bit of a 'hack' though, so take it with a grain of salt.
What why keeping them in the same file work while splitting them out doest
In order to make your classes self-register in the factory while keeping their definition in single .py files, we have to somehow force the loading of the classes in the .py files.
How can I make the separate file approach work?
In my case, I've came across this problem when trying to implement a 'Simple Factory', with self-registering subclasses to avoid having to modify the typical 'if/else' idiom in the factory's get() method.
I'll use a simple example, starting with the decorator method you've mentioned.
Example with decorators
Let's say we have a ShoeFactory as shown below, in which we register different 'classes' of shoes:
# file shoe.py
class ShoeFactory:
_shoe_classes = {}
#classmethod
def get(cls, shoe_type:str):
try:
return cls._shoe_classes[shoe_type]()
except KeyError:
raise ValueError(f"unknown product type : {shoe_type}")
#classmethod
def register(cls, shoe_type:str):
def inner_wrapper(wrapped_class):
cls._shoe_classes[shoe_type] = wrapped_class
return wrapped_class
return inner_wrapper
Examples of shoe classes:
# file sandal.py
from shoe import ShoeFactory
#ShoeFactory.register('Sandal')
class Sandal:
def __init__(self):
print("i'm a sandal")
# file croc.py
from shoe import ShoeFactory
#ShoeFactory.register('Croc')
class Croc:
def __init__(self):
print("i'm a croc")
In order to make Sandal self-register in the ShoeFactory while keeping its definition in a single .py file, we have to somehow force the loading of the Sandal class in .py file.
I've done this in 3 steps:
Keeping all class implementations in a specific folder, e.g., structuring the files as follows:
.
└- shoe.py # file with the ShoeFactory class
└─ shoes/
└- __init__.py
└- croc.py
└- sandal.py
Adding the following statement to the end of the shoe.py file, which will take care of loading and registering each individual class:
from shoes import *
Add a piece of code like the snippet below to your __init__.py within the shoes/ foder, so that to dynamically load all classes [1]:
from inspect import isclass
from pkgutil import iter_modules
from pathlib import Path
from importlib import import_module
# iterate through the modules in the current package
package_dir = Path(__file__).resolve().parent
for (_, module_name, _) in iter_modules([package_dir]):
# import the module and iterate through its attributes
module = import_module(f"{__name__}.{module_name}")
for attribute_name in dir(module):
attribute = getattr(module, attribute_name)
if isclass(attribute):
# Add the class to this package's variables
globals()[attribute_name] = attribute
If we follow this approach, I get the following results when running some test code as follows:
# file shoe_test.py
from shoe import ShoeFactory
if __name__ == "__main__":
croc = ShoeFactory.get('Croc')
sandal = ShoeFactory.get('Sandal')
$ python shoe_test.py
i'm a croc
i'm a sandal
Example with __init_subclass__()
I've personally followed a slighly different approach for my simple factory design, which does not use decorators.
I've defined a RegistrableShoe base class, and then used a __init_subclass__() approach to do the self-registering ([1] item 49, [2]).
I think the idea is that when Python finds the definition of a subclass of RegistrableShoe, the __init_subclass__() method is ran, which in turn registers the subclass in the factory.
This approach requires the following changes when compared to the example above:
Added a RegistrableShoe base class to the shoe.py file, and re-factored ShoeFactory a bit:
# file shoe.py
class RegistrableShoe():
def __init_subclass__(cls, shoe_type:str):
ShoeFactory.register(shoe_type, shoe_class=cls)
class ShoeFactory:
_shoe_classes = {}
#classmethod
def get(cls, shoe_type:str):
try:
return cls._shoe_classes[shoe_type]()
except KeyError:
raise ValueError(f"unknown product type : {shoe_type}")
#classmethod
def register(cls, shoe_type:str, shoe_class:RegistrableShoe):
cls._shoe_classes[shoe_type] = shoe_class
from shoes import *
Changed the concrete shoe classes to derive from the RegistrableShoe base class and pass a shoe_type parameter:
# file croc.py
from shoe import RegistrableShoe
class Croc(RegistrableShoe, shoe_type='Croc'):
def __init__(self):
print("i'm a croc")
# file sandal.py
from shoe import RegistrableShoe
class Sandal(RegistrableShoe, shoe_type='Sandal'):
def __init__(self):
print("i'm a sandal")

Avoid duplicate name when importing a sub-module with only one public member from a package

Basic Setup
Suppose I want to create a class named Foo. I may create a file like so:
foo.py:
class Foo:
def __init__(self):
self.data = "world"
def print(self):
print("Hello, " + self.data)
To utilize this class in my main script:
main.py
import foo
test = foo.Foo()
test.print()
Having to type foo.Foo() every time I instantiate the class already feels ridiculous enough, but it gets worse when I want to organize my code by separating my classes into a package:
classes/__init__.py
# Empty
classes/foo.py
# Copy of foo.py, above
main.py
import classes.foo
test = classes.foo.Foo()
test.print()
Simple Answer
I know I can clean this up somewhat by using from X import Y like so:
from classes.foo import Foo
test = Foo()
Preferred Answer
Because the file foo.py contains only one member whose name matches the file, I would prefer if I could do something like the following:
from classes import Foo
# Or:
import classes.Foo as Foo
test = Foo()
Is there a way to do this? Maybe with some code in my __init__.py?
In classes/__init__.py, put:
from .foo import Foo
Now you can write from classes import Foo.

Sharing a global object across files with circular dependencies

I have a global object which uses a class, and that class uses the global object. How can i put the imports correct in a clean way
I now have:
run.py (The file i run)
from global_class import Global_class
global_object = Global_class()
global_object.create_some_object()
global_class.py
from some_class import Some_class
class Global_class:
def __init__(self):
self.name = 'my_name'
def create_some_object(self):
self.some_object = Some_class()
some_class.py
class Some_class:
def __init__(self):
print(global_object.name)
How can i now access global_object in Some_class? If i put:
from run import global_object
It creates a circular dependency, and it crashes. A possible method i thought of was putting the some_class import in the Global_class::create_some_object() method, but it seems to me as unclean code. Is there any better way
Any python import module or from module import Class statement runs corresponding module line by line and loads all the objects in the module namespace in the memory. However each of the names in the modules reside separately (that is the purpose of the modules after all). So a global_object in some_class.py is completely separate from the global_object in run.py. When the interpreter sees this name in some_class.py it will look in the local and global namespace (using the LEGB rule which stands for local, enclosed, global and builtins). But there is no reference to global_object exists here, it does in the calling module. Your suggestion of putting the some_class import statement inside the method create_object() will also not work for the same reason. As you have found out you cannot import global_object in some_class as it will again need to run the run.py thus creating a loop.
If you want to maintain this setup then one option would be to explicitly pass the global_object which is self in Global_class to the Some_class() constructor like below
#run.py
from global_class import Global_class
global_object = Global_class()
global_object.create_some_object()
#global_class.py
from some_class import Some_class
class Global_class:
def __init__(self):
self.name = 'my_name'
def create_some_object(self):
self.some_object = Some_class(self) #self -> global_object
#some_class.py
class Some_class:
def __init__(self, global_object):
print(global_object.name)
$ python run.py
my_name

Inheriting a class with the same name in Python

I am new in Python and I am trying to create two classes with the same name in two different source files. Let’s call them "Main.py" and "Extension.py". The class is "MyClass". MyClass in Extesntion.py is derived from MyClass in file Main.py. If it works then when I create an object myclass and I import Extension in my code, then I would have more functions in comparison with file Main.py.
File Main.py
class MyClass:
def __init__(self):
Initialize something
def foo1(self, a, b):
Do something
Then extension would be like this:
File Extensions.py
import Main
class MyClass(MyClass):
def __init__(self):
Initialize something
def foo2(self, a, b):
Do something
def foo3(self, a, b):
Do something
And then if I have code like this. I expect that I can't use foo2 and foo3.
import Main
myclass = MyClass()
myclass.foo1(a, b)
And finally if I have code like this. I expect that I use all the functions.
import Extension
myclass = MyClass()
myclass.foo1(a, b)
myclass.foo2(a, b)
myclass.foo3(a, b)
If you do
import main
you'll need to use main.MyClass to create an object from main.py.
Instead you can do
from main import MyClass
to have it available directly.
If you need two different classes with the same name, you can instead do
from main import MyClass as MainClass
and you'll have the class available under the name MainClass
Unless you do from Extension import *, you'll need to specify the module in order to access the class.
import Main
import Extension
foo = Main.MyClass()
bar = Extension.MyClass()
If you don't want to have to specify the module, then the only way to avoid a name collision is to import the class under a different name like so:
from Main import MyClass as ClassA
It's quite easy when you explicitly import the given name using the from {module} import {name} syntax.
File main.py
class MyClass:
def __init__(self):
pass
def foo1(self, a, b):
pass
File extensions.py
from main import MyClass
class MyClass(MyClass):
def __init__(self):
pass
def foo2(self, a, b):
pass
def foo3(self, a, b):
pass
File client_main.py
from main import MyClass
myinstance = MyClass()
myinstance.foo1(a, b)
File client_extensions.py
from extensions import MyClass
myinstance = MyClass()
myinstance.foo1(a, b)
myinstance.foo2(a, b)
myinstance.foo3(a, b)
Generally in this case, you would do an import as. This allows you to alias your import as a new name. So in the file where your second class is, import the first class as:
from main import MyClass as MainMyClass
Then when doing your inheritance, refer to MainMyClass:
class MyClass(MainMyClass):

Define an object as 'root' of module

I have a module module.py
class SomeClass():
def __init__(self):
self.var='123'
def printit(self):
print self.var
And now I'm trying to import this module into script.py and call the method printit from the class SomeClass
import module
module.SomeClass().printit()
I also can do it by another way:
from module import SomeClass
SomeClass().printit()
And another one:
from module import SomeClass as module
module().printit()
It's nice but i want to get something like this:
import module
module().printit()
or even
import module
SomeClass().printit()
Generally I want to make a module that will export SomeClass by default. Is it possible to make something like this by changing module.py?

Categories

Resources