我在理解Python类中的静态变量概念时遇到了问题。根据{{3}},每当我们在方法之外和python类中定义变量时,此变量都是静态的。这意味着可以访问此变量,而无需从类中实例化对象,并且可以直接通过类名访问。 例如:
class my_class:
i=12
def __init__(self,j):
self.j=j
instance=my_class(10)
my_class.i:
>12
instance.i:
>12
instance.i=13
instance.i:
>13
my_class.i:
>12
您可以看到我们可以通过实例对象和类名访问静态变量i
。但是,当我们更改实例对象的i
值时,它不会影响类的值(my_class.i
仍然是12)。
另一方面,如果我们使用数组静态变量,事情就会彻底改变。
考虑类似的例子:
class my_class:
i=[]
def __init__(self,j):
self.j=j
instance=my_class(10)
my_class.i:
>[]
instance.i:
>[]
instance.i.append(13)
instance.i:
>[13]
my_class.i:
>[13]
您可以看到,当我更改实例对象数组的变量时,它也会影响类值。这里发生了什么?如果有人能帮助我更好地理解这个问题,我将不胜感激,因为这对我来说并不是那么明显。顺便说一句,我有一个Java背景。
答案 0 :(得分:4)
通常分配给实例属性设置实例属性。一旦有实例属性,它就会掩盖类属性。
因此,在执行instance.i=13
之前,实例上没有i
属性,仅在类上。然后,您将实例上的名称i
绑定到13
,下次查找instance.i
时找到该属性,并且不再尝试查找my_class.i
但是操纵可变对象与分配给类或实例属性不同。您未分配给instance.i
,您更改了my_class.i
引用的列表对象,并通过instance.i
显示。 instance.i
仍然会找到my_class.i
属性,您从未使用=
来创建instance.i
属性。
那是因为您只是读取对列表的instance.i
引用,以便打印它,并找到list.append()
方法。您在任何时候都没有为instance.i
属性引用设置新值。
列表对象是它自己的对象,您可以通过添加或删除或替换列表的 indices 引用的值来更改该对象。引用该列表的名称或属性并不重要,您可以对同一列表进行任意数量的此类引用,并且更改列表不会更改这些引用。
尝试创建对列表的更多引用,看看会发生什么:
>>> list_named_i = instance.i
>>> list_named_i
[13]
>>> my_class.i.append(42)
>>> list_named_i
[13, 42]
>>> list_named_i[0] = 81
>>> instance.i
[81, 42]
instance.i
,my_class.i
和list_named_i
都只是对同一列表对象的不同引用,您可以通过任何这些引用修改(mutate)该列表对象。
我建议您阅读Python名称和属性以及列表等工作;见Ned Batchelder的Facts and myths about Python names and values。
答案 1 :(得分:1)
instance.i.append(13)
这不会改变变量,它会改变列表对象。该变量仍设置为同一对象。
如果将变量设置为新列表:
instance.i = [13]
然后你会看到你期待的东西。
答案 2 :(得分:-2)
在实例化期间,对象在实例化时接收每个类属性的副本(或多或少)。这就是为什么你可以在不影响课程的情况下访问和改变实例上的值,并且签证/反之亦然。
其中list
被修改的第二点,似乎是从实例到类的反向是由于list
的可变性,并且类似于默认参数经常遇到的问题,{ {3}}