本帖最后由 刘鑫-15电子 于 2017-10-19 21:37 编辑  
 
之前在写一个小程序的时候,发现了一个问题,我拿出来给大家讨论一下。 
我们先来看一个简单的例子: 
[C] syntaxhighlighter_viewsource syntaxhighlighter_copycode class A:
    num =1
    def fun(self):
        print(self.value) 
那么我们注意到了,关于num这个列表,这么写没什么问题是吧,我们在C++或者C#或者java里面都是这么写的,这表示class的公共属性 
但是,但是!!!!!! 
是不一样的,首先我们来看一下访问这个list1列表要怎样访问呢? 
按照我们常规的思想是吧,直接访问就可以了是吧 
我们把代码改写一下 
[C] syntaxhighlighter_viewsource syntaxhighlighter_copycode class A:
    num =1
    def fun(self):
        print(num)   #在这里,希望访问num这个变量,将他打印出来 
但是,我直接告诉你们,程序会报错。 
顿时就疯了,我曾经一度怀疑是不是因为由于python是脚本语言,所以这个num =1这句表达式根本没有被执行到。但后来经过各种验证和查资料,终于知道,压根不是这么回事!! 
我在Python参考指南看到了这样几句话: 
1、类变量是可在类的所有实例之间共享的值(也就是说,他们不是单独分配给每个实例的)。 
2、在python当中,尽管类会定义命名空间,但他们不会为方法中用到的名称创建作用域。在实现类时,对属性和方法的引用必须是完全限定的。类中没有作用域,这是python与C++或者java的区别之一。 
这第一句话比较好理解,但是什么叫类变量? 
在class当中,属于class本身自己的属性的变量即为类变量 
即这里的num,在C#中我们称为公共字段(我不知道在C++和JAVA中称为什么) 
那么根据第一句话的意思,也就是说这个num变量是可以在实例之间共享的值,这个变量属于A这个class,而根据第二句话,num这个变量是没有作用域的,我们要访问它必须要对它进行作用域的限定,也就是说我们可以在这样进行访问: 
A.num 
或者: 
self.num 
那么,这两个是一样的吗? 
我们来重新修改一下代码: 
[C] syntaxhighlighter_viewsource syntaxhighlighter_copycode class A:
    num =1
    def fun(self):
        print(A.num)      #这里的输出结果为1
        print(self.num)   #这里的输出结果也为1
 
但是他们真的是一样的吗? 
如果我们仔细想的话,应该是不一样的!!!!!因为他们的限定已经不一样了,他们的作用域也不一样了 
先不多说,我们直接来做一个实验 
 
a1 =A()    #实例化a1 
a2 =A()   #实例化a2 
A.num  
#输出为1 
a1.num  
#输出为1 
a2.num 
#输出为1 
到了这里,貌似都没有什么问题 
但是,接下来一切都变得不一样 
A.num  =2 
a1.num  
#输出为2 
a2. num 
#输出为2 
我们发现,我们的值都跟着变了,这是不是印证了第一句话 
那么,我们又来做一个实验 
a1.num =3 
A.num 
#输出为2 
a2.num  
#输出为2 
这里,就体现出A.num 与self.num的不同了 
我还做过这样的实验,我将类变量和实例变量的地址进行全面的跟踪,时刻监控 
我发现这样的现象 
当我创建了两个实例a1,a2的时候 
A.num 、a1.num、a2.num 
这3个变量的地址是一样的 
当我尝试去改变a1.num的值之后 
a1.num的地址变了 
而A.num的地址与a2.num的地址还是原来的地址 
所以,经过探究我们发现,类变量与实例变量是不一样的,首先。他的作用域不一样,虽然在最初我们未对实例变量进行改变的时候,他们的地址都是一样的。但是当我们一旦改变了实例变量的值,那么,实例变量和类变量指向的地址就已经发生了改变,而这与改变类变量是不一样的,如果在改变实例变量之前(也就是在实例变量和类变量所指向的内存是同一块内存的时候) 改变类变量,将直接改变实例变量。 
 
 
 
 |