鱼C论坛

 找回密码
 立即注册
查看: 935|回复: 11

python第45讲课后题,疑问

[复制链接]
发表于 2020-3-30 18:07:36 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
动手题的第二题
修改上边【测试题】第 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']#类属性被修改了


这也导致了,小甲鱼这段代码在统计不同实例的同名属性时会出错,当一个实例的属性名字与之前另一个实例的属性名字,重复时,统计函数不能被正确调用,该属性在统计时会被忽略。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-3-30 18:16:28 | 显示全部楼层
不是啊,就是在原来的列表 k 上修改
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-3-30 18:24:52 | 显示全部楼层
zltzlt 发表于 2020-3-30 18:16
不是啊,就是在原来的列表 k 上修改

k不应该是类属性吗,当实例对类属性进行修改时,不应该是产生一个同名的实例属性代替他被修改吗。
= =难道现在这个改了吗,通过实例可以直接修改类属性了吗
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

实例本来就可以直接访问和修改类属性啊
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 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#类属性并没有被修改
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-3-30 19:02:25 | 显示全部楼层
有大佬在吗
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-3-30 20:33:28 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2020-3-30 20:55:04 | 显示全部楼层
有人吗
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 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 = [12]#这里是通过实例对类型进行了修改
b.k
['i']#类属性遭到了修改
   
2.如果是从新给可变数据类型变量赋值,这是给该实例对象添加属性
    例如:
class A:
    k =[]
a = A()
b = A()
a.k = [12]#给类属性重新赋值,那么python会保护类属性,创建同名实例变量代替其进行修改
b.k
[]#类属性没有改变
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-29 20:12:32 | 显示全部楼层
你看看我在另一篇帖子的回复,有说到这个问题,不同对象重复的变量名还是不会算入counter,所以填加字典时需要把值的变量一起写入。https://fishc.com.cn/forum.php?m ... ;highlight=45%BD%B2
所有实例确实可以修改类属性,但这里问题是当属性名相同但来自于不同对象的话,在if name not in self.k这这个来自于另一对像的属性就不会被计入
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-29 20:14:23 | 显示全部楼层
你看看我在另一篇帖子的回复,有说到这个问题,不同对象重复的变量名还是不会算入counter,所以填加字典时需要把值的变量一起写入。https://fishc.com.cn/forum.php?m ... ;highlight=45%BD%B2
所有实例确实可以修改类属性,但这里问题是当属性名相同但来自于不同对象的话,在if name not in self.k这这个来自于另一对像的属性就不会被计入
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-29 20:18:31 | 显示全部楼层
对于可变不可变的数据类型理解的很好,对于python里面的变量,不要看的太死,它只是一个标志符,表示它将‘指向’哪里,引用什么数据而已。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-27 01:46

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表