问题
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 dict
s 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