1. 主页
  2. Python基础到高级
  3. 面向对象
  4. 类作用域

类作用域

类的作用域

在之前的文章中介绍过Python的作用,在这个小结介绍下类的作用域

In [1]: class E:
   ...:     NAME = 'E'   # 类的直接下级作用域,叫做类变量
   ...:     def __init__(self, name):
   ...:         self.name = name   # 关联到实例的变量,叫做实例变量
   ...:         

In [2]: e = E('e')

In [4]: E.NAME
Out[4]: 'E'

In [5]: e.NAME
Out[5]: 'E'

上面的例子可以看出,类变量对类和对象都是可见的

In [6]: E.name   # 直接使用类名来访问实例变量的时候报错了,说明类是不能直接访问实例变量的
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-6-b6daf181be33> in <module>()
----> 1 E.name

AttributeError: type object 'E' has no attribute 'name'

In [7]: e.name   # 实例变量可以使用实例对象来进行访问和调用
Out[7]: 'e'

所有实例共享类变量,例如:

In [8]: e2 = E('e2')   # 重新定义一个实例对象

In [11]: e.NAME   # 使用之前的实例来进行访问类变量
Out[11]: 'E'

In [9]: e2.NAME # 使用刚定义的实例访问类变量,结果是一样的
Out[9]: 'E'

Python可以动态的给对象增减属性

上面说了所实例共享类变量,但是下面的例子又反驳了这个说法

In [12]: e2.NAME = 'E2'   # 给实例e2的NAME属性赋值

In [13]: e2.NAME   # 获取e2的属性值
Out[13]: 'E2'

In [14]: e.NAME   # 获取e的属性
Out[14]: 'E'

In [15]: e.xxx = 3   # 给e对象添加一个xxx的属性

In [16]: e2.xxx   # 使用e2访问xxx属性报出了错误
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-16-8ca2718f6555> in <module>()
----> 1 e2.xxx

AttributeError: 'E' object has no attribute 'xxx'

发现e2和e的实例对应的类变量的值是不相同,而且e新创建的属性是无法访问的

从上面的例子可以看出,当给实的类变量赋值的时候,就相当于动态的给这个实例增加了一个属性,覆盖了类变量

In [17]: E.NAME = 'LANYULEI'   # 直接使用类名来重新定义NAME的属性

In [18]: e.NAME   # 使用e获取NAME的值
Out[18]: 'LANYULEI'

In [19]: e2.NAME   # 使用e2来获取NAME的值,得到的是不一样的结果
Out[19]: 'E2'

这样就能看出,e因为么有重新给类变量赋值,因此当类变量修改的时候,e实例也就修改了,因为e2修改过NAME属性的值,相当于动态的给e2实例添加了一个变量,因此当类变量重新赋值的时候,e2是没有变化的

对于类变量和实例的准则其实就是,赋值及创建。

属性的查找顺序

上面的例子中看出了,类变量的赋值及创建,当实例重新定义类变量的时候,就是给实例动态的添加了属性,原理是什么呢?

In [21]: e.__class__.NAME
Out[21]: 'LANYULEI'

In [23]: E.__dict__['NAME']
Out[23]: 'LANYULEI'

在实例中会有两个默认属性分别是__dict__和__class__, 当你给实例动态的添加属性的时候,那么就是给__dict__中追加数据的,

属性的查找顺序

  • dict # 先从__dict_找有没有这个属性
  • class # 实例类的一个引用

另外类也是一个对象,因此也是可以动态的添加属性的

我们要如何帮助您?

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注