打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
六、Python类变量和实例变量(类属性和实例属性)
我们知道,无论是在类中定义的属性还是方法,在类的外部,都无法直接调用它们,因此,我们完全可以把类看做是一个独立的作用域(称为类命名空间),则类属性其实就是定义在类命名空间内的变量(类方法其实就是定义的类命名空间中的函数)。

根据定义属性的位置不同,类属性又可细分为类属性(后续用类变量表示)和实例属性(后续用实例变量表示)。

类变量(类属性)

类变量指的是定义在类中,但在各个类方法外的变量。类变量的特点是:所有类的实例化对象都可以共享类变量的值,即类变量可以在所有实例化对象中作为公用资源。

注意,类变量推荐直接用类名访问,但也可以使用对象名访问。

例如,下面代码定义了一个 Address 类,并为该类定义了多个类属性:
  1. class Address :

  2. detail = '广州'

  3. post_code = '510660'

  4. def info (self):

  5. # 尝试直接访问类变量

  6. #print(detail) # 报错

  7. # 通过类来访问类变量

  8. print(Address.detail) # 输出 广州

  9. print(Address.post_code) # 输出 510660

  10. #创建 2 个类对象

  11. addr1 = Address()

  12. addr1.info()

  13. addr2 = Address()

  14. addr2.info()

  15. # 修改Address类的类变量

  16. Address.detail = '佛山'

  17. Address.post_code = '460110'

  18. addr1.info()

  19. addr2.info()

该程序中,第二、三行代码为 Address 定义了两个类变量。当程序中第一次调用 Address 对象的 info() 方法输出两个类变量时,将会输出这两个类变量的初始值。接下来程序通过 Address 类修改了两个类变量的值,因此当程序第二次通过 info() 方法输出两个类变量时,将会输出这两个类变量修改之后的值。

运行上面代码,将会看到如下输出结果:

广州
510660
广州
510660
佛山
460110
佛山
460110

通过输出结果可以看到,addr1 和 addr2 共享类变量,换句话说,改变类变量的值会作用于该类所有的实例化对象。

当然,Python 也支持使用对象来访问该对象所属类的类属性(此方式不推荐使用)。例如如下程序:
  1. class Record:

  2. # 定义两个类变量

  3. item = '鼠标'

  4. date = '2016-06-16'

  5. def info (self):

  6. print('info方法中: ', self.item)

  7. print('info方法中: ', self.date)

  8. rc = Record()

  9. print(rc.item) # '鼠标'

  10. print(rc.date) # '2016-06-16'

  11. rc.info()

上面程序的 Record 中定义了两个类变量,接下来程序完全可以使用 Record 对象来访问这两个类变量。

因此可以看到,在 Record 类的 info() 方法中,程序使用 self 访问 Record 类的类变量,此时 self 代表 info() 方法的调用者,也就是 Record 对象,因此这是合法的;在主程序代码区,程序创建了 Record 对象,并通过对象调用 Record 对象的 item、date 类变量,这也是合法的。

在 Python 中,除了可以通过类名访问类属性之外,还可以动态地为类和对象添加类变量。例如,在上面代码的基础,添加以下代码:
  1. Address.depict ="佛山很美"

  2. print(addr1.depict)

  3. print(addr2.depict)

运行结果为:

佛山很美
佛山很美

实例变量(实例属性)

实例变量指的是定义在类的方法中的属性,它的特点是:只作用于调用方法的对象。

注意,实例变量只能通过对象名访问,无法通过类名直接访问。

Python 允许通过对象访问类变量,但无法通过对象修改类变量的值。因为,通过对象修改类变量的值,不是在给“类变量赋值”,而是定义新的实例变量。

例如如下程序:
  1. class Inventory:

  2. # 定义两个类变量

  3. item = '鼠标'

  4. quantity = 2000

  5. # 定义实例方法

  6. def change(self, item, quantity):

  7. # 下面赋值语句不是对类变量赋值,而是定义新的实例变量

  8. self.item = item

  9. self.quantity = quantity

  10. # 创建Inventory对象

  11. iv = Inventory()

  12. iv.change('显示器', 500)

  13. # 访问iv的item和quantity实例变量

  14. print(iv.item) # 显示器

  15. print(iv.quantity) # 500

  16. # 访问Inventory的item和quantity类变量

  17. print(Inventory.item) # 鼠标

  18. print(Inventory.quantity) # 2000

上面程序中,第 8、9 行代码通过实例对 item、quantity 变量赋值,看上去很像是对类变量赋值,但并不是,它们的作用是:重新定义了两个实例变量。

类中,实例变量和类变量可以同名,但是在这种情况下,使用类对象将无法调用类变量,因为它会首选实例变量,因此这也是不推荐“类变量使用对象名调用”的原因。

上面程序在调用 Inventory 对象的 change() 方法之后,访问 Inventory 对象的 item、quantity 变量,由于该对象本身己有这两个实例变量,因此程序将会输出该对象的实例变量的值;接下来程序通过 Inventory 访问它的 item、quantity 两个类变量,此时才是真的访问类变量。

运行上面程序,将看到如下输出结果:

显示器
500
鼠标
2000


即便程序通过类修改了两个类变量的值,程序中 Inventory 的实例变量的值也不会受到任何影响。例如如下代码:
  1. Inventory.item = '类变量item'

  2. Inventory.quantity = '类变量quantity'

  3. # 访问iv的item和quantity实例变量

  4. print(iv.item)

  5. print(iv.quantity)

运行上面代码,可以看到如下输出结果:

显示器
500

上面程序开始就修改了 Inventory 类中两个类变量的值,但这种修改对 Inventory 对象的实例变量没有任何影响。

同样,如果程序对一个对象的实例变量进行了修改,这种修改也不会影响类变量的值,更不会影响其他对象中实例变量的值。例如如下代码:
  1. iv2 = Inventory()

  2. iv2.change('键盘',300)

  3. iv.item = 'iv实例变量item'

  4. iv.quantity = 'iv实例变量quantity'

  5. print(Inventory.item)

  6. print(Inventory.quantity)

  1. print(iv.item)

  2. print(iv.quantity)

运行上面代码,将会看到如下输出结果:

类变量item
类变量quantity
iv实例变量item
iv实例变量quantity
键盘
300

从输出结果很容易看出,修改一个对象的实例变量,既不会影响类变量的值,也不会影响其它对象的实例变量。

和动态为类添加类变量不同,Python 只支持为特定的对象添加实例变量。例如,在之前代码的基础上,为 iv 对象添加 color 实例变量,实现代码为:
  1. iv.color="red"

  2. print(iv.color)

  3. #因为 color 实例变量仅 iv 对象有,iv2 对象并没有,因此下面这行代码会报错

  4. #print(iv2.color)

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【Java】类方法和实例方法
类的定义
static的理解
java 子类继承父类
Java变量的作用范围
C#要点
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服