首页 > 技术文章 > 实例变量与类变量不得不说的二三事

dy99 2021-05-12 20:12 原文

1. 类变量作用及解析

类变量:实例共用的属性。
比方说country 这个属性如果设置为实例属性,创建5个对象的时候,country 就需要初始化5次,但这个属性对于各个实例是相同的,每次都需要创建会造成资源浪费。类变量只会在创建类的时候生成一次,对于不同对象来说无区别的对象我们可以设置为类变量。
class Chinese:
    country = 'China'
    def __init__(self, name, age,country):
        self.name = name
        self.age = age
        self.country = country  

2. 类变量、实例变量查找优先级

优先查找实例变量,找不到再去查找类变量。就是说类变量和实例变量名相同的情况下,返回的是实例变量的值,代码如下:
class Chinese:
    country = 'China'
    age = 72
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def talk(self):
        print(self, 'is talking Chinese')
if __name__ == '__main__':
    DY = Chinese("DY", "18")
    print(DY.age)
    
执行结果:
18  # 18为实例DY的属性值

3. 实例增删改查类的变量、方法

实例是可以直接操作类的变量或方法的,可进行查询、更改、新增、删除的,如果是使用这些方法时,仅推荐操作实例属性,其他属性因为存储在类的命名空间内,操作的话会影响其他实例,Python真的是很不严谨;但其实实例的属性、方法也是不推荐操作如更改、删除的,这就引入了私有变量或方法。

class Chinese:
    country = 'China'

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def talk(self):
        print(self, 'is talking Chinese')

    @staticmethod
    def nationality():
        print("国籍归属于{}".format(Chinese.country))


if __name__ == '__main__':
    DY = Chinese("DY", 18)
    print(DY.age)  # 查询实例变量值
    DY.age = 19   # 更改实例变量的值,思考更改类变量的值?
    print(DY.age)
    DY.sex = ""  # 对象新增实例变量
    print(DY.sex)

4. 实例可以更改类变量值吗?

实例对类变量赋值(更改类变量)为什么未改变类变量值?对象给类变量赋值实际是给实例增加一种新的属性,是在对象内存空间中新增了一个变量,而使用变量的时候又是优先查找实例变量,所以打印对象的类变量时,实际是查的对象的实例属性,从根本上并未影响到类变量,也就不会影响到其他对象的类变量值。
简而言之,你觉得是在更改类变量的值,实际是给实例新增了一个实例属性
class Chinese:

    country = 'China'
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def talk(self):
        print(self, 'is talking Chinese')

if __name__ == '__main__':
    DY1 = Chinese("DY", "18")
    DY2 = Chinese("DY", "19")
    DY1.country = "zhongguo"
    print(DY1.country)
    print(DY2.country)

执行结果:
zhongguo  # 实际相当于给实例DY1新增了个实例属性
China     # 实例DY2并不受影响

5. 类属性慎用可变数据结构

class Chinese:
    country = 'China'
    populations = []

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def talk(self):
        print(self, 'is talking Chinese')

    @staticmethod
    def nationality():
        print("国籍归属于{}".format(Chinese.country))

    def add_people(self):
        Chinese.populations.append(self.name)


if __name__ == '__main__':
    DY1 = Chinese("DY", 18)
    DY2 = Chinese("DY1", 18)
    DY1.add_people()
    print(DY1.populations)
    DY2.add_people()
    print(DY2.populations)
   
执行结果:
['DY'] 
['DY', 'DY1']
由执行结果可以看出,两个实例同时操作类变量时是会相互影响的, 对象DY1操作populations属性也会影响到DY2的populations ,如果是在程序中是会出bug的,而且问题不好查找,就好比说对象A与对象B同时在做任务,并且共享任务列表,对象A完成后发通知说任务已完成,导致对象B实际未做完也发通知报告已完成。
划重点:可变数据结果一般不能用作类变量的值。如果变量的值为可变数据,需要写在__init__里面,写成self. populations = [],这样在初始化对象的时候,每个对象的populations的值都会初始化为一个空列表,对象间属性独立。
 

推荐阅读