鱼C论坛

 找回密码
 立即注册
查看: 663|回复: 4

[已解决]第47课描述符有问题

[复制链接]
发表于 2020-4-4 00:17:22 | 显示全部楼层 |阅读模式

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

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

x
>>> class MyProperty:
        def __init__(self,fget=None,fset=None,fdel=None):
                self.fget = fget
                self.fset = fset
                self.fdel = fdel
        def __get__(self,instance,owner):
                return self.fget(instance)
        def __set__(self,instance,value):
                self.fset(instance,value)
        def __delete__(self,instance):
                self.fdel(instance)

               
>>> class C:
        def __init__(self):
                self._x = None
        def getX(self):
                return self._x
        def setX(self,value):
                self._x = value
        def delX(self):
                del self._x
        x = MyPropertys(getX, setX, delX)

>>> c.x = 'X-man'
>>> c.x
'X-man'
>>> c._x
'X-man'

问题:c.x='X-man'调用了MyProperty的__set__,__set__又调用了C的setX,setX只对c._x='X-man',并没有使c.x='X-man'。请问为什么c.x和c._x都为'X-man'?
最佳答案
2020-4-4 00:57:41
本帖最后由 sunrise085 于 2020-4-4 00:58 编辑

我不知道你对__get__()和__set__()有多少理解。python中如果一个类实现了__get__、__set__、__delete__三个方法的任意一个方法就是描述器。
帮你在函数中添加了一些print,可以看清楚函数在什么时候调用的
然后对关键的一些地方做了注释
  1. class MyProperty:
  2.         def __init__(self,fget=None,fset=None,fdel=None):
  3.                 self.fget = fget
  4.                 self.fset = fset
  5.                 self.fdel = fdel
  6.         def __get__(self,instance,owner):
  7.                 print("MyProperty.__get__")
  8.                 return self.fget(instance)
  9.         def __set__(self,instance,value):
  10.                 print("MyProperty.__set__")
  11.                 self.fset(instance,value)
  12.         def __delete__(self,instance):
  13.                 print("MyProperty.__delete__")
  14.                 self.fdel(instance)
  15. class C:
  16.         def __init__(self):
  17.                 print("C.__init__")
  18.                 self._x = None
  19.         def getX(self):
  20.                 print("C.getX")
  21.                 return self._x
  22.         def setX(self,value):
  23.                 self._x = value
  24.                 print("C.setX")
  25.         def delX(self):
  26.                 print("C.delX")
  27.                 del self._x
  28.         x = MyProperty(getX, setX, delX)#C类属性放一个对象MyProperty的实例赋值给x
  29. print("创建C类对象c")
  30. c=C()
  31. print("修改描述器同名属性值")
  32. c.x='X_Man'     # 修改描述器同名属性值,会调用数据描述器MyProperty的__set__方法
  33. print("访问描述器同名属性值")
  34. print(c.x)     # 访问描述器同名属性值,会调用数据描述器MyProperty的__get__方法
  35. print("下面这句不会触发描述器")
  36. print(c._x)
复制代码

运行结果
  1. 创建C类对象c
  2. C.__init__
  3. 修改描述器同名属性值
  4. MyProperty.__set__
  5. C.setX
  6. 访问描述器同名属性值
  7. MyProperty.__get__
  8. C.getX
  9. X_Man
  10. 下面这句不会触发描述器
  11. X_Man
复制代码

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-4-4 00:57:41 | 显示全部楼层    本楼为最佳答案   
本帖最后由 sunrise085 于 2020-4-4 00:58 编辑

我不知道你对__get__()和__set__()有多少理解。python中如果一个类实现了__get__、__set__、__delete__三个方法的任意一个方法就是描述器。
帮你在函数中添加了一些print,可以看清楚函数在什么时候调用的
然后对关键的一些地方做了注释
  1. class MyProperty:
  2.         def __init__(self,fget=None,fset=None,fdel=None):
  3.                 self.fget = fget
  4.                 self.fset = fset
  5.                 self.fdel = fdel
  6.         def __get__(self,instance,owner):
  7.                 print("MyProperty.__get__")
  8.                 return self.fget(instance)
  9.         def __set__(self,instance,value):
  10.                 print("MyProperty.__set__")
  11.                 self.fset(instance,value)
  12.         def __delete__(self,instance):
  13.                 print("MyProperty.__delete__")
  14.                 self.fdel(instance)
  15. class C:
  16.         def __init__(self):
  17.                 print("C.__init__")
  18.                 self._x = None
  19.         def getX(self):
  20.                 print("C.getX")
  21.                 return self._x
  22.         def setX(self,value):
  23.                 self._x = value
  24.                 print("C.setX")
  25.         def delX(self):
  26.                 print("C.delX")
  27.                 del self._x
  28.         x = MyProperty(getX, setX, delX)#C类属性放一个对象MyProperty的实例赋值给x
  29. print("创建C类对象c")
  30. c=C()
  31. print("修改描述器同名属性值")
  32. c.x='X_Man'     # 修改描述器同名属性值,会调用数据描述器MyProperty的__set__方法
  33. print("访问描述器同名属性值")
  34. print(c.x)     # 访问描述器同名属性值,会调用数据描述器MyProperty的__get__方法
  35. print("下面这句不会触发描述器")
  36. print(c._x)
复制代码

运行结果
  1. 创建C类对象c
  2. C.__init__
  3. 修改描述器同名属性值
  4. MyProperty.__set__
  5. C.setX
  6. 访问描述器同名属性值
  7. MyProperty.__get__
  8. C.getX
  9. X_Man
  10. 下面这句不会触发描述器
  11. X_Man
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-4-4 02:28:18 | 显示全部楼层
sunrise085 发表于 2020-4-4 00:57
我不知道你对__get__()和__set__()有多少理解。python中如果一个类实现了__get__、__set__、__delete__三 ...

我分析的步骤:c.x='X-man'→__set__(c.x,c,C)→setX(c,'X-man)→c._x='X-man'
我不懂的是c.x在哪一步骤被赋值的,从我分析的步骤中看只有c._x被赋值
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-4 02:32:00 | 显示全部楼层
麻麦皮 发表于 2020-4-4 02:28
我分析的步骤:c.x='X-man'→__set__(c.x,c,C)→setX(c,'X-man)→c._x='X-man'
我不懂的是c.x在哪一步骤 ...

程序第32行,就是修改c.x的属性值啊,将'X-man'赋值给了c.x,然后才有了后面的一系列操作啊
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-4-4 02:45:55 | 显示全部楼层
sunrise085 发表于 2020-4-4 02:32
程序第32行,就是修改c.x的属性值啊,将'X-man'赋值给了c.x,然后才有了后面的一系列操作啊

懂了,我想太多了...
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-5-6 01:37

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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