作者gardenest (股海寻灯)
看板Python
标题Re: [问题] 关於class 内变数的问题
时间Thu Jan 22 04:46:27 2009
因为一样是变数的问题,所以我直接回这个标题。
1、
a = 1
class testing:
def test(self):
a = 0
print a
def test2(self):
print a
obj = testing()
obj.test()
obj.test2()
print a
----------output
0
1
1
-----------
看起来像是最上面第一行a的值并没有被test()改成0,所以後面印出来的还是1。
2、
但是当我将a改成list的型态时,它似乎会被改变了。
a = [1]
class testing:
def test(self):
a.append(2)
print a
def test2(self):
print a
obj = testing()
obj.test()
obj.test2()
print a
---------output
[1,2]
[1,2]
[1,2]
---------
看起来a在test()里被改变了。
以上这2个例子让我感到很困惑,一个会被改,一个不会被改,
想请问为什麽会有这样子的差异呢?
※ 引述《sbrhsieh (sbr)》之铭言:
: ※ 引述《millerlai (Scent of Love)》之铭言:
: : 你的例子,我稍微改一下值。
: : class CA:
: : V1 = 'V1'
: : def __init__(self):
: : self.V2 = 'V2'
: 以上这个 statement 执行後会产生一个 class object(应该说是 type instance)
: 这个 object bind 在 此 statement 所在 scope 中的名称为 'CA'.
: 所以 CA.V1 可以说是 CA 所指涉的物件的 instance field.
: 这在 Java 中也是如此, static field 是 Class(derived) object 的 instance
: field.
: : 以下的程式码,第一行建立了一个型别为CA的obj1 instance。
: : 经过将obj1.V1设为"V_V" 之後,你觉得最後的输出结果会是如何?
: : obj1 = CA();
: 这个 statement 产生一个 object(CA instance), 该 object 有一个 instance
: field: 'V2'.
: : print(obj1.V1);
: : print(obj1.V2);
: : obj1.V1 = "V_V";
: : print(CA.V1);
: : #---------output---------
: : V1
: : V2
: : V1
: : #---------output---------
: : 在Java里面,可透过 static 关键字来宣告一个 static field,但是在Python中
: : static或instance field宣告无法从syntax上来判断。
: : 以上面的例子来说明,如果CA的V1栏位是一个static栏位,那麽最後一次print的结果
: : 是V1却不是V_V,这在Java的观念里是说不通的。
: : Python是根据栏位的取用者来决定其栏位是static or instance。
: : 当程式透过 obj1 取用V1栏位时,此时V1为instance栏位。
: : 当程式透过 CA 取用V1栏位时,此时V1为static 栏位。
: : 而CA在建构元中所写的V2,是实体栏位没有错。
: 我也同意 CA.V1 不完全等同於 Java/C++ 中的 static field(data member) 这样的
: 看法.
: 但是我认为某种程度上把 CA.V1 看成是一种 static field 也无不可. static field
: 在观念上是属於 Class object(此 Class 是以 Java 界的说法), 也就是说 static
: field 是保存(依附)在 Class object 本身(不是依附在该 Class 建构出来的
: instance 上. 在 Python 中也是如此, CA.V1 是依附在 CA 所指涉的 type instance
: 中, 由 CA 所建构的多个 instance 共享.
: Python 中的 object(a type name) 所实作的 __getattribute__ method, 除了会在
: 物件本身的 namespace 里寻找外, 也会蒐寻物件所属的 class object, 所以上例中
: 在尚未 assign 一个物件进 obj1 的 namespace 之前, obj1.V1 也可以存取到 CA.V1
: 所绑定的值. obj1.V1 = "V_V" 这个 statement 是把 "V_V" 这个 object bind 在
: obj1(指涉的物件)的 namespace(或说 __dict__), 而遮蔽了 CA.V1.
: 以下这个 Java code 可以说跟文中前段的 Python code 有很高程度上的相似性.
: public class CA {
: public static String V1 = "V1";
: public String V2;
: public String _V1;
: public CA() {
: this.V2 = "V2";
: }
: public static void main(String[] args) {
: CA obj1 = new CA();
: System.out.println(obj1.getV1());
: System.out.println(obj1.V2);
: obj1.setV1("V_V");
: System.out.println(CA.V1);
: }
: public String getV1() {
: return _V1 != null? _V1 : V1;
: }
: public void setV1(String value) {
: this._V1 = value;
: }
: }
: 基於 Java 中的 class member(field/method)在 class resolve 之後就固定, 所以
: 只能用依据一个 field 的值是否为空(null)来模拟 field 是否存在.
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 115.82.4.128