1. 单例模式
类每次实例化的时候都会创建一个新的对象,如果要求类只能被实例化一次该怎么做呢?
用__new__实现单例模式
class Earth:
def __new__(cls):
if not hasattr(cls,'instance'):
cls.instance = super().__new__(cls)
return cls.instance
def __init__(self):
self.name = 'earth'
e = Earth()
print(e,id(e))
a = Earth()
print(a,id(a))
执行上面的代码的运行结果:
<__main__.Earth object at 0x00000200888EB4A8> 2201314309288
<__main__.Earth object at 0x00000200888EB4A8> 2201314309288
在上面的例子中,可以看到两个实例的ID是相同的,即这2个实例的ID是相同的,意味着这2个其实是引用的同一个实例,是一个实例的不同名字。
class Earth(object): #实例本身,cls类本身
def __new__(cls, *args, **kwargs): # new开辟了一个内存空间
if not hasattr(cls,'instance'):
cls.instance = super().__new__(cls)
return cls.instance
def __init__(self,name):
self.name = name
# new 方法是在类实例化的时候最先被执行
# 开辟新的内存空间出来
# 重写new 方法
# 单例模式
b = Earth('哈哈') # new 单例模式
c = Earth('呵呵') # 覆盖
print(b.name)
print(c.name)
# 用 new实现单例模式,当成一个范式,是固定的写法;单例模式可以节省内存;继承了单例的类,子类也会变成单例模式
class A(Earth):
pass
a = A()
d = A()
print(a,d)
2. 定制属性访问
2.1 查询
在python中所有的东西都是类
hasattr(re, 'length') # 返回bool值
getattr(re, 'length') # 返回属性值
b. __getattribute__('length') # 返回属性值
class Rectangle:
def __init__(self,width,length):
self.width = width
self.length = length
def getArea(self):
area = self.length * self.width
return '面积为:%s' % area
a = Rectangle(4,5)
print(hasattr(a,'length')) # 判断有没有这个属性,返回为bool类型
print(getattr(a,'width')) # 返回属性值
print(a.__getattribute__('length'))
执行上面代码的运行结果为:
True
4
5
2.2 修改
#__setattr__
class Rectangle:
def __init__(self,width,length):
self.width = width
self.length = length
def getArea(self):
area = self.length * self.width
return '面积为:%s' % area
a = Rectangle(4,5)
print(hasattr(a,'length')) # 判断有没有这个属性,返回为bool类型
print(getattr(a,'width')) # 返回属性值
setattr(a,'length',6) # 把长修改为6
print(a.__getattribute__('length'))
执行上面代码的结果为:
True
4
6
2.3 添加
# 有则改,无则增
# __setattr__
class Rectangle:
def __init__(self,width,length):
self.width = width
self.length = length
def getArea(self):
area = self.length * self.width
return '面积为:%s' % area
a = Rectangle(4,5)
a.aaa = 'hahaha'
setattr(a,'bb',20)
print(getattr(a,'aaa'))
print(getattr(a,'bb'))
执行上面代码运行的结果为:
hahaha
20
2.4 删除
#__delattr__
class Rectangle:
def __init__(self,width,length):
self.width = width
self.length = length
def getArea(self):
area = self.length * self.width
return '面积为:%s' % area
a = Rectangle(4,5)
print(getattr(a,'length')) # 返回属性值
delattr(a,'length')
print(hasattr(a,'length'))
执行上面代码运行的结果为:
5
False # 表明已经删除了'length'属性
3. 描述符
如果在一个类中实例化另一个类,对这个属性进行访问的时候怎么做的? 用描述符
描述符可以按照你自己定制的你想要怎么去访问这个类,也就是按照你重写代码的逻辑去执行
# 这类里面实例化另一个类,对这个类做访问时,需要定义__get__ , __set__ , __delete__ 方法
class MyClass:
def __get__(self, instance, owner):
print('恭喜您,获得了S级武器')
def __set__(self, instance, value):
print('This is %s' % value)
def __delete__(self, instance):
print('武器已经损坏')
class Control:
attr = MyClass() # 实例化
c = Control()
c.attr # 调用属性,会去MyClass类里面执行__get__方法
c.attr = 20 # 重新赋值
del(c.attr)
执行上面的代码运行的结果为:
恭喜您,获得了S级武器
This is 20
武器已经损坏
4. 装饰器
4.1 闭包
def outer():
a = 2
def inner():
print(a)
return inner # 返回出来的是一个函数体
f = outer() # inner
f() # inner()
执行以上代码的结果为:
2
def outer(func): # 参数,函数体
def inner():
print('-------------')
func()
return inner # 返回出来的是一个函数体
def func():
print('----正在登陆------')
outer(func)
a = outer(func) # 返回值,对象 a = inner
a() # inner()
执行上面的代码运行的结果为:
-------------
----正在登陆------
4.2 装饰器
装饰器他可以在不改变原有函数的基础上给函数增加一些新的功能,他也是一种语法糖,简化代码的,类似于三目运算和lambda表达式。
def outer(func): # 参数,函数体
def inner():
print('-------------')
func()
return inner # 返回出来的是一个函数体
@outer # f1 = outer(f1) #f1 = outer(f1)
def f1(): # 登陆功能
print('登陆功能')
f1() # inner()
@outer
def f2():
print('退出功能')
f2()
执行上面的代码运行的结果为:
-------------
登陆功能
-------------
退出功能
4.3 内置装饰器
class Rectangle(object):
def __init__(self,width,length):
self.width = width
self.length = length
@property
def getArea(self):
return self.length * self.width
@staticmethod # 静态方法,不能访问类里面其他的类属性跟类方法
def func():
print('我没有写self')
@classmethod # 类方法,可以访问类属性跟类方法
def func2(cls):
print('哈哈哈哈哈哈')
Rectangle.func2() #解绑
执行上面代码运行的结果为:
哈哈哈哈哈哈
class TestClass:
def __init__(self,func):
self.func = func
def __call__(self, *args, **kwargs):
print('--------call---------')
return self.func() #注意:类当装饰器一定要用__call__
@TestClass
def aaa():
print('hahahhah')
aaa()
执行以上代码的结果为:
--------call---------
hahahhah
4.4 测试程序执行时间的装饰器
# 定义一个测试程序执行时间的装饰器
from datetime import datetime
def run_time(func):
def new_func(*args,**kwargs):
start_time = datetime.now()
print('程序开始时间:%s'%start_time)
func(*args,**kwargs)
end_time = datetime.now()
print('程序结束时间:%S'%end_time)
print('程序总共执行的时间:%s'%(end_time - start_time))
return new_func()
5. 习题
测试type和isinstance两个函数,哪个速度更加的快。
from datetime import datetime
def run_time(func):
def new_func(*args,**kwargs):
start_time = datetime.now()
# print('程序开始时间:%s'%start_time)
func(*args,**kwargs)
end_time = datetime.now()
# print('程序结束时间:%s'%end_time)
print('程序总共执行的时间:%s'%(end_time - start_time))
return new_func
@run_time
def test_typetime():
print('##########测试type执行的时间###########')
for i in range(1000000):
type('hahahaha')
@run_time
def test_isinstancetime():
print('##########测试isinstance执行的时间###########')
for i in range(1000000):
isinstance('hahahaha',str)
test_typetime()
test_isinstancetime()
执行上面代码运行的结果为:
##########测试type执行的时间###########
程序总共执行的时间:0:00:00.073759
##########测试isinstance执行的时间###########
程序总共执行的时间:0:00:00.090758
代码及结果截图: