Python对象的多个实例的行为与同一个实例类似

Python对象的多个实例的行为与同一个实例类似,python,arguments,default,behavior,mutable,Python,Arguments,Default,Behavior,Mutable,我在这里有我的类模板: 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_da

我在这里有我的类模板:

 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()
然后我在这里有我的测试代码:

'''
Created on Feb 2, 2013

@author: Zach
'''
from Patron import Patron


zach = Patron()
braden = Patron()

zach.retrieve(1187277)

print zach.attributes
print braden.attributes
我的控制台显示zach和braden实例具有完全相同的属性,尽管我没有对braden实例进行任何设置。如果我给braden实例赋值,那么它们都共享该实例的属性

我认为这是一个与可变默认参数行为相关的问题,但我无法解决我的问题。

您将属性设置为类级变量,因为dict是可变的。将它的定义移动到_uinit__;中,它应该可以工作

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
给出:

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
您已经将属性设置为类级别变量,因为dict是可变的。将它的定义移动到_uinit__;中,它应该可以工作

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
给出:

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
这不是直接的可变默认参数问题,因为您根本没有默认函数参数。问题是你根本没有在zach和braden身上设置任何属性

调用zach.retrieve1187277时,retrieve将执行以下操作

self.attributes["patron_id"] = patron_id
您似乎对该语句的工作原理有一些误解,因此让我们一步一步地了解Python将如何评估该语句

第一步是查找self.attributes。这首先在自命名属性中查找属性,但没有这样的属性

当读取一个属性时,这会返回到self类和任何基类,但这与这里无关。因此,退后一步是在Patron中查找名为attributes的属性。这将成功并生成一个字典,因此对象是查找的结果

下一步是对查找结果执行项分配操作。项赋值是object[key]=值语法所做的;在您的例子中,self.attributes是对象,patron\u id是键,patron\u id是值。因此,这将在存储在用户类的attributes属性中的字典中设置关键用户id到person id

因此,打印zach.attributes和打印braden.attributes显示相同的内容也就不足为奇了。它们都没有attributes属性,因此都将在类Patron中查找attributes属性。如果您通过分配给该字典来存储所有属性,那么很明显,对其中一个字典所做的任何更改都会影响您从另一个字典中看到的内容。

这不是可变默认参数的直接问题,因为您根本没有默认函数参数。问题是你根本没有在zach和braden身上设置任何属性

调用zach.retrieve1187277时,retrieve将执行以下操作

self.attributes["patron_id"] = patron_id
您似乎对该语句的工作原理有一些误解,因此让我们一步一步地了解Python将如何评估该语句

第一步是查找self.attributes。这首先在自命名属性中查找属性,但没有这样的属性

当读取一个属性时,这会返回到self类和任何基类,但这与这里无关。因此,退后一步是在Patron中查找名为attributes的属性。这将成功并生成一个字典,因此对象是查找的结果

下一步是对查找结果执行项分配操作。项赋值是object[key]=值语法所做的;在您的例子中,self.attributes是对象,patron\u id是键,patron\u id是值。因此,这将在存储在用户类的attributes属性中的字典中设置关键用户id到person id

因此,打印zach.attributes和打印braden.attributes显示相同的内容也就不足为奇了。它们都没有attributes属性,因此都将在类Patron中查找attributes属性。如果您通过分配给该字典来存储所有属性,那么很明显,其中一个字典中的任何更改都会影响您从另一个字典中看到的内容