两仪shiki 发表于 2020-3-30 21:46:33

关于类属性的定义修改与赋值的个人心得

本帖最后由 两仪shiki 于 2020-3-30 21:56 编辑

类属性
一、特点
类属性是类所特有的,所有实例共享这个类属性,类属性经常定义在类的开头,方法的外面。
如下图所示,类属性既可以通过实例调用,也可以直接通过类名调用,如果要改变类属性,一般来说通过类名.类属性的方式:(存在例外,取决于类属性的数据类型)
class C:

    counter = 0
   
    def __init__(self):
      C.counter += 1

    def __del__(self):
      C.counter -= 1

if __name__ == "__main__":#这个不要过多纠结,看下面的内容
    x = C()
    print("Number of instances: : " + str(C.counter))
    y = C()
    print("Number of instances: : " + str(C.counter))
    del x
    print("Number of instances: : " + str(C.counter))
    del y
    print("Number of instances: : " + str(C.counter))
   
返回值如下:
Number of instances: : 1
Number of instances: : 2
Number of instances: : 1
Number of instances: : 0






二.注意事项(必须注意!!!)
"""类属性分为两种数据类型"""
(1).对于不可变数据类型
对象名.静态属性名称=值 是给对象中添加属性名称,而不是进行修改。

如果需要在类外修改类属性,必须通过类对象去引用然后进行修改。如果通过实例对象去引用,
会产生一个同名的实例属性,这种方式修改的是实例属性,不会影响到类属性,
并且之后如果通过实例对象去引用该名称的属性,实例属性会强制屏蔽掉类属性,
即引用的是实例属性,除非删除了该实例属性。

例如:
class A:
    f = 1
   
a = A()
b = A()

a.f
out:1
a.f =2#修改f属性

b.f
out:1#类属性并没有被修改


(2).对于可变数据类型
1.如果对象是修改可变数据类型变量中的数据,那么可以对类属性进行修改(注意这里不是重新赋值,而是修改),例如函数append()、pop()等。
    实例:
class A:
    k =[]
a = A()
b = A()
a.k.append('i')#这里是通过实例对类型进行了修改
b.k
['i']#类属性遭到了修改
   
2.如果是从新给可变数据类型变量赋值,这是给该实例对象添加属性
    例如:
class A:
    k =[]
a = A()
b = A()
a.k = #给类属性重新赋值,那么python会保护类属性,创建同名实例变量代替其进行修改
a.k
b.k
[]#类属性没有改变。

两仪shiki 发表于 2020-3-30 21:52:13

本帖最后由 两仪shiki 于 2020-3-30 21:54 编辑

类属性数据类型是否可变的问题,小甲鱼并没有注意到:
例如,旧版python课程45讲,最后一道动手题:

修改上边【测试题】第 4 题,使之可以正常运行:编写一个 Counter 类,
用于实时检测对象有多少个属性。
这是小甲鱼给出来的答案:
class Counter:
    k =[]
    def __init__(self):
      self.counter = 0
   
    def __setattr__(self,name,value):
      if name != 'counter':
            if name not in self.k:#实例中没有找到k属性,在类属性的中找到了k
                self.counter += 1
                self.k.append(name)#由于类属性是可变数据类型,所以类属性遭到了修改
      super().__setattr__(name,value)
    def __delattr__(self,name):
      self.counter -= 1
      self.k.remove(name)
      super().__delattr__(name)

!!!!!问题:在self.k.append(name)哪里,那里对表面上是对self.k的实例属性进行了修改,但实际上由于类属性是可变的列表数据类型,所以导致类属性也一并遭到修改。这也导致了,小甲鱼这段代码在统计不同实例的同名属性时会出错,当一个实例的属性名字与之前另一个实例的属性名字,重复时,统计函数不能被正确调用,该属性在统计时会被忽略。
例如
a = Counter()
b = Counter()
当a,b实例中都出现同名属性x时,假设a先定义x,b后定义x,你会发现b.x属性并没有被纳入统计。
页: [1]
查看完整版本: 关于类属性的定义修改与赋值的个人心得