脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Python - Python中property属性的用处详解

Python中property属性的用处详解

2022-11-25 11:44九柄 Python

这篇文章主要给大家介绍了关于Python中property属性的相关资料,需简单地说就是一个类里面的方法一旦被@property装饰,就可以像调用属性一样地去调用这个方法,它能够简化调用者获取数据的流程,而且不用担心将属性暴露出来,有人对其

前言

Python 动态属性的概念可能会被面试问到,在项目当中也非常实用,但是在一般的编程教程中不会提到,可以进修一下。

先看一个简单的例子。创建一个 Student 类,我希望通过实例来获取每个学生的一些情况,包括名字,成绩等。成绩只有等到考试结束以后才会有,所以实例化的时候不会给它赋值。

?
1
2
3
4
5
6
class Student:
    def __init__(self, name):
        self.name = name
        self.score = None
 
mike = Student('mike')

考试完以后,准备给 mike 打分:

?
1
mike.score = 999

在这里,老师一不小心多打了个 9 ,通常来说打分都是 100 分值,999 是一个非法数据,不应该赋值成功。学生一多,老师打分出现手误的情况肯定会越来越多,所以我们必须想办法修改程序,限制 score 的值必须在 0-100 分。

限制值

我们定义一个方法,如果输入的不是 0-100 的整数,就让程序报错,数据合法,我们就把 score 属性修改成功。

?
1
2
3
4
5
6
7
8
9
def set_score(self, new_score):
    if not isinstance(new_score, int):
        raise ValueError('score must be int')
 
    if 0 <= new_score <= 100:
        self.score = new_score
        return self.score
    else:
        raise ValueError('score invalid')

这样我们每次需要获取成绩的时候使用 self.score 获取,修改成绩的时候调用函数来修改:

?
1
mike.set_score(999)

调用以后会报错,因为 999 是非法数据。注意,这个时候我使用 self.score 还是可以进行设置,而且不报错:

?
1
self.score = 999

这显然是不行的。所以我们要提供一种机制,把 score 变成私有属性,不能让外部访问。很遗憾,python 的私有属性是伪私有。通常我们把 _ 开头的属性叫私有属性,但是这只是一种协议和规定,你看到下划线开头的属性,不要去访问了。你硬要访问,是可以的,python 并不会禁止。

使用 @property 的方式代替。

上面的方法虽然实现了功能,但是改变了属性的使用方式。平常是这样使用的:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 获取属性
a = mike.score
# 设置属性
mike.score = 99
 
@property
def score(self):
    return self._score
 
@score.setter
def score(self, new_score):
    if not isinstance(new_score, int):
        raise ValueError('score must be int')
 
        if 0 <= new_score <= 100:
            self._score = new_score
            return self._score
        else:
            raise ValueError('score invalid')

动态属性的好处

  • 统一了调用方式。self.score = 99 的方式,而不是函数调用的方式。
  • _score 我们就不直接去使用了。你要用也可以,不建议。
  • 如果我们一个属性只可以读,把 setter 部分注释掉就可以了。

现在我们来完善这个类,添加 birth 属性和年龄属性:

?
1
2
3
4
5
6
7
8
9
10
11
12
from datetime import datetime
 
class Student:
    def __init__(self, name, birth=1920):
        self.name = name
        self._score = None
        self.birth = birth
        self.age = datetime.now().year - self.birth
 
mike = Student('mike')
print(mike.birth)
print(mike.age)
  • birth 和 age 这两个是可以根据一个求出另外一个的。存在数据冗余问题。

  • age 属性这样是有问题的。mike 初始化的时候,age 已经被求出来了,如果我在下一年再去访问 age 属性,那他就是个错误的值。可以通过把 age 设成现在的秒数来验证:

    ?
    1
    2
    3
    4
    5
    6
    self.age = datetime.now().second
     
    mike = Student('mike')
    time.sleep(5)
    print(mike.age)
    print(datetime.now().second)

