Design your object model based on making the concepts make sense, not based on what seems easiest to implement.
If, in your application, hydrogen atoms are a different type of thing than oxygen atoms, then you want to have a Hydrogen
class and an Oxygen
class, both probably subclasses of an Element
class.*
If, on the other hand, there's nothing special about hydrogen or oxygen (e.g., if you don't want to distinguish between, say, oxygen and sulfur, since they both have the same valence), then you don't want subclasses.
Either way, you can create multiple instances. It's just a matter of whether you do it like this:
atoms = [Hydrogen(), Hydrogen(), Oxygen(), Oxygen()]
… or this:
atoms = [Element(1), Element(1), Element(-2), Element(-2)]
If your instances take a lot of arguments, and you want a lot of instances with the same arguments, repeating yourself like this can be a bad thing. But you can use a loop—either an explicit statement, or comprehension—to make it better:
for _ in range(50):
atoms.append(Element(group=16, valence=2, number=16, weight=32.066))
… or:
atoms.extend(Element(group=16, valence=2, number=16, weight=32.066)
for _ in range(50))
* Of course you may even want further subclasses, e.g., to distinguish Oxygen-16, Oxygen-17, Oxygen-18, or maybe even different mixtures, like the 99.762% Oxygen-16 with small amounts of -18 and tiny bits of the others that's standard in Earth's atmosphere, vs. the different mixture that was common millions of years ago…