刘鑫-15电子 发表于 2017-10-19 21:36:16

关于Python在class中属性作用域的关系

本帖最后由 刘鑫-15电子 于 2017-10-19 21:37 编辑

之前在写一个小程序的时候,发现了一个问题,我拿出来给大家讨论一下。
我们先来看一个简单的例子:
class A:
    num =1
    def fun(self):
      print(self.value)
那么我们注意到了,关于num这个列表,这么写没什么问题是吧,我们在C++或者C#或者java里面都是这么写的,这表示class的公共属性
但是,但是!!!!!!
是不一样的,首先我们来看一下访问这个list1列表要怎样访问呢?
按照我们常规的思想是吧,直接访问就可以了是吧
我们把代码改写一下
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
那么,这两个是一样的吗?
我们来重新修改一下代码:
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的地址还是原来的地址
所以,经过探究我们发现,类变量与实例变量是不一样的,首先。他的作用域不一样,虽然在最初我们未对实例变量进行改变的时候,他们的地址都是一样的。但是当我们一旦改变了实例变量的值,那么,实例变量和类变量指向的地址就已经发生了改变,而这与改变类变量是不一样的,如果在改变实例变量之前(也就是在实例变量和类变量所指向的内存是同一块内存的时候) 改变类变量,将直接改变实例变量。



页: [1]
查看完整版本: 关于Python在class中属性作用域的关系