Python 如何避免实例之间共享类数据?

Python 如何避免实例之间共享类数据?,python,class,Python,Class,我想要的是这种行为: class a: list = [] x = a() y = a() x.list.append(1) y.list.append(2) x.list.append(3) y.list.append(4) print(x.list) # prints [1, 3] print(y.list) # prints [2, 4] 当然,当我打印时真正发生的是: print(x.list) # prints [1, 2, 3, 4] print(y.list) #

我想要的是这种行为:

class a:
    list = []

x = a()
y = a()

x.list.append(1)
y.list.append(2)
x.list.append(3)
y.list.append(4)

print(x.list) # prints [1, 3]
print(y.list) # prints [2, 4]
当然,当我打印时真正发生的是:

print(x.list) # prints [1, 2, 3, 4]
print(y.list) # prints [1, 2, 3, 4]
很明显,他们在
a类中共享数据。如何获得单独的实例来实现我想要的行为?

您将“列表”声明为“类级属性”,而不是“实例级属性”。为了在实例级别确定属性的作用域,您需要通过引用
\uuuu init\uuuu
方法中的“self”参数来初始化属性(或根据情况在其他地方)

您不必严格地在
\uuu init\uuuu>方法中初始化实例属性,但它更易于理解。

您将“list”声明为“类级属性”,而不是“实例级属性”。为了在实例级别确定属性的作用域,您需要通过引用
\uuuu init\uuuu
方法中的“self”参数来初始化属性(或根据情况在其他地方)

您不必严格地在
\uuuu init\uuu
方法中初始化实例属性,但这样更容易理解。

您希望:

class a:
    def __init__(self):
        self.list = []
在类声明中声明变量使它们成为“类”成员,而不是实例成员。在
\uuuuu init\uuuuuu
方法中声明它们可以确保在对象的每个新实例旁边创建成员的新实例,这就是您要查找的行为。

您希望这样:

class a:
    def __init__(self):
        self.list = []

在类声明中声明变量使它们成为“类”成员,而不是实例成员。在
\uuuuu init\uuuuuu
方法中声明它们可确保在对象的每个新实例旁边创建成员的新实例,这就是您要查找的行为。

是,您必须在“构造函数”中声明如果您希望列表成为对象属性而不是类属性。

是,如果您希望列表成为对象属性而不是类属性,则必须在“构造函数”中声明。

接受的答案有效,但多做一点解释也无妨

创建实例时,类属性不会成为实例属性。当为它们指定值时,它们将成为实例属性

在原始代码中,实例化后,
列表
属性没有赋值;因此它仍然是一个类属性。在
\uuuuu init\uuuu
中定义列表是有效的,因为在实例化之后调用了
\uuuuuu init\uuuu
。或者,此代码也会产生所需的输出:

>>> class a:
    list = []

>>> y = a()
>>> x = a()
>>> x.list = []
>>> y.list = []
>>> x.list.append(1)
>>> y.list.append(2)
>>> x.list.append(3)
>>> y.list.append(4)
>>> print(x.list)
[1, 3]
>>> print(y.list)
[2, 4]
然而,这个问题中令人困惑的场景永远不会发生在数字和字符串等不可变对象上,因为它们的值在没有赋值的情况下是无法更改的。例如,类似于原始字符串属性类型的代码可以正常工作:

>>> class a:
    string = ''


>>> x = a()
>>> y = a()
>>> x.string += 'x'
>>> y.string += 'y'
>>> x.string
'x'
>>> y.string
'y'

因此,总结一下:类属性成为实例属性,当且仅当实例化后为它们分配了值时,无论是否在
\uuuu init\uuuu
方法中。这是一件好事,因为通过这种方式,如果在实例化后从未为属性赋值,则可以拥有静态属性。

接受的答案是可行的,但多做一点解释也无妨

创建实例时,类属性不会成为实例属性。当为它们指定值时,它们将成为实例属性

在原始代码中,实例化后,
列表
属性没有赋值;因此它仍然是一个类属性。在
\uuuuu init\uuuu
中定义列表是有效的,因为在实例化之后调用了
\uuuuuu init\uuuu
。或者,此代码也会产生所需的输出:

>>> class a:
    list = []

>>> y = a()
>>> x = a()
>>> x.list = []
>>> y.list = []
>>> x.list.append(1)
>>> y.list.append(2)
>>> x.list.append(3)
>>> y.list.append(4)
>>> print(x.list)
[1, 3]
>>> print(y.list)
[2, 4]
然而,这个问题中令人困惑的场景永远不会发生在数字和字符串等不可变对象上,因为它们的值在没有赋值的情况下是无法更改的。例如,类似于原始字符串属性类型的代码可以正常工作:

>>> class a:
    string = ''


>>> x = a()
>>> y = a()
>>> x.string += 'x'
>>> y.string += 'y'
>>> x.string
'x'
>>> y.string
'y'

因此,总结一下:类属性成为实例属性,当且仅当实例化后为它们分配了值时,无论是否在
\uuuu init\uuuu
方法中。这是一件好事,因为通过这种方式,如果在实例化之后从未为属性赋值,那么就可以拥有静态属性。

因此,这里几乎每个响应都会错过一个特定点。类变量永远不会成为实例变量,如下代码所示。通过使用元类在类级别截取变量赋值,我们可以看到,当重新赋值a.myattr时,不会调用类上的字段赋值魔术方法。这是因为赋值创建了一个新的实例变量。此行为与类变量完全无关,如第二个类所示,该类没有类变量,但仍然允许字段赋值

class mymeta(type):
    def __init__(cls, name, bases, d):
        pass

    def __setattr__(cls, attr, value):
        print("setting " + attr)
        super(mymeta, cls).__setattr__(attr, value)

class myclass(object):
    __metaclass__ = mymeta
    myattr = []

a = myclass()
a.myattr = []           #NOTHING IS PRINTED
myclass.myattr = [5]    #change is printed here
b = myclass()
print(b.myattr)         #pass through lookup on the base class

class expando(object):
    pass

a = expando()
a.random = 5            #no class variable required
print(a.random)         #but it still works
简而言之类变量与实例变量无关


更清楚地说它们正好在实例的查找范围内。类变量实际上是类对象本身上的实例变量。如果需要,也可以使用元类变量,因为元类本身也是对象。无论是否用于创建其他对象,一切都是一个对象,因此不要被其他语言的语义和单词类的用法所束缚。在python中,类实际上只是一个对象,用于确定如何创建其他对象及其行为。元类是创建类的类,只是为了进一步说明这一点

所以这里几乎所有的回答似乎都忽略了一个特定的要点。类变量永远不会成为实例变量,如下代码所示。通过使用元类在
>>> A.temp = 'Monuments'
>>> print(A.temp)
Monuments
>>> print(a.temp)
Monuments
>>> print(A.__dict__)
{
    'change': <function change at 0x7f5e26fee6e0>,
    '__module__': '__main__',
    '__init__': <function __init__ at 0x7f5e26fee668>,
    'temp': 'Monuments',
    '__doc__': None
}
>>> print(a.__dict__)
{x: 'Tesseract'}
>>> a.change('Intervals')
>>> print(a.temp)
Intervals
>>> print(A.temp)
Monuments
class example:
    list=[] #This is class variable shared by all instance
    def __init__(self):
        self.list = [] #This is instance variable referred to specific instance