使用property为类中的数据添加行为

Posted anovana

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用property为类中的数据添加行为相关的知识,希望对你有一定的参考价值。

对于面向对象编程特别重要的是,关注行为和数据的分离

在这之前,先来讨论一些“坏”的面向对象理论,这些都告诉我们绝不要直接访问属性(如Java):

class Color:
    def __init__(self, rgb_value, name):
        self._rgb_value = rgb_value
        self._name = name

    def set_name(self, name):
        self._name = name

    def get_name(self):
        return self._name

前缀有一个单下划线的变量表明他们是类私有的,接着get和set方法提供了对每个变量的访问方式,这个类在实际使用中一般采用如下的方式:

>>> c = Color(#ff0000, bright red)
>>> c.get_name()
bright red
>>> c.set_name(red)
>>> c.get_name()
red

这并不像python喜欢的直接访问方式具有可读性:

class Color:
    def __init__(self, rgb_value, name):
        self.rgb_value = rgb_value
        self.name = name

调用如下:

>>> c = Color(#ff0000, bright red)
>>> print(c.name)
bright red
>>> c.name = "red"
>>> print(c.name)
red

Java的这种方式方便在需要这些变量被赋值时添加额外的代码,例如我们想要验证输入值是否合理,则可以改变set_name()方法来实现:

def set_name(self, name):
    if not name:
        raise Expception("Invalid Name")
    self._name = name

 但是这样会有一个问题,采用直接访问属性方法的代码,现在必须通过调用方法才能访问原有的属性,如果他们不改变自己的访问方式,那么代码就被破坏了。

而在python中可以使用property关键字来处理该问题,加入我们原本使用直接成员访问的方法取访问属性,之后我们可以增加几个方法,在不改变访问接口的情况下,来对name这个变量进行取值和赋值。

class Color:
    def __init__(self, rgb_value, name):
        self.rgb_value = rgb_value
        self._name = name

def _set_name(self, name):
        if not name:
            raise Exception("Invalid Name")
        self._name = name

    def _get_name(self):
        return self._name

    name = property(_get_name, _set_name)

先将name这个属性改为一个(半)私有的_name属性,接着我们添加两个(半)私有方法对这个变量进行取值和赋值,并在赋值的时候进行验证。最后我们在代码底部使用property关键字进行声明。

现在Color类拥有了一个全新的name属性,这个name属性变为了一个property属性,需要通过调用我们刚刚添加的两个方法才能访问或者改变其值。而Color类仍能以前一个版本中相同的方式来使用,同时它还能支持对name赋值时进行验证

>>> c = Color(#ff0000, bright red)
>>> print(c.name)
bright red
>>> c.name = red
>>> print(c.name)
red
>>> c.name =""
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "color2.py", line 8, in _set_name
    raise Exception("Invalid Name")
Exception: Invalid Name

这样,我们之前编写的任何代码仍然能够工作,但是,即便name变成了property属性,也不能保证100%的安全,如果有人使它设定为空字符串值,仍然可以通过直接访问_name属性的方式来达到目的。

 property是怎样工作的

property函数实际上返回了一个对象,该对象通过我们指定的方法代理了全部对属性值访问或赋值的请求。

property构造函数实际上还可以接受两个额外的参数:一个删除函数和一个property的文本字符串。在实际中很少用到删除函数,但是如果需要用到记录所删除的值,那么删除函数还是很有用的。同时在我们满足某个条件的情况下,删除函数还可以否决删除操作。文本字符串是一个用来描述该property的字符串。如果我们不提供文本字符串这个参数,那么该值将从property的第一个参数,也就是getter方法的文本字符串中复制过来。

 

 

参考:

1、《Python3 面向对象编程》 [加]Dusty Philips 著

以上是关于使用property为类中的数据添加行为的主要内容,如果未能解决你的问题,请参考以下文章

从片段类中的对话框添加项目到recyclerview。

面向对象

python 反射为类添加静态属性#setattr#@ property

@property 的本质是什么?ivargettersetter 是如何生成并添加到这个类中的

将闭包定义为类中的方法

如何在 NSObject 类中添加动态行为:Swift