pythonclassinstanceinstance-variablesclass-variables

Declare allowed instance variables in class definition?


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.)


Solution

  • 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: