It seems you need a centralized place to store your data which can be accessed by any number of different objects (Qt objects, numpy objects, it makes no difference). My suggestion is the Singleton pattern. I'll make a small experiment using Alex Martelli Borg implementation but check this resource (Python 3 Patterns, Recipes and Idioms) to see a few different examples.
I think the easiest way to explain a Singleton is the following: when you instantiate the same object multiple times (for instance a QWidget), each instance will refer to a different object. So if you make a change in one instance it will not affect the others (generally speaking). The Singleton works differently. Every single instance you make refers to the same object. Check the following example:
import numpy as np
class Singleton:
"""Alex Martelli implementation of Singleton (Borg)
http://python-3-patterns-idioms-test.readthedocs.io/en/latest/Singleton.html"""
_shared_state = {}
def __init__(self):
self.__dict__ = self._shared_state
class Database(Singleton):
def __init__(self):
Singleton.__init__(self)
def get(self):
return self._data
def change(self):
# Just arbitrary experiment of changing the data
self.load()
def load(self):
# For example from csv or binary files using
# np.genfromtxt or np.fromfile
self._data = np.random.randint(0, 10, (3, 3))
With the code above I've just created my "Database" object. Every time I call this database and ask for its data it will return me the same. Notice how I'm making a randomized numpy array as data. Let's say I create two new objects:
class SomeObject:
def __init__(self):
self._something = None
def doSomething(self):
db = Database()
print(db.get())
class OtherObject:
def __init__(self):
self._othersomething = None
def doOtherSomething(self):
db = Database()
print(db.get())
Both call an instance of the Database. But will they refer to the same data? Lets check:
# Loading data into Singleton
db = Database()
db.load()
# Creating a couple of different objects
so = SomeObject()
oo = OtherObject()
# Making sure each object is calling the database
print("Original data in database:")
so.doSomething()
oo.doOtherSomething()
# Changing data in database
db.change()
# Checking the changes in both objects.
print("Changed data in database:")
so.doSomething()
oo.doOtherSomething()
The result is this:
Original data in database:
[[7 4 7]
[3 4 1]
[9 5 6]]
[[7 4 7]
[3 4 1]
[9 5 6]]
Changed data in database:
[[3 8 8]
[7 2 8]
[1 5 1]]
[[3 8 8]
[7 2 8]
[1 5 1]]
So both objects, creating their own instances of Database, obtain exactly the same data (which is randomized at the call of the load or change method). This is probably the most approachable (and maintainable) way of sharing data among different objects.
EDIT: To enable the database to understand if data has been loaded of not. Let's make a small modification to our Database class by adding the "hasData" method:
class Database(Singleton):
def __init__(self):
Singleton.__init__(self)
def get(self):
return self._data
def change(self):
# Just arbitrary experiment of changing the data
self.load()
def hasData(self):
return hasattr(self, "_data")
def load(self):
# For example from csv or binary files using
# np.genfromtxt or np.fromfile
self._data = np.random.randint(0, 10, (3, 3))
This method is asking if Database has already the attribute _data
or not. Let's make an experiment:
db = Database()
print(db.hasData())
db.load()
print(db.hasData())
Which results in:
False
True
Other variations could use the very first instantiation to load the data. This will depend greatly on the needs of your software.