Reputation: 955
Here's my example code:
#!/usr/bin/env python3
LIST_OF_UNITS = {}
class Unit():
def __init__(self,name, value):
self.name = name
self.value = value
def create_new_unit(name, value):
return Unit(name, value)
def add_new_unit(d, name, value):
d[name] = Unit(name, value)
return d
unit = create_new_unit('reactor1', 1)
LIST_OF_UNITS[unit.name] = unit
unit = create_new_unit('reactor2', 2)
LIST_OF_UNITS[unit.name] = unit
LIST_OF_UNITS = add_new_unit(LIST_OF_UNITS, 'reactor3', 3)
print(LIST_OF_UNITS)
LIST_OF_UNITS = add_new_unit(LIST_OF_UNITS, 'reactor3', 4)
print(LIST_OF_UNITS)
As you can see I have two ways of adding objects to the dictionary. Not yet sure which is the better. One may be more flexible for solving my problem. So, I've included them both.
I want to build a list of reactors and their properties.
For each reactor I create an object that will eventually contain the properties of that reactor (like it's volume, operation start and end times,etc.)
I'd like to prevent the (duplicate) creation of a unit. In the example the creation of 'reactor3' with value 4 should be avoided.
What would be the best way to do that. Inside the class, using one of the methods or somehow else?
Your insights are greatly appreciated.
Upvotes: 0
Views: 2013
Reputation: 51673
If you change your code around some, you can store all created Unit
s as classvariable inside Unit
. The factory-methods shoult be classmethods and will auto-add/create your instances to it.
class Unit():
UNITS = {} # shared btw. instances
def __init__(self, name, value):
self.name = name
self.value = value
# nicer output
def __repr__(self): return "{} - {}".format(self.name, self.value)
def __str__(self): return repr(self)
# this should be a classmethod instead, depending on your usage you might want to
# raise Errors instead of returning existing instances
def create_new_unit(name, value):
# create if needed, else return the one already in
# does not alter Unit.value if present
u = Unit.UNITS.setdefault(name, Unit(name,value))
if u.value != value:
raise ValueError("Unit '{}' exists with different value".format(name))
else:
return u
# this should be a classmethod instead, depending on your usage you might want to
# raise Errors instead of returning existing instances def add_new_unit(name, value):
# create new unit or alter an existing Unit's value
# you should rename the method accordingly
u = Unit.UNITS.setdefault(name, Unit(name,value))
u.value = value # change it if called again
return Unit.UNITS
unit1 = create_new_unit('reactor1', 1)
unit2 = create_new_unit('reactor2', 2)
all_units = add_new_unit('reactor3', 3)
for u in Unit.UNITS:
print(id(Unit.UNITS[u]),Unit.UNITS[u])
all_units = add_new_unit('reactor3', 4)
for u in Unit.UNITS:
print(id(Unit.UNITS[u]),Unit.UNITS[u])
Output:
140125186245968 reactor1 - 1
140125186246024 reactor2 - 2
140125186246080 reactor3 - 3
140125186245968 reactor1 - 1
140125186246024 reactor2 - 2
140125186246080 reactor3 - 4 # changed by add_new_unit
# if create_new_unit(..) same named unit again with different value:
# ValueError: Unit 'reactor2' exists with different value
Personally I would advice against creating multiple ways to instantiate new ones. And I would probably put the "factory methods" as @classmethods and not inside the normal program. That way all the housekeeping of Unit
s is done by the
Unit
class itself, and you can centralize the logic where it belongs instead of having to add created Units inside your main program.
Suggested read for @classmethod
: Meaning of @classmethod and @staticmethod for beginner?
Upvotes: 1
Reputation: 2910
Just make check if the item is already in the keys of the dictionary. Insert only if not already there.
def add_new_unit(d, name, value):
if(name in d.keys()):
print("The reactor information for {name} already recorded!".format(name = name))
return d
d[name] = Unit(name, value)
return d
Upvotes: 1
Reputation: 736
If you add an entry with the same key to the dictionary, the item will be overwritten so you will lose 1 of the entries.
If you want to avoid that, you can check if the name is already in the key values of the dictionary.
How about this?
if name in LIST_OF_UNITS.keys():
# raise an error
else:
pass
Upvotes: 0