The underlying problem here is that you're not using the dictionary right. Instead of adding the new employee to the existing global employee_dict
, you're trying to replace that global dict with a new one, containing just the new employee:
def employee_dictionary(self):
employee_dict = {self.id: self}
If you fix this, the problem you're actually asking about won't even come up:
def employee_dictionary(self):
employee_dict[self.id] = self
This will add a new mapping from self.id
to self
in the dict. So, after your two Employee
constructions, with IDs 1 and 2, you'll end up with two entries in the dict, for keys 1
and 2
, and everything will just work.
Also, you should definitely at least consider two other changes:
- Replace the global variable with a class attribute, and possibly also replace the
employee_dictionary
method with a class method, as detailed in scharette's answer.
- Rename the method from
employee_dictionary
to something (a) marked private (methods starting with _
are private by convention, meaning your users know they aren't supposed to be calling it unless they have a weird use case), and (b) more reflective of what it does. Maybe _register
or _add_to_dict
?
The first one of these would also (as, again, detailed in scharette's answer) have made the problem you're asking about go away. (But you still need the main fix anyway.)
But you probably want to understand the more immediate scope problem anyway—and how to solve it when you can't just make it go away.
In Python, any name that you assign to in a function is a local variable. If there's a spam = …
anywhere in the function (or a with eggs as spam:
or certainly other kinds of things that also count as assignment), every reference to spam
in that function is to that local. So, employee_dict = {self.id: self}
creates a local variable named employee_dict
, assigns a value to it, and then returns, at which point all the locals go away. The fact that it happens to have the same name as a global doesn't mean anything to Python (although to a human reader, like you, it's obviously confusing).
Any name that you use without assigning to it anywhere is a local-or-enclosing-or-global-or-builtin variable. When you do employee_dict[self.id]
, because there's no employee_dict = …
anywhere, Python searches the local, enclosing, global, and builtin scopes to find what you meant by employee_dict
, and it finds the global.
You can force Python to treat a name as a global variable, even if you assign to it, with a global
statement at the top of the function:
def employee_dictionary(self):
global employee_dict
employee_dict = {self.id: self}
Adding global
is safe even if the name would already be a global. This is usually pointless—but if you're not sure whether something counts as an assignment (or just not sure future readers of your code would be sure…), and you want to make it clear that the variable is a global, you can declare it:
def employee_dictionary(self):
global employee_dict
employee_dict[self.id] = self