首先先介绍一下property的类,因为需要深入了解property就随便了解了下描述符,property实现就用了这个功能。

property以前在我脑子里面就是方法转属性的装饰圈,现在回想虽然也对,但只不过是里面功能的冰山一角。

首先介绍property的用法,后面上代码:

In [11]: class Rectange:
    ...:     def __init__(self):
    ...:         self.width = 0
    ...:         self.height = 0
    ...:
    ...:     def set_size(self, size):
    ...:         self.width, self.height = size
    ...:
    ...:     def get_size(self):
    ...:         return self.width, self.height
    ...:
    ...:     def del_size(self):
    ...:         del self.width,self.height
    ...:
    ...:     size = property(get_size, set_size, del_size)
    ...:

In [12]: r = Rectange()

In [13]: r.size
Out[13]: (0, 0)

In [14]: r.size = 5,5

In [15]: r.size
Out[15]: (5, 5)

In [16]: r.height
Out[16]: 5

In [17]: del r.size

In [18]: r.size
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-18-f01c9e7af2ea> in <module>
----> 1 r.size

<ipython-input-11-6b0a6fffb0c4> in get_size(self)
      8
      9     def get_size(self):
---> 10         return self.width, self.height
     11
     12     def del_size(self):

AttributeError: 'Rectange' object has no attribute 'width'

In [19]: r.height
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-19-9fec4be02cd3> in <module>
----> 1 r.height

AttributeError: 'Rectange' object has no attribute 'height'

 根据实际操作,size已变成了property的实例,调用size可以对多属性进行查询,复制,删除,使用起来非常的方便。

property后面后面共有四个关键字参数,fget,fset,fdel,doc,doc参数我没用过,官方解释是一个带文档字符串的特性。

所以在实例化的时候必须关键词参数的顺序输入读取属性,写入属性,删除操作的顺序

这是第二种property的使用,效果都一样,这个用的是装饰器的用法。(非常不好用)

In [36]: class Rectange:
    ...:     def __init__(self):
    ...:         self.width = 0
    ...:         self.height = 0
    ...:
    ...:     @property
    ...:     def size(self):
    ...:         return self.width, self.height
    ...:
    ...:     @size.setter
    ...:     def size(self, size):
    ...:         self.width, self.height = size
    ...:
    ...:
    ...:     @size.deleter
    ...:     def size(self):
    ...:         del self.width,self.height
    ...:

In [37]:

In [37]: r= Rectange()

In [38]: r.size = 3,4

In [39]: r.size
Out[39]: (3, 4)

In [40]: del r.size

In [41]: r.height
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-41-9fec4be02cd3> in <module>
----> 1 r.height

AttributeError: 'Rectange' object has no attribute 'height'

 为什么不好用,首相你定义的方法名必须相同,经过我的测试@property必须用在读取参数身上,麻烦的是不能单独设置写入的property

In [47]: class Rectange:
    ...:     def __init__(self):
    ...:         self.width = 0
    ...:         self.height = 0
    ...:
    ...:
    ...:     def dsize(self):
    ...:         return self.width, self.height
    ...:
    ...:     @property
    ...:     def size(self, size):
    ...:         self.width, self.height = size
    ...:
    ...:
    ...:
    ...:     def dsize(self):
    ...:         del self.width,self.height
    ...:

In [48]: r = Rectange()

In [49]: r.size=3,4
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-49-08f82adabb51> in <module>
----> 1 r.size=3,4

AttributeError: can't set attribute

 这个就是说,方法转函数限制条件很多,如果是读取的话,问题不大,如果是带参数写入,必须先定义一个读取,一个写入,不能单独把写入的方法改成属性复制。

总体使用下来,强烈推荐用property的类实例话对多方法进行合并成一个对象属性进行操作。

为什么property能够实行这个功能呢,那是因为__get__,__set__,__delete__魔方函数定义了描述符。

概念:描述符就是将某种特殊类型的类的实例指派给另一个类的属性。

