python初学之面向对象知识点补充(property、单例模式)

一、property类属性

知识点回顾:

1.什么是property属性?

一种用起来像是使用的实例属性一样的特殊属性,可以对应于类的某个方法。property属性的定义和调用要注意一下几点:
 
1). 定义时,在实例方法的基础上添加 @property 装饰器;并且仅有一个 self 参数
 
2). 调用时,无需括号
 
2.property属性的有两种方式:
 
• 装饰器 即:在方法上应用装饰器
 
• 类属性 即:在类中定义值为 property 对象的类属性
 
注意:
 
• 经典类中的属性只有一种访问方式,其对应被 @property 修饰的方法
 
• 新式类中的属性有三种访问方式,并分别对应了三个被 @property @ 方法名.setter、@ 方法名 .deleter 修饰的方法。
 

3. 类属性应用

应用1:需求: 对于京东商城中显示电脑主机的列表页面,每次请求不可能把数据库 中的所有内容都显示到页面上,而是通过分页的功能局部显示,所以在向数据库中请求 数据时就要显示的指定获取从第start条到第end条的所有数据 这个分页的功能包括:

• 根据用户请求的当前页和总数据条数计算出 start 和 end

• 根据start 和 end 去数据库中请求数据

• 是否有上一页has_prev、下一页has_next

• 上一页prev、下一页next

• 总页数pages, 数据总条数total、当前页信息items

注:分页显示是一种非常常见的浏览和显示大量数据的方法,属于web编程中最常处理的事件之一。

代码:

class Pagintor(object):
    """实现商品分页的类"""
    def __init__(self, objects_list, page=1, per_page=5):
        """
        :param objects_list: 商品列表
        :param page: 当前需要显示的页码信息
        :param per_page: 每页显示的数据个数
        """
        self.objects_list = objects_list
        self.page = page
        self.per_page = per_page

    @property
    def start(self):
        return (self.page - 1) * self.per_page

    @property
    def end(self):
        return self.page * self.per_page

    @property
    def total(self):
        """
        数据总条数total
        :return:
        """
        return len(self.objects_list)

    @property
    def pages(self):
        """
        总页数pages
        if 总商品数量%每页显示数量==0:  刚好当前页显示满
        else: 好友多与的部分, 在计算的结果上面加1
        self.total = 5  pages=1
        self.total = 6  pages=2
        :return:
        """
        result = self.total // self.per_page
        if self.total % self.per_page == 0:
            return result
        else:
            return result + 1

    @property
    def has_next(self):
        return True if 0 < self.page + 1 <= self.pages else False

    @property
    def next(self):
        next_page = self.page - 1
        next_start = (next_page - 1) * self.per_page
        next_end = self.page * self.per_page
        return self.objects_list[next_start:next_end]

    @property
    def has_prev(self):
        return True if 0 < self.page - 1 <= self.pages else False

    @property
    def prev(self):
        prev_page = self.page - 1
        prev_start = (prev_page - 1) * self.per_page
        prev_end = self.page * self.per_page
        return self.objects_list[prev_start:prev_end]

    @property
    def items(self):
        """
        当前页信息items
        :return:
        """
        return self.objects_list[self.start:self.end]

if __name__ == '__main__':
    # 应用场景二: 某一个属性不能直接返回, 需要计算的, 可以通过property属性实现
    goods = ["信息" + str(i) for i in range(15)]
    # 需求: 显示第三页时, 开始的索引是? 结束的索引为多少?
    pagintor = Pagintor(goods, page=1, per_page=5)
    print("第1页的商品信息为: ", goods[pagintor.start:pagintor.end])
    print("是否有上一页:", pagintor.has_prev)
    print("总页数:", pagintor.pages)

测试结果:

第1页的商品信息为:  ['信息0', '信息1', '信息2', '信息3', '信息4']
是否有上一页: False
总页数: 3

应用二:property通过函数的方式实现类属性(类属性 即:在类中定义值为property对象的类属性)

例如:

class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.__age = age  # 私有属性

    @property
    def is_age_vaild(self):
        return  0 < self.__age <= 150
    def get_age(self):
        if self.is_age_vaild:
            return self.__age
        else:
            raise Exception("年龄不合法")

    def set_age(self, age):
        if self.is_age_vaild:
            self.__age = age
        else:
            raise Exception("年龄不合法")

    def del_age(self):
        print("年龄属性删除......")
    # 类属性 即:在类中定义值为property对象的类属性
    age = property(fget=get_age, fset=set_age, fdel=del_age)

