鱼C论坛

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

[技术交流] 46讲描述符章节和property()的理解

[复制链接]
发表于 2018-6-5 15:43:16 | 显示全部楼层 |阅读模式

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

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

x
在第46讲,小甲鱼讲了有关描述符的知识,看完十几分钟的视频有点懵逼。下来自己又仔细思考了一下,记了一些笔记。主要还是对小甲鱼的两个例子,加上自己个人的理解解读。欢迎大家批评指正,共同学习。


描述符
描述符就是 将某种特殊类型的类的实例指派给另一个类的属性。
有关的魔法方法有以下三种:
__get__(self,instance,owner):
用于访问属性,它返回属性的值。

__set__(self,instance,value):
将在属性分配操作中调用,不返回任何内容。

__delete__(self,instance):
控制删除操作,不返回任何内容。

所谓特殊类型的类,就是含有以上三种魔法方法的类。然后把这个特殊的类的实例,指派给另一个类的属性(注意是类属性!!!而非实例属性。见后文。)。例如如下代码示例:
=======================================================================
class mydescriptor:
   def __get__(self,instance,owner):
      print('gettttttt',self,instance,owner)

   def __set__(self,instance,value):
      print('settttttt',self,instance,value)

   def __delete__(self,instance):
      print('delllllll',self,instance)

class Test:
   x = mydescriptor()                        # x为Test的类属性
=======================================================================
定义了一个mydescriptor的类,重写了 __get__  __set__  __delete__ 魔法方法。然后又定义了一个Test的类,将mydescriptor的类实例化,然后指派给Test的属性x。
运行后结果如图1:

图1

图1

图2

图2

输入Test的实例化加上·之后,会自动弹出来相应的属性x,如图2。接下来对实例化对象,通过x进行操作,结果如图3:

图3

图3

可以看出 __set__(self,instance,value)的三个参数分别为:
self 指的就是tst.x这个经过mydescriptor()实例化后的对象(而它本身又是Test类的一个属性,实例化后的Test类对象也可以访问这个属性);instance 指的就是tst这个Test类实例化后的对象;value则是要赋给x这个属性的值,也就是30.
__get__(self,instance,owner) 中的owner指的是,Test 这个类对象本身。
而其中的self,instance以及 __delete__中的相应参数意义同上。
但是进行del tst.x操作后,访问tst.x依然可以,没有报错。因为这里只是通过tst.x执行了mydescriptor中的__delete__ 操作,而不是执行删除类属性的操作,所以tst.x还可以访问,没有问题。


下一个例子——实现自己的property()函数:
=======================================================================
class myypro:
   def __init__(self,fget = None,fset = None,fdel = None):
      self.fget = fget
      self.fset = fset
      self.fdel = fdel

   def __get__(self,instance,owner):
      print('动静のget')
      return self.fget(instance)

   def __set__(self,instance,value):
      print('有点动静のset')
      self.fset(instance,value)

   def __delete__(self,instance):
      print('一不小心9删掉了')
      self.fdel(instance)

class C:
   def __init__(self):
      self.xx = None

   def getx(self):
      return self.xx

   def setx(self,value):
      self.xx = value

   def delx(self):
      del self.xx

   x = myypro(getx,setx,delx)
=======================================================================
执行结果如图4:

图4

图4

实例化一个c1,然后通过c1.x对c1.xx进行赋值,执行myypro()中的 __set__方法。
然后输入: c1.x 和c1.xx 结果都为30. 利用del c1.x删除c1.xx,直接删除掉xx这个属性,若是再访问就会报错,提示C这个类没有xx这个属性。(这里c1.x就是类属性,而c1.xx则是实例属性)

整个过程理解起来就是:C是一个商人,getx、setx、delx是机器,而xx这个属性可以是材料。对这些材料进行加工,进行一系列操作,如果利用c1.get()等这些操作也可以,但是每次需要调用不同的方法(可以理解为需要不同的工人),比较麻烦,效率比较低。于是就从外面请了一个人,这个人能力比较强,什么都会,然后商人给了他一定的权利让他可以使用自己的机器来加工材料。这个人就是myypro!

