翼度科技»论坛 编程开发 python 查看内容

python使用property完成数据隐藏封装与校验

4

主题

4

帖子

12

积分

新手上路

Rank: 1

积分
12
禁止随意设置属性


需求

考虑这样一种情况,在某一个类中,有一个属性我们不希望别人随便设置,因为这可能会造成很大的麻烦:
  1. class Rectangle:
  2.     def __init__(self, width, height):
  3.         self.width = width
  4.         self.height = height
  5.    
  6.     def calculate_area(self):
  7.         return self.width * self.height


  8. r = Rectangle(3, 4)
  9. print(r.calculate_area())
复制代码
在这种情况下,长度和宽度都应该是数字类型的,而如果有人在这个过程中修改了这个属性,那么就会导致错误。
  1. r = Rectangle(3, 4)
  2. r.width = "3"
  3. print(r.calculate_area())  # 结果为3333,明显不是我们希望的结果
复制代码
私有属性

为了避免他人随意访问,我们可以将其设置为私有属性,通常可以添加1个或者2个下划线。
  1. class Rectangle:
  2.     def __init__(self, width, height):
  3.         # 一个下划线通常表明了,这个属性不应该随意使用,但是不起实际作用
  4.         self._width = width
  5.         
  6.         # 两个下划线表明了,这个属性会触发名称重整,但是也并非真正的私有
  7.         self.__height = height
  8.         
  9.         
  10. r = Rectangle(3, 4)
  11. print(r._width)

  12. # 双下划线最终会重整为_类名__属性名的形式
  13. print(r._Rectangle__height)
复制代码
需要注意的是,由于python中没有真正的私有属性,所以,这两种设置方法都不能完全起到作用,但是一般而言,两个下划线是更好的,因为可以触发名称重整。

提供访问方法

在这种情况下,为了避免他人随意设置属性,因此需要提供专门的访问方法。
  1. class Rectangle:
  2.     def __init__(self, width, height):
  3.         self.set_width(width)
  4.         self.set_height(height)

  5.     def set_width(self, width):
  6.         if not isinstance(width, (int, float)):
  7.             raise ValueError("width must be a number.")
  8.         if width <= 0:
  9.             raise ValueError("width must be greater than 0.")
  10.         self.__width = width

  11.     def set_height(self, height):
  12.         if not isinstance(height, (int, float)):
  13.             raise ValueError("height must be a number.")
  14.         if height <= 0:
  15.             raise ValueError("height must be greater than 0.")
  16.         self.__height = height

  17.     def get_width(self):
  18.         return self.__width

  19.     def get_height(self):
  20.         return self.__height

  21. r = Rectangle(3, 4)

  22. # 此时需要通过专门的方法进行访问
  23. print(r.get_width())

  24. # 非法的设置不再被允许
  25. r.set_width("3")
复制代码
但是这样的使用方法并不方便,因此,在python中,一个更好的使用方法是通过property。

property的详细介绍


基本语法

基本语法实现是通过property的内置函数完成的
  1. class MyClass:
  2.     def __init__(self, value):
  3.         self.value = value

  4.     # get方法
  5.     def get_value(self):
  6.         return self.__value

  7.     # set方法
  8.     def set_value(self, value):
  9.         if value < 0:
  10.             raise ValueError("value must be non-negative.")
  11.         self.__value = value

  12.     # del方法
  13.     def del_value(self):
  14.         print("value is being deleted.")
  15.         del self.__value

  16.     # property创建
  17.     value = property(get_value, set_value, del_value)

  18. mc = MyClass(20241120)
  19. print(mc.value)
复制代码
使用装饰器
  1. class MyClass:
  2.     def __init__(self, value):
  3.         self.value = value

  4.     @property
  5.     def value(self):
  6.         return self.__value

  7.     @value.setter
  8.     def value(self, value):
  9.         if value < 0:
  10.             raise ValueError("value must be non-negative.")
  11.         self.__value = value

  12.     @value.deleter
  13.     def value(self):
  14.         print("value is being deleted.")
  15.         del self.__value
复制代码
与基本语法的版本效果是相同的

常见应用


数据隐藏与封装

property装饰器允许像访问和操作普通一样属性进行操作
  1. class Rectangle:
  2.     def __init__(self, width, height):
  3.         self.width = width
  4.         self.height = height

  5.     @property
  6.     def width(self):
  7.         return self.__width

  8.     @width.setter
  9.     def width(self, value):
  10.         if not isinstance(value, (int, float)):
  11.             raise ValueError("width must be a number.")
  12.         if value <= 0:
  13.             raise ValueError("width must be greater than 0.")
  14.         self.__width = value

  15.     @property
  16.     def height(self):
  17.         return self.__height

  18.     @height.setter
  19.     def height(self, value):
  20.         if not isinstance(value, (int, float)):
  21.             raise ValueError("height must be a number.")
  22.         if value <= 0:
  23.             raise ValueError("height must be greater than 0.")
  24.         self.__height = value

  25.         
  26. r = Rectangle(3, 4)
  27. print(r.width)

  28. r.width = "3"
复制代码
设置只读属性

通过property,可以设置一个属性只允许读取,不允许修改
  1. class Person:
  2.     def __init__(self, name):
  3.         self.__name = name

  4.     @property
  5.     def name(self):
  6.         return self.__name
  7.    
  8. # 初始化的时候可以设置名字
  9. p = Person("sagegrass")

  10. # 名字可以正常被访问
  11. print(p.name)

  12. # 名字不可以被修改,AttributeError: can't set attribute 'name'
  13. p.name = "xxx"
复制代码
一般来说,这样设置已经足够保证属性只读,但是极特殊的情况下,仍然可以通过p._Person__name进行修改,
不过通常无需额外关注这一问题。

动态计算

关于一开始的例子,我们使用calculate_area进行面积的计算,但是,通过property就可以将area设置为一个属性,进行动态的计算
  1. class Rectangle:
  2.     def __init__(self, width, height):
  3.         self.width = width
  4.         self.height = height
  5.    
  6.     def calculate_area(self):
  7.         return self.width * self.height
复制代码
使用property属性,修改为:
  1. class Rectangle:
  2.     def __init__(self, width, height):
  3.         self.width = width
  4.         self.height = height

  5.     @property
  6.     def area(self):
  7.         return self.width * self.height
  8.    
  9. r = Rectangle(3, 4)
  10. print(r.area)
  11. r.width = 5
  12. print(r.area)
复制代码
以上就是python使用property完成数据隐藏封装与校验的详细内容,更多关于python property数据隐藏封装与校验的资料请关注脚本之家其它相关文章!

来源:https://www.jb51.net/python/331172mmq.htm
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具