目录:
init,del,add,str和 repr,call,单例模式,class,dict,doc,bases,mro
魔法方法:
定义:在特定条件下,触发方法
在python里面很多以双下划线开头且结尾的固定方法,他们会在特定时机被触发执行
例子:__init__
__init__ ------构造函数
__init__为初始化魔法方法,又叫构造函数,因为在初始化时,可以构造属性
触发条件:在实例化后自动调用,以完成实例初始化
__del__ ------ 析构函数
__del__是析构函数,用来回收内存(释放内存空间)
主动触发__del__:
触发条件:del,当使用del删除对象时,会调用他本身的析构函数。
自动触发__del__:
析构函数会当对象在某个作用域中调用完毕,在跳出其作用域的同时析构函数也会被调用一次,这样可以用来释放内存空间。
**析构函数不会立即触发回收机制**
class Demo():
def __init__(self):
self.age = 18
def __del__(self):
print('del被调用')
x = Demo()
y = Demo()
del x #主动触发__del__
print(y.age)
del被调用 #主动触发__del__
18 #先运行__init__
del被调用 #自动触发__del__;先运行其他魔法方法,再自动触发del。析构函数 不会立即触发回收机制
__add__------ 定义加法的行为:+
__ add__(self, other) 触发条件:x+y (相当于self+other)
__str__和__ repr__
含义:
__ str__(self):定义当被 str() 调用或者打印对象时的行为
__ repr__(self):定义当被 repr() 调用或者直接执行对象时的行为
触发条件:
__str__: 输出实例对象变量的时候触发, 在非交互模式下, 如果二者同时存在, 只会触发__str__
__repr__ : 输出实例对象变量的时候触发, 在交互式模式下, 如果二者同时存在,
输出不使用print, 只会触发__repr__;若使用print,只能触发__str__
**这两个魔法方法在定义时需使用return,而不能使用print**
__call__------实例后像函数一样调用时触发
触发条件:变量名() ---- 类似函数的调用方法
单例模式------实现数据互通
- 如何实现数据互通?
分析:
1. 实例对象与实例对象数据不互通,这是因为每次实例化时,生成了新的实例对象,每一个实例对象都是类的独一无二的个体
2. 因此要想实现数据互通,就需要引用同一个实例对象
3. 此时,我们就需要知道创建实例对象的方法,__new__魔法方法可以实现这个功能
#__new__(cls, *args, **kwargs): 用来创建实例对象; 它返回的值:类的实例化对象
# cls:类本身
__new__和__init__的执行顺序:
__new__:创建实例化对象
__init__:初始化
要先创建实例化对象,才能执行初始化,因为执行初始化的对象是实例本身;
因此先执行__new__,再执行__init__
注意:在定义__new__方法时,一定要返回(return)实例对象,这样才能执行__init__
以下是:在定义__new__方法时,return实例对象
class Demo():
def __init__(self,length,width):
print('触发init魔法方法')
self.length = length
self.width = width
def __new__(cls, *args, **kwargs):
print('触发new魔法方法')
return object.__new__(cls)
#object是所有类的超类,可以理解为是所有类的祖先
#__new__是创建实例对象的魔法方法
#这里通过Demo类的祖先来创建Demo类的实例对象,即object.__new__,并返回实例对象,
这样才可以调用__init__魔法方法
x = Demo(1,2)
print(x) #生成了实例对象
print(x.length) #调用__init__,输出x实例对象的length属性
触发new魔法方法
触发init魔法方法 #先执行__new__,再执行__init__
<__main__.Demo object at 0x00000000027D7788> #生成了实例对象
1 #输出x实例对象的length属性
- 在单例模式下添加属性:
添加属性之前,首先要判断要添加的属性是否在当前类里存在:
hasattr(查询的类, 属性名):查找属性,判断类的某个属性是否存在
class Demo():
def __init__(self,length,width):
self.length = length
self.width = width
def __new__(cls, *args, **kwargs):
if not hasattr(cls,'instance'):
# 判断instance这个属性是否不存在Demo类里,为真,则进行if not下的操作
#cls改成Demo也可以,因为是在Demo类中查找instance属性
cls.instance = super().__new__(cls)
#属性名 = 实例对象(属性值)
#通过继承超类(父类),来创建类的实例对象;
#super是继承超类的方法,__new__是创建实例对象的魔法方法
return cls.instance
#最后返回属性instance
x = Demo(1,2) #用x变量接收实例对象
y = Demo(3,3) #用y变量接收实例对象
x.instance = 1 #添加instance的属性值
y.instance = 10 #添加instance的属性值
# 因为在单例模式下,数据实现互通,因此x和y接收的都是同一个实例对象,
所以y.instance的属性值10,覆盖了之前的x.instance的属性值1
print(x.instance)
print(y.instance) #不管打印x还是y变量,返回的值都以最后的instance属性值为准
10
10
__class__ ------- 查看类名
触发条件:实例.__class__
class Demo():
pass
x = Demo()
print(x.__class__)
<class '__main__.Demo'> ----表示x的类名是Demo
__dict__-------查看实例对象的全部属性
触发条件:实例.__dict__
输出:以字典形式输出属性和值
class Demo():
def __init__(self):
self.age = 18
x = Demo()
x.name = 'x'
x.sex = '男'
print(x.__dict__)
{'age': 18, 'name': 'x', 'sex': '男'}
__doc__--------查看对象注释信息
触发条件:实例/类名.__doc__
class Demo():
'''
测试
'''
def __init__(self):
self.age = 18
x = Demo()
print(x.__doc__) #实例.__doc__
print(Demo.__doc__) #类名.__doc__
测试
测试
__bases__--------查看类的父类
触发条件:类名.__bases__
class Demo():
def __init__(self):
self.age = 18
print(Demo.__bases__)
(<class 'object'>,)
__mro__-------- 多继承情况下, 查看继承顺序
触发条件:类名.__mro__
class Demo():
def __init__(self):
self.age = 18
print(Demo.__mro__)
(<class '__main__.Demo'>, <class 'object'>)
----先返回自己的类,再返回比自己更高级的父类,任何类最终都会返回object
__class__和__bases__,__mro__可以一起用,因为【实例.__class__】表示类名
class Demo():
def __init__(self):
self.age = 18
x = Demo()
print(x.__class__.__bases__)
print(x.__class__.__mro__)
(<class 'object'>,)
(<class '__main__.Demo'>, <class 'object'>)