开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