I'm looking to use class objects to store data from multiple simulations and save them in a list, each entry in the list a new instance of the class). I'd like to ensure that each instance has exactly the same attributes (variables), but would like to assign them dynamically as the program runs - not all at the same time when the new instance is created.
Some suggestions to do that (what I'd use a structure for in C) are here, but if using a native class (preferred option over external modules or dictionary for simplicity/readability), I don't see a way to make sure that each instance has exactly the same attributes yet they are populated at different times. Please tell me if there's a solution for this.
Don't want to use the constructor below because the attributes would all have to be populated at once - then I guess I'd have to create the object at the end of the simulation but would have to definite additional variables to store the data in the meantime. Also this is not great because I have a large number of attributes and the argument in the brackets would be very long.
simulations = []
class output_data_class:
def __init__(self, variable1, variable2):
self.variable1 = variable1
self.variable2 = variable2
# simulation, generates the data to store in variable1, variable2
variable1 = 'something' # want to avoid these interim variables
variable2 = 123 # want to avoid these interim variables
new_simulation = output_data_class(variable1, variable2) # create an object for the current simulation
simulations.append(new_simulation) # store the current simulation in the list
Right now I'm using something like this:
simulations = []
class output_data_class:
pass
new_simulation = output_data_class() # create an object for the current simulation
# simulation, generates the data to store in variable1
new_simulation.variable1 = 'something'
# another part of simulation, generates the data to store in variable2
new_simulation.variable2 = 123
simulations.append(new_simulation) # store data from current simulation
This allows me to add the data as they are produced during the simulation (can be things like an array of data, then something calculated from that array etc.) My gut feeling is that the above is bad practice - it isn't immediately clear what the instance attributes are supposed to be, and it doesn't protect against creating totally new attributes due to typos etc (example below). I'd like to impose that each instance must have the same attributes.
new_simulation.variabel2 = 123
Note the typo above - this would create a new variable specifically for this instance, right?
I would like to be able to declare the admissible attributes (including their type if possible) in the class definition, but obviously not as class variables as I need to populate them separately for each instance. (And to reiterate, not in the innit method because then I believe I'd have to populate all the attribute at once.)
I would like to be able to declare the admissible attributes (including their type if possible) in the class definition, but obviously not as class variables as I need to populate them separately for each instance. (And to reiterate, not in the __init__ method because then I believe I'd have to populate all the attribute at once.)
It sounds like you could use dataclasses.
Python objects support an attribute called __slots__
. The actual purpose of __slots__
is to save memory, but they can also be used to forbid access to variables not specifically declared by the class. More information.
So you could implement your idea like this:
from dataclasses import dataclass
@dataclass(slots=True, init=False)
class Foo:
bar: int
baz: str
f = Foo()
f.bar = 10
f.baz = 'a string'
f.qux = 'another string' # This causes an error because it's not in __slots__
Explanations:
slots=True
argument to the dataclass decorator causes the dataclass to generate a __slots__
attribute.__init__
method which requires you to specify values for every member of that dataclass. But with init=False
, you can turn this behavior off, and the dataclass starts uninitialized.