第22篇 内置方法的进阶 __new__ __hash__ __eq__ json pickle

内置方法的进阶:
__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)#得到字符串的数据,进行相应的数据

  


{'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的类的对象,类不在的时候会报错








猜你喜欢

转载自www.cnblogs.com/cavalier-chen/p/9581466.html