一:__new__
在__init__之前,实例化对象的第一步是__new__创建了一个空间
class Foo: def __init__(self): # 初始化方法 print('执行了init') def __new__(cls, *args, **kwargs): # 构造方法 print('执行了new') return object.__new__(cls) obj = Foo() ''' 执行了new 执行了init 创造一个对象比喻成捏小人 new是小人捏出来了 init就是给小人穿衣服 '''
单例模式:
一个类,只有一个实例的时候
class Foo: __instance = None def __init__(self,name,age): # 初始化方法 self.name = name self.age = age def __new__(cls, *args, **kwargs): if cls.__instance is None: cls.__instance = object.__new__(cls) return cls.__instance obj1 = Foo('alex',38) obj2 = Foo('taibai',28) print(obj1,obj2) # <__main__.Foo object at 0x0132CE70> <__main__.Foo object at 0x0132CE70> print(obj1.name,obj2.name) # taibai taibai ''' 单例模式的时候,不管实例化多少个对象,永远只取最后一个对象的值 '''
二、__del__
析构方法,当对象在内存中被删除(释放)时,自动触发执行。
class Foo: def __init__(self,name,age): self.name = name self.age = age self.file = open('file', mode='w') def write(self): self.file.write('sdfsdgsdgs') def __del__(self): # 析构方法 : 在删除这个类创建的对象的时候会先触发这个方法,再删除对象 # 做一些清理工作,比如说关闭文件,关闭网络的链接,数据库的链接 self.file.close() print('执行del了') f = Foo('alex',38) del f print('hahahaha') ''' 执行del了 hahahaha '''
三、__len__
__len__支持的数据类型跟函数len()是一样的:lst dict set tuple str
# len()函数支持的数据类型---> lst dict set tuple str print('__len__' in dir(list)) # True print('__len__' in dir(dict)) # True print('__len__' in dir(set)) # True print('__len__' in dir(tuple)) # True print('__len__' in dir(str)) # True print('__len__' in dir(int)) # False print('__len__' in dir(float)) # False class Foo: def __len__(self): return 1 obj = Foo() print(len(obj)) # 1 class Class: def __init__(self,name,course): self.name = name self.course = course self.students = [] def __len__(self): return len(self.students) s1 = Class('骑士1班','python') s1.students.append('laowang') s1.students.append('laoliu') s1.students.append('laocheng') print(len(s1)) # 3
四、__eq__
自定义两个实例化对象的值是否相等,是的话返回True
class Staff: def __init__(self,name,sex): self.name = name self.sex = sex def __eq__(self, other): return self.__dict__ == other.__dict__ alex = Staff('alex','男') alex1 = Staff('alex','男') alex2 = Staff('alex','female') print(alex == alex1) # True 两个对象的值相同 print(alex2 == alex1) # False 两个对象的值不同 l1 = [1,2,3,4] l2 = [1,2,3,4] print(id(l1),id(l2)) # 1787304 1788464 print(l1 == l2) # True print(l1 is l2) # False
五、__hash__
1、每次执行hash值都会变化
2、在一次执行的过程中对同一个值的hash结果总是不变的
class Foo(): pass obj1 = Foo() obj2 = Foo() print(hash(obj1)) # 内存地址:319039 print(hash(obj2)) # 内存地址:318993 print(hash(obj2)) # 内存地址:318993 print(hash(obj2)) # 内存地址:318993 print(hash(obj2)) # 内存地址:318993 print(hash(obj2)) # 内存地址:318993 ''' hash算法 1、对于相同的值在一次程序的运行中是不会变化的 2、对于不同的值在一次程序的运行中总是不同的 '''
# 不用set去重 new_lst = [] lst = [2,2,43,53,238579,14780] for i in lst: if i in new_lst: pass else: new_lst.append(i) set = {1,2,'abc',3,4,5,6,7,8,9,'bca'} # 不能通过逐个判断值相等这件事儿来做去重工作 # hash算法也不是完全的靠谱 # # set 的去重机制 # 1.对每一个元素进行hash计算出一个内存地址 # 2.到这个内存地址上查看 # 如果这块内存中没有值 # 将这个元素存到对应的内存地址上 # 如果这块内存中已经有值 # 判断这两个值是否相等 # 如果相等 就舍弃后面的值 # 如果不相等 就二次寻址再找一个新的空间来存储这个值
# 员工类 # 姓名 年龄 性别 部门 # 转岗位后 # 姓名 年龄变化了 性别 部门变化了 # 100个员工,去掉重复的 # 员工的姓名 性别 是相同的,就认为是同一个员工 class Staff: def __init__(self,name,age,sex,dep): self.name = name self.age = age self.sex = sex self.dep = dep def __hash__(self): return hash(self.name + self.sex) def __eq__(self, other): if self.name == other.name and self.sex == other.sex: return True name_lst = ['alex','taibai','egon','peiqi'] obj_lst = [] for i in range(100): name = name_lst[i % 4] obj = Staff(name, i, 'male', 'python') obj_lst.append(obj) print(obj_lst) # 打印出了100个对象的内存地址 ret = set(obj_lst) print(ret) # 去掉重复的,只剩4个了 # 查看保留的值是保留前面的还是保留后面的 for i in ret: # 结果是保留前面的 print(i.name,i.age) ''' peiqi 3 taibai 1 egon 2 alex 0 '''
六、初识模块
别人写好的功能放在一个文件里
内置模块: 安装Python解释器的时候一起装上的
第三方模块、扩展模块: 需要自己安装
自定义模块: 自己写的py文件
序列化模块:
什么叫序列化:
将原本的字典、列表等内容转换成一个字符串、byets类型的过程就叫做序列化。
比如,我们在python代码中计算的一个数据需要给另外一段程序使用,那我们怎么给? 现在我们能想到的方法就是存在文件里,然后另一个python程序再从文件里读出来。 但是我们都知道,对于文件来说是没有字典这个概念的,所以我们只能将数据转换成字典放到文件中。 你一定会问,将字典转换成一个字符串很简单,就是str(dic)就可以办到了,为什么我们还要学习序列化模块呢? 没错序列化的过程就是从dic 变成str(dic)的过程。现在你可以通过str(dic),将一个名为dic的字典转换成一个字符串, 但是你要怎么把一个字符串转换成字典呢? 聪明的你肯定想到了eval(),如果我们将一个字符串类型的字典str_dic传给eval,就会得到一个返回的字典类型了。 eval()函数十分强大,但是eval是做什么的?e官方demo解释为:将字符串str当成有效的表达式来求值并返回计算结果。 BUT!强大的函数有代价。安全性是其最大的缺点。 想象一下,如果我们从文件中读出的不是一个数据结构,而是一句"删除文件"类似的破坏性语句,那么后果实在不堪设设想。 而使用eval就要担这个风险。 所以,我们并不推荐用eval方法来进行反序列化操作(将str转换成python中的数据结构) 为什么要有序列化模块
序列化的目的:
1、以某种存储形式使自定义对象持久化
2、将对象从一个地方传递到另一个地方
3、使程序更具维护性
json模块 & pickle模块
用于序列化的两个模块
json:用于字符串和Python数据类型间进行转换
pickle:用于Python特有的类型和Python的数据类型间进行转换
json模块:
json模块提供了四个功能:dumps、dump、loads、load
优点:
所有的语言都通用
缺点:
只支持非常少的数据类型
对数据类型的约束很苛刻
字典的key必须是字符串
只支持:数字、字符串、列表、字典
import json stu = {'name':'王瑞臣','sex':'male'} ret = json.dumps(stu) # 序列化的过程 print(stu,type(stu)) # {'name': '王瑞臣', 'sex': 'male'} <class 'dict'> print(ret,type(ret)) # {"name": "\u738b\u745e\u81e3", "sex": "male"} <class 'str'> d = json.loads(ret) # 反序列化的过程 print('d--->',d,type(d)) # d---> {'name': '王瑞臣', 'sex': 'male'} <class 'dict'> lst = [1,2,3,4,'aaa','bbb'] ret = json.dumps(lst) # 序列化的过程 print(lst,type(lst)) # [1, 2, 3, 4, 'aaa', 'bbb'] <class 'list'> print(ret,type(ret)) # [1, 2, 3, 4, 'aaa', 'bbb'] <class 'list'> d = json.loads(ret) # 反序列化的过程 print('d-->',d,type(d)) # d--> [1, 2, 3, 4, 'aaa', 'bbb'] <class 'list'> stu = {'name':'王瑞臣','sex':'male',1:('a','b')} ret = json.dumps(stu) # 序列化的过程 print(stu,type(stu)) # {'name': '王瑞臣', 'sex': 'male', 1: ('a', 'b')} <class 'dict'> print(ret,type(ret)) # {"name": "\u738b\u745e\u81e3", "sex": "male", "1": ["a", "b"]} <class 'str'> d = json.loads(ret) # 反序列化的过程 print('d-->',d,type(d)) # d--> {'name': '王瑞臣', 'sex': 'male', '1': ['a', 'b']} <class 'dict'> # 把元祖变成列表了
import json data = {'username':['李华','二愣子'],'sex':'male','age':16} json_dic2 = json.dumps(data,sort_keys=True,indent=4,separators=(',',':'),ensure_ascii=False) print(json_dic2) ''' sort_keys=True:将数据根据keys的值进行排序 indent=4: 表示每行开头4个空格 separators=(',',':'):分隔符,keys之间用“,”隔开,而key和value之间用“:”隔开 ensure_ascii=False:当False时,非ascii码才能正常显示 '''
pickle模块
pickle模块提供了四个功能:dumps、dump(序列化,存)、loads(反序列化,读)、load (不仅可以序列化字典,列表...可以把python中任意的数据类型序列化)
import pickle stu = {'name':'王瑞臣','sex':'male',1:('a','b')} ret = pickle.dumps(stu) # 序列化的过程 print(ret) # b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\t\x00\x00\x00\xe7\x8e\x8b\xe7\x91\x9e\xe8\x87\xa3q\x02X\x03\x00\x00\x00sexq\x03X\x04\x00\x00\x00maleq\x04K\x01X\x01\x00\x00\x00aq\x05X\x01\x00\x00\x00bq\x06\x86q\x07u.' d = pickle.loads(ret) # 反序列化的过程 print(d,type(d)) # {'name': '王瑞臣', 'sex': 'male', 1: ('a', 'b')} <class 'dict'> class Course(): def __init__(self,name,price): self.name = name self.price = price python = Course('python',29800) ret = pickle.dumps(python) # 序列化的过程 print(ret) # b'\x80\x03c__main__\nCourse\nq\x00)\x81q\x01}q\x02(X\x04\x00\x00\x00nameq\x03X\x06\x00\x00\x00pythonq\x04X\x05\x00\x00\x00priceq\x05Mhtub.' p = pickle.loads(ret) # 反序列化的过程 print(p.name,p.price) # python 29800