Multiple Instances of a Python Object are acting like the same instance

狂风中的少年 提交于 2019-12-12 02:06:59

问题


I have my class template here:

 import sqlite3

class Patron(object):
    #Let's set some basic attributes
    attributes = { "patron_id" : None,
    "name" : None,
    "address" : None,
    "phone" : None,
    "email" : None,
    "fee_balance" : None,
    "fees_per_day" : None,
    "books_checked_out" : [],
    "books_overdue" : []}

    def __init__(self):
        #Create a empty instance
        pass

    def new(self, patron_id, name, address, phone, email):
        #Create an instance with new values
        self.attributes["patron_id"] = patron_id
        self.attributes["name"] = name
        self.attributes["address"] = address
        self.attributes["phone"] = phone
        self.attributes["email"] = email

    def retrieve(self, patron_id):
        #Connect to database and prepare patron id
        self.attributes["patron_id"] = patron_id
        patron_database = sqlite3.connect('patrons.db')
        cursor = patron_database.cursor()
        t = (str(patron_id),)

        #Get data from database
        cursor.execute("SELECT * FROM patrons WHERE id =?", t)
        data = cursor.fetchone()

        #Now close your database connection
        patron_database.close()

        #Parse tuple into attributes
        self.attributes["name"] = data[1]
        self.attributes["address"] = data[2]
        self.attributes["phone"] = data[3]
        self.attributes["email"] = data[4]
        self.attributes["fee_balance"] = data[5]
        self.attributes["fees_per_day"] = data[6]
        self.attributes["books_checked_out"] = data[7]
        self.attributes["books_overdue"] = data[8]

    def save(self):
        #Connect to the database
        patron_database = sqlite3.connect('patrons.db')
        cursor = patron_database.cursor()

        #Compile the data into a list
        attributes = []
        for value in self.attributes.itervalues():
            attributes.append(value)

        #Insert the values and save them
        cursor.execute("INSERT INTO patrons VALUES(?,?,?,?,?,?,?,?,?)", attributes)
        patron_database.commit()

        #Close the connection
        patron_database.close()

and then I have my test code here:

'''
Created on Feb 2, 2013

@author: Zach
'''
from Patron import Patron


zach = Patron()
braden = Patron()

zach.retrieve(1187277)

print zach.attributes
print braden.attributes

My console says that both the "zach" and "braden" instance have the exact same attributes, even though I have not set anything to the "braden" instance. If I assign something to the "braden" instance, then they both share the properties of that instance.

I think it's a problem related to mutable default argument behavior, but I can't figure out my problem.


回答1:


You have made attributes a class level variable and because dicts are mutable. Move it's definition inside of __init__ and it should work.

class demo(object):
    class_level = {'a': 0}
    class_level_nm = 0
    class_level2 = 0
    def __init__(self, v):
        self.instance_level = v 
        self.class_level['a'] += 1
        self.class_level_nm += 1
        demo.class_level2 += 1
    def __str__(self):
        return 'class level (mut): %d  class level (unmut): %d  instance level: %s  class level2: %d' % (self.class_level['a'],
                                                                                     self.class_level_nm,
                                                                                     self.instance_level,
    self.class_level2)

a = demo('a')
b = demo('b')

print a
print b

c = demo('c')

print a
print b
print c

Gives:

class level (mut): 2  class level (unmut): 1  instance level: a  class level2: 2
class level (mut): 2  class level (unmut): 1  instance level: b  class level2: 2
class level (mut): 3  class level (unmut): 1  instance level: a  class level2: 3
class level (mut): 3  class level (unmut): 1  instance level: b  class level2: 3
class level (mut): 3  class level (unmut): 1  instance level: c  class level2: 3



回答2:


This isn't directly the "mutable default argument" problem, since you have no default function arguments at all. The problem is just that you're not actually setting any attributes on zach and braden at all!

When you call zach.retrieve(1187277), retrieve executes this

self.attributes["patron_id"] = patron_id

You appear to have some misconceptions about how this works, so lets go through how Python will evaluate this statement step by step.

The first step necessary is to lookup self.attributes. This first looks for an attribute in self named attributes, but there is no such attribute.

When reading an attribute, this then falls back to looking in the class of self (and any base classes, but that's not relevant here). So the fall back is to look for an attribute named attributes in Patron. This succeeds and fins a dictionary, so that object is the result of the lookup.

The next step is to execute the "item assignment" operation on the result of the lookup. Item assignment is what the object[key] = value syntax does; in your case self.attributes is the object, "patron_id" is the key, and patron_id is the value. So this ends up setting the key "patron_id" to person_id in the dictionary being stored in the attributes attribute of the Patron class.

So then it's completely unsurprising that print zach.attributes and print braden.attributes show the same thing. Neither of them has an attributes attribute, so both are going to find the attributes attribute in the class Patron. And if you keep storing all your attributes by assigning to that dictionary, then obviously any change made in one will affect what you see from the other.



来源:https://stackoverflow.com/questions/14667465/multiple-instances-of-a-python-object-are-acting-like-the-same-instance

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!