关于类属性的定义修改与赋值的个人心得
本帖最后由 两仪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: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]