Python类的内置方法
一、类的type
class A:pass
print(type(A)) # <class 'type'>
print(type(object)) # <class 'type'>
print(type(type)) # <class 'type'>
① 所有的对象的type都是创造这个对象类
② 所有没有指定metaclass的类的type都是type
③ 指定了metaclass,这个类的type就是指定的metaclass的值
④ 类也是被创造出来的,type是创造类的机制,即元类是创造类的机制
所有的对象的type都是创造这个对象类
class A:pass
a = A()
print(type(a) is A) # True
所有没有指定metaclass的类的type都是type
class A():pass
print(type(A)) # <class 'type'>
指定了metaclass,这个类的type就是指定的metaclass的值
from abc import ABCMeta
class A(metaclass=ABCMeta):pass
print(type(A)) # <class 'abc.ABCMeta'>
类也是被创造出来的,type是创造类的机制,即元类是创造类的机制
print(type(type) is type(object)) # True,type和object的type都是 <class 'type'>
print(isinstance(type,object)) # True,type和object都属于<class 'type'>
print(isinstance(object,type)) # True,type和object都属于<class 'type'>
print(issubclass(type,object)) # True,type是object的子类
print(issubclass(object,type)) # False
二、__new__ 构造方法
__new__ :构造方法,类实例化对象第一步创建了一个对象空间,这个对象空间是由__new__来创建的,继承object的__new__方法
__init__:初始化方法
类实例化对象的时候,先执行的 __new__,再执行__init__。
类实例化对象的内存机制:
实例化对象先执行__new__方法,但是类里没有__new__的方法,到父类object中去找到__new__方法并执行,开辟了属于对象的空间,这时才开始执行__init__方法,把self参数传进去才是刚才创造的空间。
整个过程把类比作模板,创造对象比作捏泥像,__new__方法是捏出来泥像,__init__是给泥像装饰。
class A:
def __init__(self): # 初始化方法
print('执行初始化方法')
def __new__(cls, *args, **kwargs): # 构造方法
print('执行构造方法')
return object.__new__(cls)
a = A()
'''
执行构造方法
执行初始化方法
'''
三、单例模式
关于设计模式:
常用有23种设计模式,源于Java,为了规范java的开发。
python一种是推崇设计模式,另一种是贬低设计模式。
单例模式:一个类无论实例化多少次,都只有一个对象,只开辟一个空间,这种就是单例模式。
单例模式下,创造的对象的属性是最后一个对象的属性,一直再赋值。
class City:
__initialize = 0 # 静态属性
def __init__(self,city):
self.city = city
def __new__(cls, *args, **kwargs):
if not cls.__initialize:
cls.__initialize = object.__new__(cls) # 把对象空间地址赋值静态属性
return cls.__initialize
gz = City('广州')
sz = City('深圳')
print(gz,sz)
print(gz.city,sz.city)
'''
<__main__.City object at 0x0000022B2DCBC6A0> <__main__.City object at 0x0000022B2DCBC6A0>
深圳 深圳
'''
四、__del__ 析构方法
① 析构方法是销毁对象时会调用__del__方法,执行del就会触发__del__的方法
② 在删除这个类创建的对象的时候会先触发这个方法,再删除对象,主要是做清理的工作,需要手动归还资源给操作系统,比如:关闭文件,关闭网络的连接,关闭数据库的连接等。
③ 无论是手动删除对象还是程序结束自动删除对象,本质上都是执行del 对象,只要调用del 对象,就会触发__del__方法
④ 构造方法和析构方法是一对的
class A:
def __init__(self,name): # 初始化方法
self.name = name
print(self.name)
print('执行初始化方法1')
def __new__(cls, *args, **kwargs): # 构造方法
print('执行构造方法!')
return object.__new__(cls)
def __del__(self): # 析构方法
print('执行析构方法!')
a = A('苹果')
print('-----分割线-----')
'''
执行构造方法!
苹果
执行初始化方法1
-----分割线-----
执行析构方法!
'''
总结:初始化对象先执行__new__方法,再执行__init__方法,然后把self传进去,执行__init__的内容,当整个程序执行完自动删除对象,触发了__del__方法,执行__del__方法的内容。
五、__len__ 方法
① 所有使用len()的数据类型都有__len__的方法,使用len()的数据类型:str,list,dict,tuple,set
② 只要在类中定义__len__方法,并且方法内return整数,就能使用len(对象)
③ 若要统计对象的长度,定义__len__的方法比较好
class Fruits:
def __init__(self,name):
self.name = name
self.fruit_lis = []
def __len__(self):
return len(self.fruit_lis)
durian = Fruits('榴莲')
durian.fruit_lis.append('苹果')
durian.fruit_lis.append('番茄')
durian.fruit_lis.append('西瓜')
durian.fruit_lis.append('雪梨')
durian.fruit_lis.append('香蕉')
ret = len(durian)
print(ret) # 5
六、__eq__ 方法
① __eq__方法判断对象是否相等,但是object类的__eq__方法是通过对象的内存地址判断是否相等
② __eq__方法 有时会配合__hash__方法使用,判断对象里的对象属性是否相等
③ obj.__eq__(obj2) 相当于 obj == obj2
class City:
def __init__(self,city):
self.city = city
def __eq__(self, other):
return self.__dict__ == other.__dict__
c1 = City('广州')
c2 = City('广州')
print(c1.__eq__(c2)) # 调用类的__eq__方法
print(c1 == c2) # 调用类的__eq__方法
print(c1,c2) # 对象空间的地址
'''
True
True
<__main__.C
七、__hash__ 方法
默认的__hash__()继承自对象本身,返回一个基于对象的内部ID值。
相同的hash值:这意味着两个对象可能是相等的。该hash值为我们提供了一个快速检查对象相等的可能性。如果hash值是不同的,两个对象不可能是相等的,他们也不可能是相同的对象。至关重要的是,内部ID和默认__hash__()方法间有一种强联系。
等号比较:这意味着hash值也一定相等。这是==操作符的定义。对象可能是相同的对象。
相同的IDD:这意味着他们是同一个对象。进行了等号比较且有相同的hash值。这是is操作符的定义。
然而,反过来是不正确的。对象可以有相同的hash值但比较是不相等的。在创建集合或字典时导致一些预计的处理开销是正当的。我们不能确切的从更大的数据结构创建不同的64位hash值。将有不相等的对象被简化为一致相等的hash值。
特点:
① 每次执行的哈希值都会变化
② 在一次执行哈希的过程中,对同一个值的hash结果总是不变的
字典寻址快的原因是运用了哈希算法,比二分查找快。
字典在内存中的存储方式:
每存储在内存的数据都有一个内存地址,字典会对键key进行哈希hash(key),把值放在hash的对应地址,所以字典的键是可哈希的
hash算法的特点:
① 对于相同的值在一次程序的运行中是不会变化的
② 对于不同的值在一次程序的运行中总是不同的
set的去重机制:
① 对每一个元素进行hash,计算出一个内存地址
② 到这个内存地址上查看,如果这块内存中没有值,将这个元素存到对应的内存地址上
③ 到这个内存地址上查看,如果这块内存中有值,判断这两个值是否相等。如果相等就舍弃后面的值,如果不相等就二次寻址,再找一个新的空间来存储这个值
自定义__hash__和__eq__方法
class Fruits: def __init__(self,name): self.name = name def __hash__(self): return hash(self.name) def __eq__(self, other): return self.__dict__ == other.__dict__ fruits_lis = ['apple','orange','banana'] obj_lis = [] for i in range(9): name = Fruits(fruits_lis[i%3]) obj_lis.append(name) print(obj_lis) print('-'*100) ret = set(obj_lis) print(ret) ''' [<__main__.Fruits object at 0x000001A5EF92C6D8>, <__main__.Fruits object at 0x000001A5EF9373C8>, <__main__.Fruits object at 0x000001A5EF9370F0>, <__main__.Fruits object at 0x000001A5EF937400>, <__main__.Fruits object at 0x000001A5EF937470>, <__main__.Fruits object at 0x000001A5EF937518>, <__main__.Fruits object at 0x000001A5EF937550>, <__main__.Fruits object at 0x000001A5EF937588>, <__main__.Fruits object at 0x000001A5EF9375C0>] ---------------------------------------------------------------------------------------------------- {<__main__.Fruits object at 0x000001A5EF9370F0>, <__main__.Fruits object at 0x000001A5EF92C6D8>, <__main__.Fruits object at 0x000001A5EF9373C8>} '''