譬如执行c1.x = 30 赋值操作的时候,C的实例化对象c1的属性c1.x是myypro的实例化对象,当对c1.x进行赋值的时候,会自动调用myypro中的 __set__ 方法,根据上面一个例子可以知道, __set__(self,instance,value)方法的参数self是c1的属性x;instance 是C的实例化对象c1,而value 是 赋值等式中右端的值,在这里也就是30。
又因为在myypro的 __init__方法中,定义了 self.fset = fset,而在C这个类对象中有 x = myypro(getx,setx,delx),因此self.fset也就等于传入的参数setx了,也就是说在myypro中,__set__ 方法中的 self.fset(instance,value) 也就等于C中的
setx(self,value)。并且两者对应完全一致。后者中的self也就是指c1,而前者中的instance也是c1,后面的value值也一样。因此就间接的通过x这个接口,实现了C中setx的功能,对c1.xx实现了赋值。后面的c1.x  和 del c1.x的操作分析类似。
这样就可以实现小甲鱼在前面讲property()方法章节时所说的,只给用户一个端口,就可以进行赋值和删除等操作,而避免用户直接去执行getx、setx、delx这些函数,对用户来说是一个很好的体验。描述符以及property()函数的意义也就在于此!!!

类属性和实例属性
参照学习以下网站链接:
https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014319117128404c7dd0cf0e3c4d88acc8fe4d2c163625000

https://www.cnblogs.com/wgDream/p/6749643.html

由于python是动态语言,根据类创建的实例可以绑定任意属性。
给实例绑定属性的方法是通过实例变量,或者通过self变量:
=======================================================================
class Student():
    def __init__(self,name):
        self.name = name

s = Student('xiaoyang')
s.score = 90
=======================================================================
这里通过 __init__ 方法定义的 self.name是实例化对象的属性,通过实例化对象s可以访问到;绑定属性也可以直接赋值的操作,例如 s.score = 90 来实现。
利用s.__dict__可以看到,如下图5:

图5

图5

此时,利用类对象Student来访问name等属性,就不行了。因为这些属性都是实例化对象的属性,而非类属性。如图6:

图6

图6

如果一个类本身需要一个属性,可以直接在class中定义属性,这种属性是类属性,归类所有,如下:
=======================================================================
class Student():
name = 'xiaoyang'
=======================================================================
这个name就是类属性,归类所有,但是所有的实例对象都可以访问到。

图7

图7

如果再给实例化对象绑定属性,那么实例属性将会改变,而不会改变类属性。

图8

图8

此时若删除实例属性的话,不会改变类属性,而是删掉了刚才赋值的新的实例属性,这时调用 s.name,由于实例的name属性没有找到,类的name属性就显示出来了。
若是删掉类属性的话,不会改变实例属性,如图9:

图9

图9

廖雪峰网站的总结:
1.实例属性属于各个实例所有,互不干扰;
2.类属性属于类所有,所有实例共享一个属性;
3.不要对类属性和实例属性使用相同的名字,否则将产生难以发现的错误。
因此一定要区分类属性和实例属性
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-11-7 13:33:28 | 显示全部楼层
很详细,学习了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-11-8 09:34:38 | 显示全部楼层
谢谢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-2-26 13:12:12 | 显示全部楼层
谢谢,有一个问题不太明白。
__set__ 方法中的 self.fset(instance,value) 也就等于C中的
setx(self,value)。并且两者对应完全一致。
也就是说,在执行c1.x = 30时,自动调用myypro的__set__方法,也就是执行print('有点动静のset')和self.fset(instance,value)语句。
确实,执行self.fset(instance,value)就等于执行setx(self,value)。
我的疑问是,运行setx(self,value)语句是如何操作的?调用方法不是应该self.setx(value)吗?我表达的清楚吗?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-5-27 13:34:07 | 显示全部楼层
本帖最后由 Tigeroad 于 2020-5-27 13:47 编辑
jiajiaself 发表于 2020-2-26 13:12
谢谢,有一个问题不太明白。
__set__ 方法中的 self.fset(instance,value) 也就等于C中的
setx(self,valu ...


在class C中已经定义了函数了:
def setx(self,value):
      self.xx = value
到你说的那一步就是一个简单的调用函数的问题。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-7-17 20:11:57 | 显示全部楼层
评论下,免得之后找不到O
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-7-17 20:14:46 From FishC Mobile | 显示全部楼层
有点小乱……
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-8-4 18:47:10 | 显示全部楼层
写的超棒!!!!!!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-11-15 16:42:55 | 显示全部楼层

谢谢,能帮到你,很开心
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-11-15 16:43:27 | 显示全部楼层

谢谢你的夸奖,大家一起学习。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-11-15 16:44:58 | 显示全部楼层

自己的语言组织能力还有待提高。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-11-15 16:45:48 | 显示全部楼层
鼋头鱼 发表于 2020-7-17 20:11
评论下,免得之后找不到O

哈哈,谢谢支持
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-1-17 17:54

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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