前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >trick(八)、类的Properties

trick(八)、类的Properties

作者头像
狼啸风云
发布2022-09-30 11:18:58
1310
发布2022-09-30 11:18:58
举报

property最大的用处就是可以为一个属性制定getter,setter,delete和doc,函数原型为:

代码语言:javascript
复制
    def __init__(self, fget=None, fset=None, fdel=None, doc=None): # known special case of property.__init__
        """
        property(fget=None, fset=None, fdel=None, doc=None) -> property attribute
        
        fget is a function to be used for getting an attribute value, and likewise
        fset is a function for setting, and fdel a function for del'ing, an
        attribute.  Typical use is to define a managed attribute x:
        
        class C(object):
            def getx(self): return self._x
            def setx(self, value): self._x = value
            def delx(self): del self._x
            x = property(getx, setx, delx, "I'm the 'x' property.")
        
        Decorators make defining new properties or modifying existing ones easy:
        
        class C(object):
            @property
            def x(self):
                "I am the 'x' property."
                return self._x
            @x.setter
            def x(self, value):
                self._x = value
            @x.deleter
            def x(self):
                del self._x
        
        # (copied from class doc)
        """
        pass

从上边的代码中可以看出来,它一共接受4个参数,我们再继续看一段代码:

代码语言:javascript
复制
class Rectangle(object):
    def __init__(self, x1, y1, x2, y2):
        self.x1, self.y1 = x1, y1
        self.x2, self.y2 = x2, y2

    def _width_get(self):
        return self.x2 - self.x1

    def _width_set(self, value):
        self.x2 = self.x1 + value

    def _height_get(self):
        return self.y2 - self.y1

    def _height_set(self, value):
        self.y2 = self.y1 + value

    width = property(_width_get, _width_set, doc="rectangle width measured from left")
    height = property(_height_get, _height_set, doc="rectangle height measured from top")

    def __repr__(self):
        return "{}({}, {}, {}, {})".format(self.__class__.__name__,
                                           self.x1,
                                           self.y1,
                                           self.x2,
                                           self.y2)


rectangle = Rectangle(10, 10, 30, 15)
print(rectangle.width, rectangle.height)
rectangle.width = 50
print(rectangle)
rectangle.height = 50
print(rectangle)
print(help(rectangle))


Output:
-----------------------------------------------------------------------------------------
20 5
Rectangle(10, 10, 60, 15)
Rectangle(10, 10, 60, 60)
Help on Rectangle in module __main__ object:

class Rectangle(builtins.object)
 |  Methods defined here:
 |  
 |  __init__(self, x1, y1, x2, y2)
 |      Initialize self.  See help(type(self)) for accurate signature.
 |  
 |  __repr__(self)
 |      Return repr(self).
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
 |  
 |  height
 |      rectangle height measured from top
 |  
 |  width
 |      rectangle width measured from left

None
-----------------------------------------------------------------------------------------

通过property,我们有能力创造出一个属性来,然后为这个属性指定一些方法,在这里用setter,getter的好处就是可以监听属性的赋值和获取行为,表面上看上去上边的代码没有问题,但是当出现继承关系的时候,就出问题了。

代码语言:javascript
复制
class MetricRectangle(Rectangle):
    def _width_get(self):
        return "{} metric".format(self.x2 - self.x1)


mr = MetricRectangle(10, 10, 100, 100)
print(mr.width)

Output:
---
90
---

即使我们在子类中重写了getter方法,结果却是无效的,这说明property只对当前的类生效,于是不得不把代码改成下边这样:

代码语言:javascript
复制
class MetricRectangle(Rectangle):
    def _width_get(self):
        return "{} metric".format(self.x2 - self.x1)

    width = property(_width_get, Rectangle.width.fset)


mr = MetricRectangle(10, 10, 100, 100)
print(mr.width)

Output:
----------
90 metric
----------

因此,在平时的编程中,如果需要重写属性的话,应该重写该类中所有的property,否则程序很很难以理解,试想一下,setter在子类,getter在父类,多么恐怖,另一种比较好的方案是使用装饰器,可读性也比较好。

代码语言:javascript
复制
class Rectangle(object):
    def __init__(self, x1, y1, x2, y2):
        self.x1, self.y1 = x1, y1
        self.x2, self.y2 = x2, y2

    @property
    def width(self):
        """rectangle width measured from left"""
        return self.x2 - self.x1

    @width.setter
    def width(self, value):
        self.x2 = self.x1 + value

    @property
    def height(self):
        return self.y2 - self.y1

    @height.setter
    def height(self, value):
        self.y2 = self.y1 + value

    def __repr__(self):
        return "{}({}, {}, {}, {})".format(self.__class__.__name__,
                                           self.x1,
                                           self.y1,
                                           self.x2,
                                           self.y2)


rectangle = Rectangle(10, 10, 30, 15)
print(rectangle.width, rectangle.height)
rectangle.width = 50
print(rectangle)
rectangle.height = 50
print(rectangle)
print(help(rectangle))


Output:
-----------------------------------------------------------------------------------------
20 5
Rectangle(10, 10, 60, 15)
Rectangle(10, 10, 60, 60)
Help on Rectangle in module __main__ object:

class Rectangle(builtins.object)
 |  Methods defined here:
 |  
 |  __init__(self, x1, y1, x2, y2)
 |      Initialize self.  See help(type(self)) for accurate signature.
 |  
 |  __repr__(self)
 |      Return repr(self).
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
 |  
 |  height
 |  
 |  width
 |      rectangle width measured from left

None

-----------------------------------------------------------------------------------------
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-09-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档