new方法、定制属性访问、描述符与装饰器知识点总结
第一部分:__new__方法
思考:
a. 我们创建实例是通过什么方法创建的呢?
b. 类每次实例化的时候都会创建一个新的对象,如果要求类只能被实例化一次该怎么做呢?===通过单利模式实现
c.什么是单例模式(Singleton Pattern )
1、确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,单例模式是一种对象创建型模式
2、是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场
3、如果instance是None,则创建对象并赋值给instance,如果instance等于之前创建的对象,则直接返回
例1:创建单例典范(保证只有一个对象,只执行一次init方法)
问题:
类每次实例化的时候都会创建一个新的对象,如果要求类只能被实例化一次该怎么做呢?
a:用__new__方法实现单例模式可以当成一个范式记忆
b:节省空间
c:new 方法在实例化的时候最先被执行
步骤:
# 单例模式思路:
# 需要生成一个实例===》通过一个方法创建的===》通过object中的__new__方法生成的实例===>返回地址空间
# 以下写法a与a2就不再是独立的实例
# 每次实例的时候都会开辟一个新的空间
# a=A() # 通过object中的__new__方法生成的实例
# a2=A()
# 需求:这个类只能够我一个人使用怎么办?(这个实例实例化了就不能够再创建实例了)
# 只让__new__创建一个实例,重写====》加个条件===》super
# 条件:第一次实例的时候、保存第一次创建的实例 (创建并保存)
# 不是第一次实例的时候:返回第一次创建的实例地址
class A(object):
instance = None # 这个属性要在方法外面
#def __init__(self): # 这个方法可以不写,直接写属性就行
# name='aa'
# cls==》当前类 A
# 初始化在__new__方法之后
def __new__(cls, *args, **kwargs): # 重写object类中的new方法
# hasattr(cls,'instance')为True,加个not就是False语句
# if not hasattr(cls,'instance'): # instance是一个随便写的属性
if not cls.instance:
# 创建一个实例并把实例地址空间保存到cls.instance中
cls.instance=super().__new__(cls) # new方法来自与object类
# A.instance = super().__new__(A) # cls==A
# else:
# 不满足就返回
return cls.instance # cls.instance为第一次创建的地址空间
a=A()
a.name='小米' # 初始化,如果这行代码注释的话就没有初始化实例
print(a.name)
# 当第二次创建实例直接返回地址空间==》cls.instance
a2=A()
print(a2.name)
print(id(a))
print(id(a2))
运行截图:
延伸1.:hasattr 方法
class A(object):
name='小明'
a=A()
# hasattr这个方法是查找有没有这个属性返回bool值,前面放得是类名或者实例,后面是属性变量
print(hasattr(a,'name')) # True
print(hasattr(a,'name1')) # False
运行截图:
延伸2:初始化的重要性
class A(object):
instance = None # 这个属性要在方法外面
name='aa'
# 初始化在__new__方法之后
def __new__(cls, *args, **kwargs): # 重写object类中的new方法
# hasattr(cls,'instance')为True,加个not就是False语句
# if not hasattr(cls,'instance'): # instance是一个随便写的属性
if not cls.instance:
# 创建一个实例并把实例地址空间保存到cls.instance中
cls.instance=super().__new__(cls) # new方法来自与object类
# A.instance = super().__new__(A) # cls==A
# else:
# 不满足就返回
return cls.instance # cls.instance为第一次创建的地址空间
a=A()
# a.name='小米' # 如果注释的话这里代表实例没有初始化
print(a.name)
print(a.__dict__) # 如果没有初始化空值
# 当第二次创建实例直接返回地址空间==》cls.instance
a2=A()
print(a2.name)
print(a2.__dict__)
print(id(a))
print(id(a2))
运行截图:
第二部分:定制属性访问
思考:
a. 如何判断一个实例里面有某个属性呢?
b. 怎样删除实例属性呢?
c. 同样的怎样删除变量呢?
例1:
# 定制属性访问
class A(object):
pass
def __getattr__(self, item):
return '写错了'
a=A()
a.name='小明' # 增加或者修改
print(a.name) # 查找==》内容
print(hasattr(a,'name')) # 查找==》返回的是bool类型
# print(hasattr(a,'name22')) # False # 判断是否存在属性,如果属性存在则进行下一步操作
print(getattr(a,'name')) # 小明
# print(getattr(a,'name2')) # AttributeError: 'A' object has no attribute 'name2'
print(getattr(a,'name2','222')) # 222为默认值 调用__getattr__
print(a.__getattribute__('name')) # 小明
# AttributeError: 'A' object has no attribute 'name2'
# print(a.__getattribute__('name2')) # 小明
a.name='小满哥' # 修改
print(a.name)
# 修改跟添加一样,有则改无则增加
setattr(a,'name','xiaoxiao') # 修改 (实例、属性、属性值)
setattr(a,'name2','xiaofei') # 添加 (实例、属性、属性值)
print(a.name) # xiaoxiao
print(a.name2) # xiaofei
a.__setattr__('name3','xiaohua') # 修改
print(a.name3)
# 删除
# delattr(a,'name')
# a.__delattr__('name')
# print(a.name)
# del a # 删除实例
运行截图:
第三部分:描述符(比较抽象的一个概念,了解即可)
一个类中如果实现了__get__、__set__、__delete__中某一个方法就称为描述符
思考:
如果在一个类中实例化另一个类,对这个属性进行访问的时候怎么做的?
class A:
# 当这个类在另一个类中当做属性的时候并访问这个属性被调用
# 如果把这个get方法注释不写输出<__main__.A object at 0x000001F28B996080>
def __get__(self, instance, owner):
return 'get'
# 在修改的时候调用
def __set__(self, instance, value):
print('set')
# 在删除的时候调用
def __delete__(self, instance):
print('del')
class B:
name='aa'
a=A() # 1.实例化 2.把a当做属性
b=B()
# 查
print(b.a) # a为属性,可以访问 输出 get 实际调用的是get魔术方法
print(b.name) #
# 修改
b.a=123
# 删除
del b.a
运行截图:
第四部分:装饰器(本质是函数,能够实现在不修改原来的函数的基础上添加功能)
1. 回顾知识点:
闭包:外层函数返回内层函数
def f1(obj): # obj就代表是f3
print('这里是f1')
print(obj)
# 以下f2()函数代码只有被调用才执行
def f2():
obj() # 调用f3
print('这里是f2')
return f2
def f3():
print('这里是f3')
#
# 通过参数aa接受===>f2
aa=f1(f3) # 执行f1 把f3当做一个参数传进去
#
aa() # 输出顺:序这里是f3 这里是f2
运行截图:
2. 装饰器的作用(在不改变别人代码的同时添加新的功能)
# 以下为自己写的装饰器
def f1(obj): # obj就代表是f3
print('这里是f1') # 添加格外的功能
def f2():
obj() # 调用f3
print('这里是f2')
return f2
@f1 # 这个相当与以上===》f1(f3) 即调用f1
def f3(): # 把f3当做是别人已经写好的方法
print('这里是f3')
f3() # 执行f3 ====》a() 实际就是在调用f2函数
运行截图:
3. Python也有自带的装饰器(以下python自带的三个内置装饰器)
class A:
@property # 这个装饰器的作用:就像访问属性一样访问方法
def area(self):
print('这里是area方法')
@staticmethod #
def func():
print('这里是func方法')
@classmethod # 把第一个参数变成类本身
# def show(self):
# print(self)
# print('这里是show函数')】
# 改为以下写法
def show(cls):
print(cls)
print('这里是show函数')
a=A()
a.area
a.func() # 无需传参 可以用类调用
A.func()
a.show() # <class '__main__.A'>
print(A) # <class '__main__.A'>
运行截图:
4. 类装饰器(用的不多)
func()
以下完善写法:
代码如下:
class Test_Class:
def __init__(self,func):
print('这是初始化')
self.func=func
def __call__(self, *args, **kwargs):
return self.func # 返回值说明调用了fun函数
@Test_Class # ====》调用Test_Class 函数并把fun函数传进去,然后通过参数func接受
def fun():
print('这里是fun函数')
fun()()
# fun()
作业:测试type和isinstance两个函数,那个速度更加的快