动态显示

?
1
2
3
@property
def age(self):
    return datetime.now().year - self.birth

注意,这里不要去设置 @age.setter ,因为他是动态变化的,你修改了会造成数据不一致,它只能作为一个只读属性。

@property 作用和应用场景:

  • @property 优化了属性读取和设置的可读性
  • 需要限制属性的特征;
  • 只读属性。如果属性只可以读,不可以写,用起来很方便。
  • 这个属性根据一个变化的环境动态改变。

附:用property代替getter和setter方法

?
1
2
3
4
5
6
7
8
9
10
11
12
>>>class Watermelon():
       def __init__(self,price):
           self._price = price                  #私有属性,外部无法修改和访问
 
       def get_price(self):
           return self._price
 
       def set_price(self,new_price):
           if new_price > 0:
               self._price = new_price
           else:
               raise 'error:价格必须大于零'

用property代替getter和setter

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
>>>class Watermelon():
       def __init__(self,price):
           self._price = price
 
       @property                          #使用@property装饰price方法
       def price(self):
           return self._price
 
       @price.setter                      #使用@property装饰方法,当对price赋值时,调用装饰方法
       def price(self,new_price):
           if new_price > 0:
               self._price = new_price
           else:
               raise 'error:价格必须大于零'
 
>>> watermelon = Watermelon(4)
>>>
>>> watermelon.price
4
>>>
>>> watermelon.price = 7
>>>
>>> watermelon.price
7

总结

到此这篇关于Python中property属性用处的文章就介绍到这了,更多相关Python中property属性内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://juejin.cn/post/7084604734471929863

延伸 · 阅读

精彩推荐
  • PythonPython字符编码判断方法分析

    Python字符编码判断方法分析

    这篇文章主要介绍了Python字符编码判断方法,结合实例形式分析了Python字符编码的判断技巧,并给出了chardet的安装与使用方法,需要的朋友可以参考下...

    dkcndk4662020-08-31
  • Pythonpython 通过SSHTunnelForwarder隧道连接redis的方法

    python 通过SSHTunnelForwarder隧道连接redis的方法

    今天小编就为大家分享一篇python 通过SSHTunnelForwarder隧道连接redis的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    __Jack12792021-05-30
  • PythonPython中的time模块和calendar模块

    Python中的time模块和calendar模块

    这篇文章主要介绍了Python中的time模块和calendar模块,在Python中对时间和日期的处理方式有很多,其中转换日期是最常见的一个功能。Python中的时间间隔是以...

    一碗周10122022-02-23
  • PythonPython基于traceback模块获取异常信息

    Python基于traceback模块获取异常信息

    这篇文章主要介绍了Python基于traceback模块获取异常信息,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可...

    bashliuhe2642020-07-23
  • PythonPython动态加载模块的3种方法

    Python动态加载模块的3种方法

    这篇文章主要介绍了Python 动态加载模块的3种方法,本文分别使用使用系统函数__import_()、使用imp 模块、使用exec三种方法实现,需要的朋友可以参考下 ...

    脚本之家13772020-05-15
  • Pythonpython 线程的暂停, 恢复, 退出详解及实例

    python 线程的暂停, 恢复, 退出详解及实例

    这篇文章主要介绍了python 线程的暂停, 恢复, 退出详解及实例的相关资料,需要的朋友可以参考下...

    scolia6202020-09-13
  • PythonDjango与JS交互的示例代码

    Django与JS交互的示例代码

    本篇文章主要介绍了Django与JS交互的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    pNull4762020-12-03
  • PythonPython编程中装饰器的使用示例解析

    Python编程中装饰器的使用示例解析

    这篇文章主要介绍了Python编程中装饰器的使用示例解析,包括装饰函数和方法,含参的装饰器以及装饰类这三个方面,需要的朋友可以参考下...

    JeffLi19933892020-08-28