unexplainable python dict problem
hey all, i been trying to make a class that uses a dictionary to construct a kind of table but something extremely weird is happening.. heres my code
class dbase:
def __init__(self):
self.rows = {}
self.cols = {}
def addrow(self, name):
self.rows[name] = self.cols
def addcol(self, name):
for x in self.rows:
self.rows[x][name] = None
def printi开发者_开发技巧t(self):
for x in self.rows:
print x, self.rows[x]
a = dbase()
a.addrow("coke")
a.addcol("price")
a.printit()
a.addrow("sprite")
a.printit()
ok heres the weird thing. my program prints the sprite row as having a inner dictionary with a "price" value but no where in my program did i say self.cols["price"] = None so howcome the addrow function for sprite puts this inner dictionary into it? thanks for any help
Wow. This is the messiest code I've seen in a while. You realize that when you add a row, you're just adding the same dictionary that every other column has.
def __init__(self):
self.rows = {}
self.cols = {}
def addrow(self, name):
self.rows[name] = self.cols
I think you meant
def addrow(self, name):
self.rows[name] = {}
Every value in self.rows
is assigned self.cols
, so they share the same dictionary as a key. If you modify self.rows[x]
, then you also modify self.rows[y]
, because they are the same object. Similarly, if you then re-add self.cols
as the value for self.rows[z]
, it has all the same contents, because it's still the same object.
If you wanted to make a separate empty dict for the row each time, then do that: assign {}
.
But you really don't need a class for this in the first place; it's just pushing you into using a custom interface for something that's naturally done directly in Python. You should probably also be looking into collections.defaultdict
.
When you call a.addcol("price")
the code modifies self.rows[x][name]
, setting it equal to None
.
self.cols
is thus set to equal the dict {'price': None}
. Since each self.rows[x]
is set equal to self.cols
, you get the same dict printed each time.
When you set up the columns for a row, you always refer to self.cols
- because Python handles this like a reference, anytime that you update it you update it for everything that points to that reference.
You should initialize it to an appropriate value each time if you expect a different set of columns for each row.
You're reusing the same dictionary instance all the time.
def addrow(self, name):
self.rows[name] = self.cols
Remember that Python is similar like Java when it comes to variables - each name is just a reference to an object instance. It's not like in C where variable assignment almost always means copying the value.
If you want to create a quick-n-dirty table class for rows and columns, you could make use of defaultdict
, for example:
from collections import defaultdict
class RowsAndColumns:
def __init__(self):
self._rows = defaultdict(dict)
def get(self, row, col):
return self._rows[row][col]
def set(self, row, col, value):
self._rows[row][col] = value
matrix = RowsAndColumns()
matrix.set("Coke", "Price", 1.99)
print matrix.get("Coke", "Price") # 1.99
print matrix.get("Pepsi", "Price") # KeyError "Price"
The easiest way to do this is to just have a list of dictionaries. Like this:
# A new "database"
dbase = []
# Adding a new "row".
dbase.append({})
# Adding columns to a specific row:
dbase[0]['newcol'] = "The value"
# Retrieving a colum from a row which will raise a KeyError if the column doesn't exist:
dbase[0]['newcol']
# Retrieving a colum from a row which will return None if the column doesn't exist:
dbase[0].get('anothercol')
Also you could look at the DefaultDict, but I think it's better to learn how standard dictionaries and objects work first.
精彩评论