Here's my code, hopefully self explanatory.
import os
import numpy as np
class MyApp:
def __init__(self, x, y, project_name):
'''default constructor'''
# Build Project if Non-Existent
if not os.path.exists(project_name):
os.makedirs(project_name)
# Attribute Arrays
self.arr1 = np.arange(x) # Dummy task based on x
self.arr2 = np.arange(y) # Dummy task based on y
# Dump Arrays
np.save(f'{project_name}/arr1.npy', self.arr1)
np.save(f'{project_name}/arr2.npy', self.arr2)
@classmethod
def from_project(cls, project_name):
'''load objects from project'''
# Check if project exists
if not os.path.exists(project_name):
raise FileNotFoundError(f'{project_name} missing')
# Now load arr1 and arr2
arr1 = np.load(f'{project_name}/arr1.npy')
arr2 = np.load(f'{project_name}/arr2.npy')
# And return an instance with self.arr1 and self.arr2 set
pass # ????
def task_A(self):
'''do some task based on arr1'''
return self.arr1.mean()
def task_B(self):
'''do some task based on both arr1 and arr2'''
return np.convolve(self.arr1, self.arr2)
# Init Object
app = MyApp(x=5, y=10, project_name='testing_tmp')
print(type(app)) # <class '__main__.MyApp'>
# Initally Tasks OK
print(app.task_A()) # 2.0
print(app.task_B()) # [ 0 0 1 4 10 20 30 40 50 60 70 70 59 36]
# No Tasks after Object Deletion
del app
try:
print(app.task_A()) # No execution
print(app.task_B()) # No execution
except:
pass
# Now want to instantiate object from project
app = MyApp.from_project(project_name='testing_tmp')
print(type(app)) # <class 'NoneType'>
The output is as follows:
<class '__main__.MyApp'>
2.0
[ 0 0 1 4 10 20 30 40 50 60 70 70 59 36]
<class 'NoneType'>
Is there a way to write a classmethod
that would read saved object attributes from file, and return an instance with the proper attributes set, as desired?
I understand I can save the x
and y
values to disk as well and use something like return cls(x=disk_x, y=disk_y, project_name=project_name)
but my real task would not permit that as objects created from x
and y
are rather expensive to compute, and I created and saved them to disk for later use for this very reason.
Editing for clarity: My goal is to use the from_project
method to return an instance of the class with the self.arr1
and self.arr2
attributes correctly set, without using the __init__()
method which requires setting x
and y
. Please see the from_project
method for details as to where I got clueless. I know how to serialize and deserialize objects and class attributes, it is not my concern.
I tried using the cls
attribute to the from_project
classmethod
to set cls.arr1
and cls.arr2
both, but it did not work.
Yes, I found the answer. The trick is to use the __new__
method for instantiation and bypass __init__
to then set the attributes and returning the instance. Here's the required method change to from_project
.
@classmethod
def from_project(cls, project_name):
'''load objects from project'''
# Check if project exists
if not os.path.exists(project_name):
raise FileNotFoundError(f'{project_name} missing')
# Now load arr1 and arr2
arr1 = np.load(f'{project_name}/arr1.npy')
arr2 = np.load(f'{project_name}/arr2.npy')
# And return an instance with self.arr1 and self.arr2 set
# First we use the __new__ method for instantiation
instance = cls.__new__(cls)
# Then we set attributes
instance.arr1 = arr1
instance.arr2 = arr2
# Return the instance
return instance