内置方法的进阶:
__new__ *****
__del__
__len__
__hash__
__eq__
item系列
内置方法的应用举例
纸牌游戏
面试题 员工信息去重
(1)__new__
在实例化对象的时候,在执行__init__给对象生成属性之前,发生了什么?
谁来开辟对象空间?
class Foo: def __init__(self): print('执行了init') def __new__(cls, *args, **kwargs): print('执行了new') return object.__new__(cls)#传入的参数是cls 说明是类Foo创建对象的空间 obj1 = Foo()
执行了new 执行了init
整个过程如下:
Foo() 实例化先执行__new__方法-->但是Foo里面没有__new__方法
-->到类的祖宗 object类中去找-->执行object中的__new__方法
-->开辟一块属于对象的空间-->把self(这个对象本身)传进去,执行__init__方法
再来理解一下上面的过程
__new__方法叫做构造方法,构造出一个对象空间
__init__方法叫做初始化方法,给对象里面存放对象属性
整个过程比喻成上帝造人
__new__方法就是把人捏出来
__init__方法就是给人赋予一定的属性,人的名字,性格,灵魂,,,
设计模式
python中有23中常见的设计模式
现在学一种简单的模式
单例模式:这个类生成的所有对象都是同一个对象
class Foo: __instance = None #私有化一个类属性 def __init__(self): pass def __new__(cls, *args, **kwargs): if cls.__instance is None: cls.__instance = object.__new__(cls)#到obj里面调用__new__方法,以类Foo生成对象 return cls.__instance obj1 = Foo() obj2 = Foo() print(obj1,obj2) <__main__.Foo object at 0x000000F4EC208CF8> <__main__.Foo object at 0x000000F4EC208CF8>
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)#到obj里面调用__new__方法,以类Foo生成对象 return cls.__instance obj1 = Foo('alex',28) obj2 = Foo('Egon',29) print(obj1.name,obj2.name) print(obj1.age,obj2.age) Egon Egon 29 29
可以看到这里是同一个对象
在类里面年实现len方法??
class Foo: def __len__(self): return 1 obj = Foo() print(len(obj))#1
#len(对象)自动触发
def __len__(self): return 1
也就是相当与执行了__len__(对象)这么一个函数 返回值是1
class Class: def __init__(self,name,course): self.name = name self.course = course self.student = [] def __len__(self): return len(self.student) s1 = Class('1','python') s1.student.append('wuyi') s1.student.append('yangyi') s1.student.append('wangfang') print(len(s1))#3
class Staff(): def __init__(self,name,sex): self.name = name self.sex = sex alex = Staff('alex','male') alex2 = Staff('alex','male') print(alex ==alex2)#False 应为这里生成的是两个不同的对象 虽然两个对象的属性是一样的 l1 = [1,2,3,4] l2 = [1,2,3,4]
print(id(l1),id(l2))#522064697032 522077784904 l1,l2放在不同的地方
print(l2 == l1)#True #两边的值是相等的
那么为了使得两个对象的属性相等的时候 生成的是同一个对象 应该怎么办??
class Staf: def __init__(self,name,sex): self.name = name self.sex = sex def __eq__(self, other): return True #不管你传入什么 都认为是相等的 alex = Staf('alex','male') alex2 = Staf('alex','male') alex3 = Staf('alex2','female') print(alex==alex2) print(alex3==alex2) print(alex==alex3) True True True
class Foo: pass obj1 = Foo() obj2 = Foo() print(hash(obj1))-9223372025455966001 print(hash(obj2))-9223372025455966015 print(hash(obj1))-9223372025455966001 print(hash(obj2))-9223372025455966015 print(hash(obj1))-9223372025455966001
总结:在同一次程序启动的时候 hash同样的对象会得到相同的结果
但是下一次启动程序的时候得到的结果与前一次不相同
字典在内存中是如何存储的?字典的key为什么必须是可哈希?
dic = {'name':'alex','age':28,'sex':'male'}
name --> hash('name')-->1765436541-->拿着这个地址直接放到内存中
不同的name对应不同的哈希值,根据key的哈希值 直接去访问
set的去重机制
1,对每个元素进行hash运算 得到一个内存地址
2,到这个内存地址去查看
#如果这个地址没有值,将这个元素存到对应的内存地址上
#如果这个地址已经有元素
#判断这两个元素的值是否相等,
#如果相等,舍弃后面进来的这个值
#如果不相等,进行二次寻址,找一个新的空间来存储这个值
(2)模块
什么是模块?
别人写好的功能,放在一个文件里面,
什么是内置模块?安装python解释器的时候,一起安装的功能模块。
什么是第三方模块?也叫做扩展模块,使用的时候需要自己安装的功能模块,jangGou,爬虫
自定义模块?自己写的py文件
(3)什么叫做序列化?为什么要进行序列化?
把一个数据转换成字符串或者bytes类型的过程就叫做序列化。
为什么要进行序列化?
当需要把一个数据存储在文件中的时候
当需要把一个数据通过互联网进行传输的时候
stu = {'name0':'何青松','age':20,'sex':'male'} ret = str(stu) print(ret)#得到字符串的数据,进行相应的数据
扫描二维码关注公众号,回复:
3038009 查看本文章
{'name0': '何青松', 'age': 20, 'sex': 'male'}
print(eval(ret))#读取到str形式的数据,执行该数据
{'name0': '何青松', 'age': 20, 'sex': 'male'}
但是eval()不嫩更随便用,因为这个重网络或者别的渠道获得的ret里面可能含有病毒
(4)json
JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。
它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,
采用完全独立于编程语言的文本格式来存储和表示数据。
简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。
易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
下面学习一个安全的读取和写入文件的模块json
先学一个单词
dump n:仓库,无序的累积,忧郁
vt:倾倒,随便堆放
import json stu = {'name0':'何青松','age':20,'sex':'male'} ret = json.dumps(stu)#注意哦这里是damps 带s的哦 print(stu) print(ret)
{'name0': '何青松', 'age': 20, 'sex': 'male'} {"name0": "\u4f55\u9752\u677e", "age": 20, "sex": "male"}
可以看到json.dumps()之后的字典,字符类型的全部变成双引号 中文变成bytes类型
import json stu = {'name0':'何青松','age':20,'sex':'male'} ret = json.dumps(stu)#注意哦这里是damps 带s的哦
print(stu,type(stu))
print(ret,type(ret))
{'name0': '何青松', 'age': 20, 'sex': 'male'} <class 'dict'> {"name0": "\u4f55\u9752\u677e", "age": 20, "sex": "male"} <class 'str'>
可以看到一个是dict数据类型
可以看到一个是str数据类型
str形式的数据有怎么还原成原来的数据类型??
import json
stu = {'name':'何青松','age':20,'sex':'male'}
ret = json.dumps(stu)#注意哦这里是damps 带s的哦
print(ret,type(ret))
d = json.loads(ret)#注意哦这里是loads 带s的哦
print('d-->',d,type(d))
{"name": "\u4f55\u9752\u677e", "age": 20, "sex": "male"} <class 'str'>
d--> {'name': '何青松', 'age': 20, 'sex': 'male'} <class 'dict'>#还原成了一个字典
列表的序列化
import json li = [1,2,3,'aaa','bbb'] ret = json.dumps(li) print(ret,type(ret))
[1, 2, 3, "aaa", "bbb"] <class 'str'>#再次可看到字符串变成了双引号
json的优缺点:
优点:所有的语言都通用
缺点:只支持非常少的数据类型
对于数据类型的约束很苛刻
import json
stu = {'name':'何青松','sex':'male',1:('a','b')}
ret = json.dumps(stu)
print(ret)
d = json.loads(ret)
print('d-->',d,type(d))
{"name": "\u4f55\u9752\u677e", "sex": "male", "1": ["a", "b"]}
d--> {'name': '何青松', 'sex': 'male', '1': ['a', 'b']} <class 'dict'>#可以看到数字1 变成了双引号的字符串,元组变成了字典
对于数据类型的约束:
字典的key必须是字符串
字典你的value只支持:数字,字符串,类表字典
(5)学习下一个问文件读取的操作模块pickle
pickle的本意
vt 腌渍泡菜
将数据以及类实例化的对象腌渍起来,长时间的保存在文件中,留着下次使用
import pickle stu = {'name':'何青松','sex':'male',1:('a','b')} ret = pickle.dumps(stu) print(ret) print(type(ret))
b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\t\x00\x00\x00\xe4\xbd\x95\xe9\x9d\x92\xe6\x9d\xbeq\x02X\x03\x00\x00\x00sexq\x03X\x04\x00\x00\x00maleq\x04K\x01X\x01\x00\x00\x00aq\x05X\x01\x00\x00\x00bq\x06\x86q\x07u.'
<class 'bytes'>#可以看到获得的是一个bytes类型的数据
b = pickle.loads(ret) print('b-->',b) print(type(b)) b--> {'name': '何青松', 'sex': 'male', 1: ('a', 'b')} <class 'dict'>#可以看到pickle.loads()方法将bytes类型的数据 还原成了字典
pickle.loads()
pickle.damps()
这两真正厉害的地方是用来处理类生成的多个对象 *****
import pickle
class Course:
def __init__(self,name,price):
self.name = name
self.price = price
python = Course('python',29800)
ret = pickle.dumps(python)#将python这个对象转成字符串
print(ret)
obj = pickle.loads(ret)#将字符串还原成对象
print(obj)
print(obj.name)
print(obj.price)
#pickle.dumps(python)方法 对象生成的bytes形式的字符串
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.'
<__main__.Course object at 0x00000002FB99DAC8>#bytes形式的字符串 还原成 Course生成的对对象
#注意要是 类的定义不存在的话 对象的属性无法获取
python
29800
json文件的写入
import json
dic= {'name': '何青松', 'sex': 'male'}
str= json.dumps(dic)
with open('json_file','w') as f:
f.write(str)
写入的文件是:{"name": "\u4f55\u9752\u677e", "sex": "male"}
为了让bytes类型的数据在文件能够看懂,需要添加一个参数ensure_ascii=False
import json
dic= {'name': '何青松', 'sex': 'male'}
str= json.dumps(dic,ensure_ascii=False)
print(str)
{"name": "何青松", "sex": "male"}
import json
dic= {'name': '何青松', 'sex': 'male'}
str= json.dumps(dic,ensure_ascii=False)#json.dumps()方法生成字符串添加参数ensure_ascii=False
with open('json_file','w',encoding= 'utf-8') as f:#写入的时候增加问价编码:encoding= 'utf-8'
f.write(str)
写入文件的数据是:{"name": "何青松", "sex": "male"}
如何读取已经写入文件的数据?
import json with open('json_file','r',encoding='utf-8') as f:#文件中有中文编码方法encoding = 'utf-8' content = f.read() ret = json.loads(content)#使用json.loads()方法将读到的数据转化成原来的数据类型 print(ret,type(ret))
{'name': '何青松', 'sex': 'male'} <class 'dict'>
修改文件中的数据,使用json.loads()方法是否还能够转化数据?
将文件修改成:{"name": "何青松", "sex": "male","age":"83"}
#注意key 一定要是字符串而且使用双引号
import json with open('json_file','r',encoding='utf-8') as f:#文件中有中文编码方法encoding = 'utf-8' content = f.read() ret = json.loads(content) print(ret) print(ret['age']) {'name': '何青松', 'sex': 'male', 'age': '83'} 83
json.dump(需要转化的数据,需要写入的文件句柄)
方法接受的是两个参数,这里与json.damps()有所不同
import json dic= {'name': '何青松', 'sex': 'male'} with open('json_file',encoding='utf-8',mode='w') as f: json.dump(dic,f)
写入的数据是 {"name": "\u4f55\u9752\u677e", "sex": "male"}
import json dic= {'name': '何青松', 'sex': 'male'} with open('json_file',encoding='utf-8',mode='w') as f: json.dump(dic,f,ensure_ascii=False)#添加另个参数ensure_ascii=False 写入的中文变得可以看懂
写入的数据是 :{"name": "何青松", "sex": "male"}
与json.damp相对应的json.load()方法
json.load(读取的文件句柄)
json.load()方法接受的是文件句柄参数,
import json
dic= {'name': '何青松', 'sex': 'male'}
with open('json_file',encoding='utf-8',mode='r') as f:
ret = json.load(f)
print(ret,type(ret))
{'name': '何青松', 'sex': 'male'} <class 'dict'>
总结一下:
damp load完全是与文件的读取打交道
能不能够使用json.damp()方法向一个文件多次写入数据,?可以
但是,不能load
import json dic = {'name': '何青松', 'sex': 'male'} with open('json_file',mode='w',encoding='utf-8') as f: json.dump(dic,f,ensure_ascii=False) json.dump(dic,f,ensure_ascii=False) json.dump(dic,f,ensure_ascii=False) json.dump(dic,f,ensure_ascii=False)
{"name": "何青松", "sex": "male"}{"name": "何青松", "sex": "male"}{"name": "何青松", "sex": "male"}{"name": "何青松", "sex": "male"}
json.damp()方法多次写入数据没有问题
import json dic = {'name': '何青松', 'sex': 'male'} with open('json_file',mode='w',encoding='utf-8') as f: json.dump(dic,f,ensure_ascii=False) json.dump(dic,f,ensure_ascii=False) json.dump(dic,f,ensure_ascii=False) json.dump(dic,f,ensure_ascii=False) with open('json_file',encoding='utf-8',mode='r') as f : dic = json.load(f) print(dic)
JSONDecodeError: Extra data: line 1 column 31 (char 30)
json解码遇到错误!!!
现在就是有这么一个需求,写入多个字典,并且读取出来
import json def my_dump(dic): with open('json_file','a',encoding='utf-8') as f: dat = json.dumps(dic)#将需要写入的数据使用json.dumps()方法生成bytes f.write(dat+'\n') dic1 = {'name': '何青松', 'sex': 'male'} dic2 = {'name': '关亮何', 'sex': 'male'} dic3 = {'name': '何思浩', 'sex': 'male'} my_dump(dic1) my_dump(dic2) my_dump(dic3)
-->
{"name": "\u4f55\u9752\u677e", "sex": "male"} {"name": "\u5173\u4eae\u4f55", "sex": "male"} {"name": "\u4f55\u601d\u6d69", "sex": "male"}
import json
with open('json_file','r',encoding='utf-8') as f:
for line in f:
dic = json.loads(line.strip())
print(dic['name'])
-->
何青松
关亮何
何思浩
总结一下json:
在左右的语言中通用
能够处理的数据类型非常的有限
也就是是在网络操作中,以及多语言环境中,需要传递的字典,数字,字符串。。
json的字典要求非常的苛刻:
key必须是字符串,
json.dumps(dic/list) dic/list--> str 序列化
json.loads(str) str--> dic/list 反序列化
json.dump(dic/list,f) dic/lis-->文件 序列化
json.load(f) 文件-->dic/lis 反序列化
参数 ensure= False 希望系列化的中文能以中文的形式被显示或者存放
总结一下pickle方法
pickle.dump(dic/str,f)
pickle.load(f)
操作文件必须用+b的模式打开
在load的时候,入股哦这个要被load的类的对象,类不在的时候会报错