if __name__ == '__main__':
    p1 = Person("爱丽丝", 24)
    print(p1.age)
    p1.age = 25
    print(p1.age)
    del p1.age

测试结果:

24
25
年龄属性删除......

应用三:property通过desc的方式实现类属性

代码:

class Person(object):
    def __init__(self, name, age, score):
        self.name = name
        self.__age = age  # 私有属性
        self.__score = score

    @property
    def score(self):
        return  self.__score
    @score.setter
    def score(self, score):
        self.__score = score

    @property
    def is_age_vaild(self):
        return  0 < self.__age <= 150

    @property           # 获取age属性时执行的内容
    def age(self):
        if self.is_age_vaild:
            return self.__age
        else:
            raise Exception("年龄不合法")
    @age.setter         # 设置age属性时执行的内容
    def age(self, age):
        if self.is_age_vaild:
            self.__age = age
        else:
            raise Exception("年龄不合法")
    @age.deleter        # 删除age属性时执行的内容
    def age(self):
        print("年龄属性删除......")

if __name__ == '__main__':
    p1 = Person("张三", 25, 100)
    print(p1.age)       # 获取年龄(), 执行@property def age(self):
    p1.age = 26         # 设置年龄, age=31
    print(p1.age)
    del p1.age          # 删除年龄属性

测试结果:

25
26
年龄属性删除......

二、单例模式

1、什么是单例模式?

 简单来说就是一个类只能创建一个人对象的设计模式。

2.为什么需要单例模式?

对于系统中的某些类来说,只有一个实例很重要。
例如,一个系统中可以存在多个 打印任务 ,但是只能有一个正在工作的任务;一个系统只能有一个 窗口管理器或文件系统
一个系统只能有一个 计时工具或 ID( 序号 ) 生成器 。如在 Windows 中就只能打开一个 任务管理器
如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;
如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。
因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。
 
3.怎么完成单例模式?
1)装饰器(decorator)可以动态地修改一个类或函数的功能。这里,我们也可以使用装饰器来装饰某个类,使其只能生成一个实例:(装饰器实现单例模式),如下:
 
from functools import wraps
def singleton(cls):
    instances = {}
    @wraps(cls)
    def wrapper(*args,**kwargs):
        name = cls.__name__
        if instances.get(name):
            return instances.get(name)
        else:
            obj=cls(*args,**kwargs)
            instances[name]=obj
            return obj
    return wrapper
@singleton
class Person(object):
    pass
if __name__ == '__main__':
    p1=Person()
    p2=Person()
    print("单例模式是否成功?",p1 is p2)

测试结果:

单例模式是否成功? True

2)new方法实现单例模式:

class Person(object):
    # 1). 设置类属性, 存储已经创建好的对象。
    _instance = None
    def __new__(cls, *args, **kwargs):
        print("new方法在实例化对象之前执行.....返回对象本身")
        # 2). 判断是否已经实例化对象?
        if cls._instance:
            return  cls._instance
        else:
            self = object.__new__(cls)
            cls._instance = self
            # 返回父类object的new方法创建的对象.....
            return self

    def __init__(self):
        print("构造方法实例化对象之后执行......")

if __name__ == '__main__':
    p1 = Person()
    p2 = Person()
    print(p1, p2)

测试结果:

new方法在实例化对象之前执行.....返回对象本身
构造方法实例化对象之后执行......
new方法在实例化对象之前执行.....返回对象本身
构造方法实例化对象之后执行......
<__main__.Person object at 0x0000017BF8516D30> <__main__.Person object at 0x0000017BF8516D30>

此方法可以改进简化一下:如下

from datetime import  date

class Person(object):
    def __new__(cls, *args, **kwargs):
        print("判断当前类是否拥有instance属性?", hasattr(cls, 'instance'))
        if not hasattr(cls, 'instance'):
            cls.instance = super(Person, cls).__new__(cls)
        return  cls.instance

    def __init__(self, name):
        self.name = name

p1 = Person("张三")
p2 = Person("李四")
print("单例模式是否成功? ", p1 is p2)

测试结果:

判断当前类是否拥有instance属性? False
判断当前类是否拥有instance属性? True
单例模式是否成功?  True

 

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值