【问题标题】:Multiple Instances of a Python Object are acting like the same instance [duplicate]Python对象的多个实例就像同一个实例[重复]
【发布时间】:2013-01-18 00:21:19
【问题描述】:

我在这里有我的课程模板:

 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”实例,那么它们都会共享该实例的属性。

我认为这是与可变默认参数行为有关的问题,但我无法弄清楚我的问题。

【问题讨论】:

    标签: python arguments default behavior mutable


    【解决方案1】:

    您已将attributes 设为class 级别变量,因为dicts 是可变的。将它的定义移到__init__ 内,它应该可以工作。

    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
    

    【讨论】:

      【解决方案2】:

      直接不是“可变默认参数”问题,因为您根本没有默认函数参数。问题在于您实际上根本没有在 zachbraden 上设置任何属性!

      当您调用zach.retrieve(1187277) 时,retrieve 会执行此操作

      self.attributes["patron_id"] = patron_id
      

      您似乎对它的工作原理有一些误解,所以让我们逐步了解 Python 将如何评估此语句。

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

      当读取一个属性时,这会回退到查看self(以及任何基类,但这与这里无关)。所以回退是在Patron 中寻找一个名为attributes 的属性。这成功并找到了一个字典,因此该对象是查找的结果。

      下一步是对查找的结果执行“项目分配”操作。项目分配是object[key] = value 语法的作用;在您的情况下,self.attributes 是对象,"patron_id" 是键,patron_id 是值。所以这最终将键 "patron_id" 设置为 person_id 在字典中存储在 Patron 类的 attributes 属性中

      那么print zach.attributesprint braden.attributes 显示相同的东西就不足为奇了。它们都没有attributes 属性,因此它们都将在Patron 类中找到attributes 属性。而且,如果您通过分配给该字典来继续存储所有属性,那么显然对一个字典所做的任何更改都会影响您从另一个字典中看到的内容。

      【讨论】:

        猜你喜欢
        • 2022-01-04
        • 1970-01-01
        • 2022-12-10
        • 2012-01-13
        • 1970-01-01
        • 2020-09-18
        相关资源
        最近更新 更多