7.8. property装饰器,将方法转为属性,动态属性

#!/usr/bin/env python
# -*- coding:utf8 -*-
# auther; 18793
# Date:2019/6/13 17:54
# filename: property2.py
class Rectangle:
    # 定义构造方法
    def __init__(self, width, height):
        self.width = width
        self.height = height
    # 定义setsize()函数
    def setsize (self , size):
        self.width, self.height = size
    # 定义getsize()函数
    def getsize (self):
        return self.width, self.height
     # 定义delsize()函数
    def delsize (self):
        self.width, self.height = 0, 0
    # 使用property定义属性
    size = property(getsize, setsize, delsize, '用于描述矩形大小的属性')


print(Rectangle.size.__doc__)

# print(help(Rectangle.size))
rect = Rectangle(3, 4)
print(rect.size)
rect.size = 7, 8
print(rect.height)
print(rect.width)
del rect.size
print(rect.width)
print(rect.height)

7.8.1. 访问方式和之前略有区别,用属性的方式访问

代码示例 1

#!/usr/bin/env python
#-*- coding:utf8 -*-

#通过装饰器方法来获取私有属性
class TVShow:       #电视节目类
    list_film = ["战狼2", "红海行动", "西游记女儿国", "熊出没变形记"]

    def __init__(self, show):
        self.__show = show      ## 私有的实例属性

    @property
    def show(self):
        '''
        :return:私有属性
        '''
        return self.__show      #返回类的实例


    @show.setter                #让属性可以进行修改
    def show(self, value):
        if value in TVShow.list_film:       #判断值是否在列表中
            self.__show = '您选择了《'+ value + "》,稍后将播放"    #修改返回值
        else:
            self.__show = "您点播的电影不存在"


tvshow = TVShow("战狼2")  #创建类的实例
print("正在播放:《", tvshow.show, "》")     #获取属性值
print("您可以从", TVShow.list_film, "中选择台点播的电影")

tvshow.show = '红海行动'
print(tvshow.show)      #获取属性值

7.8.2. @property 实现只读属性

@property 可以实现一个只读属性, 为属性添加了安全保护的机制。
注意:
@property 所装饰的方法变成属性之后,为只读的属性
    不能通过 实例.xxx=  的方式进行修改。

用代码来理解 2

新式类中的属性有三种访问方式,

并分别对应了三个被@property、@方法名.setter、@方法名.deleter修饰的方法

#!/usr/bin/env python
#-*- coding:utf8 -*-
class Rect:
    def __init__(self,weight,height):
        self.__weight = weight
        self.__height = height

    @property                       #将方法转为属性
    def area(self):
        return self.__weight*self.__height

    @area.setter                    #设置属性的值
    def set_area(self, value):
        if isinstance(value,int):
            self.__weight += value
        else:
            raise ValueError

    @area.deleter
    def delete_are(self):
        print("删除属性.......")

hu = Rect(10,20)
print(hu.area)

#不能进行重新赋值,会报错
hu.set_area = 100
print(hu.area)
del hu.delete_are

代码示例 3

#!/usr/bin/env python
#-*- coding:utf8 -*-
from datetime import datetime,date

class User:
    def __init__(self,name,birthday):
        self.name = name
        self.birthday = birthday
        self._age = 0

    @property
    def age(self):
        return datetime.now().year - self.birthday.year

    @age.setter
    def age(self,value):
        self._age = value

if __name__ == '__main__':
    user = User("derek",date(year=1994,month=11,day=11))
    user.age = 23
    print(user._age)   # 23,setter设置的
    print(user.age)    # 24 ,动态计算出来的

7.8.3. 使用property函数调用私有属性

使用方式如图所示: image1

#!/usr/bin/env python
# coding=utf-8

__metaclass__ = type

class ProtectMe:
    def __init__(self):
        self.me = "qiwsir"
        self.__name = "kivi"

    @property
    def name(self):
        return self.__name

if __name__ == "__main__":
    p = ProtectMe()
    print p.name
定义时,在普通方法的基础上添加 @property 装饰器;
定义时,属性仅有一个self参数
调用时,无需无括号

7.8.4. 实现一个分页打印的类的代码

#!/usr/bin/env python
# -*- coding:utf8 -*-
# auther; 18793
# Date:2019/4/21 10:32
# filename: 分页的类.py

class Pagination(object):
    """
    分页相关的代码
    """

    def __init__(self, data_list, page, per_page=30):
        """

        :param data_list: 数据的列表
        :param page: 当前查看的页面
        :param per_page: 每页默认要显示的行数
        """
        self.data_list = data_list
        self.page = page
        self.per_page = per_page

    @property
    def start(self):
        """
        计算索引的起始位置
        :return:
        """
        return (self.page - 1) * self.per_page

    @property
    def end(self):
        """
        计算分页的结束位置
        :return:
        """
        return self.page * self.per_page

    @property
    def check_show(self):
        res = None
        if self.page * self.per_page > len(self.data_list):
            print("--------已为您打开最后一页-------------")
            last_index = int(len(self.data_list)/self.per_page)
            self.page = last_index
            res = self.data_list[self.start:self.end]
        else:
            res = self.data_list[self.start:self.end]

        for index in res:
            print(index)



if __name__ == '__main__':

    # 模拟所有数据写入到一个list里面
    data_list = []
    for i in range(1, 901):
        data_list.append("hujianli-blog-{}".format(i))

    # 循环查看页面页数
    while True:
        page = int(input("请输入要查看的页数:"))
        obj = Pagination(data_list, page)
        obj.check_show

7.8.5. 属性(property)

##不推荐
class Clock(object):
  def __init__(self):
    self.__hour = 1
  def setHour(self, hour):
    if 25 > hour > 0: self.__hour = hour
    else: raise BadHourException
  def getHour(self):
    return self.__hour

##推荐
class Clock(object):
  def __init__(self):
    self.__hour = 1
  def __setHour(self, hour):
    if 25 > hour > 0: self.__hour = hour
    else: raise BadHourException
  def __getHour(self):
    return self.__hour
  hour = property(__getHour, __setHour)