一.析构方法__del__和构造方法__new_
析构方法: 删除一个对象的时候调用的方法
构造方法: 创建一个对象的
初始化方法: __init__ 给已经创建出来的对象添加属性初始化方法
1.析构方法:
class A:
def __init__(self,name):
self.name=name
def __del__(self):
print(666)
a=A("alex")
del a
print(a.__dict__) #NameError: name 'a' is not defined
View Code
删除一个对象的时候,如果内部存在__del__方法,那么在删除一个对象之前先执行__del__方法中的代码
析构函数的调用是由解释器在进行垃圾回收时自动触发执行的
class Foo:
def __del__(self):
print('执行我啦')
f1=Foo() #执行我啦
##没有删-除对象,却仍然执行了__del__函数。原因是解释器在代码全部执行完后会收集没执行的代码,因此会触发
这个函数执行
2.__new__创造一个对象。即实例化时为什么能实例化出来一个对象
class A:
def __init__(self):
print("执行了init方法")
def __new__(cls, *args, **kwargs):
print("执行了new方法")
return object.__new__(cls)
a=A()
# 执行了new方法 执行了init方法
print(type(a)) #<class '__main__.A'>
print(type(A)) #<class 'type'>
View Code
实例化的实质:先执行__new__方法 创造出一个对象 然后把创造出来的对象传递给__init__方法
二.元类和单例模式
1.元类:type()
类和对象都不是凭空出此现的。对象的产生是类创造的。也有一个类在创建类,这个类叫做元类
type() 所有直接用class创建出来的类的元类都是type
class Preson:pass
print(type(Preson)) #<class 'type'>
class Preson:pass 的完整形式是class Preson(metaclass=type):pass
在接口类和抽象类中不能实例化的原因就是改变了元类
元类 创造 类 所以所有的类的type都是它的元类,默认是type
类 创造 对象 具体创造对象的方法 __new__方法,所有的对象的type都是它对应的类
2.单例模式:一个类可以被多次实例化 但是同一时间在python的内存中,只能有一个实例
class A:
def __init__(self,name):
self.name=name
#print("执行了init")
def __new__(cls, *args, **kwargs):
#print("执行了__new__")
if not hasattr(A,'instance'):
A.instance=object.__new__(cls) #instance为A的静态变量
return A.instance
a=A("alex")
print(a.name) #alex
b=A("egon")
print(a.name,b.name) #egon egon
View Code
三.item系列
1.__item__系列 操作a['name']这种形式
__getitem__
class A:
def __init__(self,name):
self.name=name
self.age=18
def __getitem__(self,item):
return self.__dict__[item]
a=A('alex')
print(a['name'],a['age']) # alex 18 对应了类中一个方法的语法
先进行初始化,然后执行__getitem__ 在return时不能return self.[item] 对象并没有[item]这种属性
View Code
2.###增加.修改和删除一个属性
class A:
def __init__(self,name):
self.name=name
self.age=18
def __getitem__(self, item):
return self.__dict__[item]
def __setitem__(self, key, value):
self.__dict__[key]=value
def __delitem__(self, key):
del self.__dict__[key]
a=A('alex')
##增加属性
a['sex']='nan'
print(a.__dict__) #{'name': 'alex', 'age': 18, 'sex': 'nan'}
###查看
print(a.sex) #nan
print(a["sex"]) #nan
##修改##
a['sex']='不详'
print(a.__dict__) #{'name': 'alex', 'age': 18, 'sex': '不详'
##删除##
del a['sex']
print(a.__dict__) #{'name': 'alex', 'age': 18}
View Code
四.__call__和__hash__
1.__call__
class A:
def __call__(self,a):
print('执行我了',a)
a = A()('aaa') #等同于a=A() a('aaa')
2.__hash__
不可变的数据类型都可以被hash
class A:
def __hash__(self):
return 1
a = A()
b = A()
print(hash(a))
print(hash(b))
hash(obj)函数,obj对象对应的类必然内部实现了__hash__方法
hash的结果就是__hash__方法的返回值
且在一次成的执行过程中是不会发生变化的
且要想作为字典的key或者作为集合的元素,这个对象对应的类必须实现__hash__方法
面试题
有一个类,对应这个类产生了100个对象
每个对象有三个属性 : 姓名 年龄 性别
请对这一百个对象进行去重,如果姓名和性别相同,即便年龄不同也是相同的对象
'''
class Person:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def __hash__(self):
return hash('%s%s'%(self.name,self.sex))
def __eq__(self, other):
if self.name == other.name and
self.sex == other.sex:
return True
p_lst = []
for i in range(100):
p_lst.append(Person('egon',i,'male')) #print(Person('egon',18,'male'))显示对象的地址
print(p_lst)
print(set(p_lst)) # 报错不可hash 完成了__hash__
View Code