一、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