两仪shiki 发表于 2020-3-30 18:07:36

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
                self.counter += 1
                self.k.append(name)#问题在这,这里对类属性k进行了修改,但是按照python的保护原则,实例self开头修改类属性时,应该会在实例中产生一个同名变量k代替类属性k被修改。但是结果却显示类属性k确实遭到了修改。
      super().__setattr__(name,value)
    def __delattr__(self,name):
      self.counter -= 1
      self.k.remove(name)
      super().__delattr__(name)

!!!!!问题:在self.k.append(name)哪里,那里对类属性k进行了修改,但是按照python的保护原则,实例self开头修改类属性时,应该会在实例中产生一个同名变量k代替类属性k被修改。但是结果却显示类属性k确实遭到了修改。!!!!!!
例如
c = Counter()
c.x = 1
c.y = 1
c.z = 1
按道理来说类属性k应该还是为空列表
但是
Counter.k
['x', 'y', 'z']#类属性被修改了


这也导致了,小甲鱼这段代码在统计不同实例的同名属性时会出错,当一个实例的属性名字与之前另一个实例的属性名字,重复时,统计函数不能被正确调用,该属性在统计时会被忽略。

zltzlt 发表于 2020-3-30 18:16:28

不是啊,就是在原来的列表 k 上修改

两仪shiki 发表于 2020-3-30 18:24:52

zltzlt 发表于 2020-3-30 18:16
不是啊,就是在原来的列表 k 上修改

k不应该是类属性吗,当实例对类属性进行修改时,不应该是产生一个同名的实例属性代替他被修改吗。
= =难道现在这个改了吗,通过实例可以直接修改类属性了吗

zltzlt 发表于 2020-3-30 18:25:51

两仪shiki 发表于 2020-3-30 18:24
k不应该是类属性吗,当实例对类属性进行修改时,不应该是产生一个同名的实例属性代替他被修改吗。
= =难 ...

实例本来就可以直接访问和修改类属性啊

两仪shiki 发表于 2020-3-30 18:27:14

zltzlt 发表于 2020-3-30 18:25
实例本来就可以直接访问和修改类属性啊

不是吧,例如下面这个例子
class A:
    f = 1
   
a = A()
b = A()

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

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

两仪shiki 发表于 2020-3-30 19:02:25

{:10_266:}有大佬在吗

两仪shiki 发表于 2020-3-30 20:33:28

{:10_266:}{:10_266:}{:10_266:}{:10_266:}{:10_266:}

两仪shiki 发表于 2020-3-30 20:55:04

{:10_249:}有人吗

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

问题已解决,我懂了。
小甲鱼讲类属性是忽略了一些注意事项。
类属性分为两种数据类型
(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 = #这里是通过实例对类型进行了修改
b.k
['i']#类属性遭到了修改
   
2.如果是从新给可变数据类型变量赋值,这是给该实例对象添加属性
    例如:
class A:
    k =[]
a = A()
b = A()
a.k = #给类属性重新赋值,那么python会保护类属性,创建同名实例变量代替其进行修改
b.k
[]#类属性没有改变

Ananas_Comosus 发表于 2020-4-29 20:12:32

你看看我在另一篇帖子的回复,有说到这个问题,不同对象重复的变量名还是不会算入counter,所以填加字典时需要把值的变量一起写入。https://fishc.com.cn/forum.php?mod=viewthread&tid=159904&highlight=45%BD%B2 ,
所有实例确实可以修改类属性,但这里问题是当属性名相同但来自于不同对象的话,在if name not in self.k这这个来自于另一对像的属性就不会被计入

Ananas_Comosus 发表于 2020-4-29 20:14:23

你看看我在另一篇帖子的回复,有说到这个问题,不同对象重复的变量名还是不会算入counter,所以填加字典时需要把值的变量一起写入。https://fishc.com.cn/forum.php?mod=viewthread&tid=159904&highlight=45%BD%B2 ,
所有实例确实可以修改类属性,但这里问题是当属性名相同但来自于不同对象的话,在if name not in self.k这这个来自于另一对像的属性就不会被计入

Stubborn 发表于 2020-4-29 20:18:31

对于可变不可变的数据类型理解的很好,对于python里面的变量,不要看的太死,它只是一个标志符,表示它将‘指向’哪里,引用什么数据而已。
页: [1]
查看完整版本: python第45讲课后题,疑问