面向对象高级特性
目录
三种方法
类方法
类方法是类对象所拥有的方法,需要用修饰器一般以 @classmethod 来标识其为类方法
1). python解释器会自动将类传入方法
2). 对于类方法,第一个参数必须是类对象,作为第一个参数(cls是形参,可以修改为其他变量名,但推荐使用‘cls’)
3). 能够通过实例对象和类对象去访问
实例方法
1). python解释器会自动将对象/实例传入方法。
2). 在类的内部,使用 def 关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数 self,且为第一个参数,self 代表的是类的实例。
3). self 的名字并不是规定死的,也可以使用 this,但是最好还是按照约定是用 self。
静态方法
静态方法需要用修饰器一般以 @staticmethod 来标识其为静态方法,
1).python解释器不会自动传入任何参数
2). 静态方法不需要多定义参数
3). 能够通过实例对象和类对象去访问。
示例:
示例1:类方法和实例方法
"""
相关的源码:from datetime import datetime
"""
class Student(object):
def __init__(self, name, age):
self.name = name
self.age = age
# 实例方法, python解释器会自动将对象/实例传入方法。
def get_age(self):
print('self:', self)
return self.age
# 类方法:python解释器会自动将类传入方法。
@classmethod
def get_cls(cls):
print('cls:', cls)
# 静态方法:python解释器不会自动传入任何参数
@staticmethod
def get_info():
print("static method信息")
if __name__ == '__main__':
s = Student('张三', 18)
s.get_age()
s.get_cls()
s.get_info()
执行结果:
self: <__main__.Student object at 0x000002D2322E9F70>
cls: <class '__main__.Student'>
static method信息
实例2:类方法和静态方法理解的简单案例
class date(object):
# 正常的方法: 将对象作为参数传给self
def get_self(self):
print('self:', self)
# 类方法: 将类名作为参数传给cls
@classmethod
def get_cls(cls):
print('cls:', cls)
# 静态方法:不自动传递任何参数
@staticmethod
def get_static(name, age):
print("静态方法", name, age)
d = date()
d.get_self()
d.get_cls()
d.get_static("张三", 18)
执行结果
self: <__main__.date object at 0x000001DEE0599F10>
cls: <class '__main__.date'>
静态方法 张三 18
property 类(类方法变成类属性,让代码更简洁)
1)、property 类原型
class property
(fget=None, fset=None, fdel=None, doc=None)
1). 返回 property 属性。
2). fget 是获取属性值的函数。 fset 是用于设置属性值的函数。 fdel 是用于删除属性值的函数。并且 doc 为属性对象创建文档字符串
2)、什么是propetry类
一种用起来像是使用的实例属性一样的特殊属性,可以对应于类的某个方法。检查参数,用类似属性这样简单的方式来访问类的变量。
3)、property属性的定义和调用要注意一下几点:
1). 定义时,在实例方法的基础上添加 @property 装饰器;并且仅有一个self参数
2). 调用时,无需括号
4)、property属性的有两种方式:
1). 装饰器 即:在方法上应用装饰器
2). 类属性 即:在类中定义值为property对象的类属性
5)、注意:
1). 经典类中的属性只有一种访问方式,其对应被 @property 修饰的方法
2). 新式类中的属性有三种访问方式,并分别对应了三个被@property、@方法名.setter、@方法名.deleter修饰的方法
示例3:property类属性
"""
类属性应用需求: 对于京东商城中显示电脑主机的列表页面,每次请求不可能把数据库中的所有内容都显示到页面上,而是通过分页的功能局部显示,所以在向数据库中请求数据时就要显示的指定获取从第m条到第n条的所有数据 这个分页的功能包括:
- 根据用户请求的当前页和总数据条数计算出 m 和 n
- 根据m 和 n 去数据库中请求数据
from datetime import datetime
"""
class Page(object):
"""
[user1, user2, user3......user100]
page=2, per_page=10
第一页: start=0 end=10
第二页: start=10 end=20
第三页: start=20 end=30
....
第page页: start=(page-1)*per_page end=page*per_page
"""
def __init__(self, page, per_page=10):
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
if __name__ == '__main__':
goods = ['good'+str(i+1) for i in range(100)]
page = Page(page=10, per_page=3)
print(goods[page.start:page.end])
执行结果
['good28', 'good29', 'good30']
示例4:property简单案例
class date(object):
def __init__(self, year, month, day):
# 私有属性
self.__year = year
self.__month = month
self.__day = day
# 将类方法object.year()转变成类属性object.year, 只是让代码更加简洁而已。
@property
def year(self):
return self.__year
today = date(2021, 2, 27)
print(today.year)
执行结果
2021
单例模式(一个类只能实例化一个对象的设计模式)
对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要
示例5:理解单例模式
"""
什么是单例模式?
一个类只能实例化一个对象的设计模式称为单例模式。
"""
class People(object):
pass
p1 = People() # object
p2 = People() # object
print(p1, p2) # 每个对象的内存地址不同,肯定不是单例模式
执行结果
<__main__.People object at 0x0000021F881E6FD0> <__main__.People object at 0x0000021F881E6FA0>
基于装饰器的单例模式
装饰器(decorator)可以动态地修改一个类或函数的功能。这里,我们也可以使用装饰器来装饰某个类,使其只能生成一个实例。
示例6:基于装饰器的单例模式
from functools import wraps
def singleton(cls):
# 通过一个字典存储类和对象信息{"Class":"object"}
instances = {}
@wraps(cls)
def wrapper(*args, **kwargs):
# 为了保证单例模式, 判断该类是否已经实例化为对象
# 1. 如果有对象,直接返回存在的对象
# 2. 如果没有则实例化对象, 并存储类和对象到字典中, 最后返回对象
if instances.get(cls):
return instances.get(cls)
object = cls(*args, **kwargs)
instances[cls] = object
return object
return wrapper
@singleton
class People(object):
pass
p1 = People()
p2 = People()
print(p1, p2)
print(p1 is p2) # 判断是否为单例模式(p1和p2内存地址是否相同)
执行结果
<__main__.People object at 0x0000017267A49EE0> <__main__.People object at 0x0000017267A49EE0>
True
基于new方法的单例模式 (创建对象之前执行的内容)
示例7:基于new 方法的单例模式
class People(object):
_instance = None
def __new__(cls, *args, **kwargs):
"""创建对象之前执行的内容"""
if cls._instance is None:
cls._instance = object.__new__(cls)
return cls._instance
def __init__(self):
"""在new方法之后执行, 将属性和对象封装在一起"""
print("正在执行构造方法init......")
p1 = People()
p2 = People()
print(p1, p2)
执行结果
正在执行构造方法init......
正在执行构造方法init......
<__main__.People object at 0x000001A1D8BFAFA0> <__main__.People object at 0x000001A1D8BFAFA0>