In [56]: class MyDescriptor:
    ...:     def __get__(self, instance, owner):
    ...:         print('__get__output=====>', instance, owner,self)
    ...:
    ...:     def __set__(self, instance, value):
    ...:         print('__set__output=====>' , instance, value)
    ...:
    ...:     def __delete__(self, instance):
    ...:         print('__delete__output=====>', instance)
    ...:
    ...: class Test:
    ...:     x = MyDescriptor()
    ...:

In [57]: t = Test()

In [58]: t.x
__get__output=====> <__main__.Test object at 0x10e9ca710> <class '__main__.Test'> <__main__.MyDescriptor object at 0x10de16210>

In [59]: t
Out[59]: <__main__.Test at 0x10e9ca710>

In [60]: t.x = 20
__set__output=====> <__main__.Test object at 0x10e9ca710> 20

In [61]: Test
Out[61]: __main__.Test

其实从代码中可以看出来,在描述符里面任何一个参数里面都有这instance,这个instance就是用户描述符类属性实例化的对方,案例这里面就是t。

对x的属性进行读取,复制都会在描述符对应里面的__get__,__set__函数里面都将执行。

In [63]: class MyProperty:
    ...:     def __init__(self, fget=None, fset=None, fdel=None):
    ...:         self.fget = fget
    ...:         self.fest = fset
    ...:         self.fdel = fdel
    ...:
    ...:     def __get__(self, instance, owner):
    ...:         return self.fget(instance)
    ...:
    ...:     def __set__(self, instance, value):
    ...:         self.fest(instance, value)
    ...:
    ...:     def __delete__(self, instance):
    ...:         self.fdel(instance)
    ...:
    ...: class Demo:
    ...:     def __init__(self):
    ...:         self.vv = None
    ...:
    ...:     def getvv(self):
    ...:         return self.vv
    ...:
    ...:     def setvv(self,value):
    ...:         self.vv = value
    ...:
    ...:     def delvv(self):
    ...:         del self.vv
    ...:
    ...:     cute = MyProperty(getvv, setvv, delvv)
    ...:

In [64]: dd =Demo()

In [65]: dd.cute = 5

In [66]: dd.cute
Out[66]: 5

In [67]: del dd.cute

In [68]: dd.cute
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-68-b9d4fbd43102> in <module>
----> 1 dd.cute

<ipython-input-63-86b6cb623d25> in __get__(self, instance, owner)
      6
      7     def __get__(self, instance, owner):
----> 8         return self.fget(instance)
      9
     10     def __set__(self, instance, value):

<ipython-input-63-86b6cb623d25> in getvv(self)
     19
     20     def getvv(self):
---> 21         return self.vv
     22
     23     def setvv(self,value):

AttributeError: 'Demo' object has no attribute 'vv'

上面的代码展示了自己编写property的效果,跟官方的比较像了,上面定义了property针对不同的操作进行的操作返回不同的操作,property里面拥有需要操作的实例与传入的方法,所以定义具体的操作非常方便。

为了强化学习,我从一本书中抄写了一串代码强化记忆。

In [76]: class Celsius:
    ...:     def __init__(self, value = 26):
    ...:         self.value = float(value)
    ...:
    ...:     def __get__(self, instance, owner):
    ...:         return self.value
    ...:
    ...:     def __set__(self, instance, value):
    ...:         self.value = float(value)
    ...:
    ...: class Fahrenheri:
    ...:     def __get__(self, instance, owner):
    ...:         return instance.cel * 1.8 + 32
    ...:
    ...:     def __set__(self, instance, value):
    ...:         instance.cel = (float(value) -32) /1.8     # 设置华氏度温度后,返回给实例复制cel,执行Celsius的s
    ...: et功能,并复制更新。
    ...:

In [77]: class Temperatrye:
    ...:     cel = Celsius()
    ...:     fah = Fahrenheri()
    ...:

In [78]: temp = Temperatrye()

In [79]: temp.cel
Out[79]: 26.0

In [80]: temp.fah
Out[80]: 78.80000000000001

In [81]: temp.fah = 250

In [82]: temp.cel
Out[82]: 121.11111111111111

 上面代码通过两个描述符对属性进行不同的切换,我觉的还是很有意思的。记号下。

et功能,并复制更新。
[Et gōngnéng, bìng fùzhì gēngxīn.]
et function, and copy the update.
 
01-03 08:04
查看更多