内置方法,序列化模块

所有的作业讲解之后必须再敲一遍
讲之后在写一遍

反射
hasattr
getattr

  类名反射
      类名.静态属性  getattr(类名,"静态属性")
      对象名放射  getattr(类名,"类方法")()
      类名.静态方法() getattr(类名,"静态方法")()
      
      对象.对象属性 getattr(对象,"对象属性")
      对象.方法()  getattr(对象,"方法")
      模块名,方法
      模块名,类名
      模块名,变量
      模块名,函数
      
      本文件反射
      imp sys
      getattr(sys.modules[__name__]),所有定义在这个文件中的名字

setattr 给命名空间的某一个名字设置一个值
delattr 删除某一个命名空间中变量对应的值

内置方法

不用调用这个
方法就可触发这个方法的执行
__str__

格式化输出 "%s" % obj
print(obj)
数据类型的强制转换

__repr__ 当使用会触发str方法的方式但是Foo类内部又没有实现__str__方法时候都会调用__repr__

  '%r' % obj
  '!r'.format
  repr()

作业总结

购物车,是训练整段代码的驾驭能力,面向过程编程的使用
员工信息系统,数据库系统原理的初识
选课系统,面向对象编程的综合

!!!note

类的type都是type

class A:pass
print(type(A))
-----------
"输出"
<class "type">
-----------

!!!

fomat

class A:
    name = "sfsd"
    def __repr__(self):
        return "bob"
    def __str__(self):
        return "b"
    def func(self):
        return "1"
print("{}".format(A()))
print("{.name}".format(A))
print("{:,}".format(132545443))
print("{:o}".format(8))
print("{:x}".format(16))
print("{:.2f}".format(43424.5435))
print("{:a>20.4f}".format(234235.2342342))
print("{1[1]},{0[0]}".format((1,34),(67,45)))
print("{:+.3f}".format(23432444.23432))
print("{sd},{va},{fd}".format(va="1",fd=67,sd="qwe"))
emailf = "Your email address was {email}".format
print(emailf(email="wodani@dd.com"))
print("{}{{0}}".format("empty"))
print("{!a}".format("牛逼"))
print("{0:#d},{0:#x},{0:#b},{0:#o}".format(23))
print(type(A))

内置方法的进阶

__new__
__del__
__len__
__hash__
__eq__

__new__

在init之前,实例化对象的第一步是__new__创造了一个空间
python代码无法创建空间,创建空间交给了object.new()
执行顺序

    实例化Foo,先执行__new__方法,
    但是Foo类没有__new__方法,
    到object类中去找先执行object中的__new__方法,
    开辟了一块属于对象的空间,
    才开始执行initself正式刚才创造的空间

class Foo:
  def __init__(self): # 初始化方法
      print("执行了init") 
  def __new__(cls,*args,*kwargs):  # "构造方法"
      print("执行了new") 
      return object.__new__(cls)
    #return super().__new__(cls)
obj = Foo()
创造一个对象

设计模式

23种
来自java
单例模式

"一个类只有一个实例的时候 单例模式"
class Foo: pass
obj1 = Foo()
obj2 = Foo()

class Foo:
  __instance =None
  def __init__(self):pass
  def __new__(cls,*args,*kwargs):
    if cls.__instance is None:
        cls.__instance = object.__new__(cls)
      return cls.__instance
obj1 = Foo("alex",20)
obj2 = Foo("egon",22)

__del__

在删除这个类创建的对象的时候会先触发这个方法啊,再删除这个对象
比如说关闭文件,关闭网络连接,关闭数据库

class Foo:
  def __init__(self):
    self.age= age
    self.file = open("file",mode="w")
  def write(self):
    self.file.write("sdjfklsdjf")
  def __del__(self): #析构方法 
    self.file.close()
    print("执行了del了")

__len__

统计对象的长度


class Classes:
  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("wuyi")
s1.students.append("wangfan")
print(len(s1))

__eq__

class Staff:
    def  __init__(self,name,sex):
      self.name = name
      self.sex = sex
    def __eq__(self,other):
      return self.name == other.name
      # return self.__dict__ == other.__dict__
alex = Staff("alex","不详")
alex2 = Staff("alex","不详")
print(alex == alex2) #值判断
print(alex is alex2) #身份判断

__hash__ 哈希

  1. 每次执行hash值都会变化
  2. 再一次执行的过程中对同一个值得hash结果总是不变的
class Foo():pass
obj1 = Foo()
obj2 = Foo()
print(type(hash(obj1))) #int
print(type(hash(obj2)))

字典寻址快原因
!!!error 溜号了没听明白
!!!
字典在内存中是如何存储的?
为什么字典的key必须可hash?
字典通过key转变的hash值直接找到内存中值的地址

hash算法原理

  1. 对于相同的值在同一次程序的运行中是不会变化的
  2. 对于不同的值在一次程序的运行中总是不同的

set的去重机制
!!!error
list去重需要遍历 并且in判断 时间 O(n)
set = {1,2,3,4,5,6,7,8,9}
不能通过逐个判断值相等这件事来做去重工作
内存地址与值
hash 1 1地址 1值
hash 2 2地址 2值
hash 2 得到结果地址由于也是2 但是里面有值,也就不去存储
hash n 得到的值如果没有内存地址 那么表示没有新的值
hash算法也不是完全靠谱
如果也别长可能会相同
如果刚好hash值一样,再做一个值得比对,如果值不相同,然后再对新的值二次寻址

"面试题"
> 员工类
> 姓名 性别 年龄 部门
> 转岗位
> 姓名 年龄变化了 性别 部门  
> 100个员工 去掉重复的
> 员工的姓名和性别是相同的,就认为使用一个员工

> 答案
"通过重写__hash__以及__eq__对大列表去重"
"得到了hash值相等了,但是set的机制是地址相同之后开始判断值是不是相同"
"所以要通过eq方法过去"
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 = ["yuanhao","egon","nazha","peqi"]
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)
ret = set(obj_lst)
print(ret)
for i in ret:
  print(i)
  1. 对每个元素进行hash计算出一个内存地址
  2. 到这个内存地址上查看
  3. 如果这块内存中没有值
  4. 将这个元素存到对应的内存地址上
  5. 如果这块内存中已经有值
  6. 判断这两个值时候相等
  7. 如果相等,就舍弃后面的值
  8. 如果不相等就二次须知再找一个新的内存空间
    !!!

第二种用例是在动态执行环境中支持协作多重继承。
super() 被实现为用于显式点属性查找(例如 super().getitem(name))的绑定过程的一部分。它通过实现自己的 getattribute() 方法来搜索类,以可预测的顺序支持合作多重继承。因此,super() 未定义用于使用诸如 super()[name] 的语句或操作符的隐式查找。

内置方法的例子

纸牌游戏
面试题

常用模块

  1. 序列化模块
  2. 随机数模块

别人写好的功能放在一个文件里
内置模块 安装python解释器时一起装上的。
第三方模块,扩展模块:需要自己安装
自定义模块:自己写了含有功能的。自己写的py文件

序列化模块

什么叫序列化
序列
字符串
bytes

把一个数据类型转换成字符串,bytes类型的过程就叫做序列化。

为什么要把一个数据类型序列化了?
当你需要把一个数据类型存储在文件中。
当你需要把一个数据类型同过网络传输的时候

不能用eval() 用户输入 ,文件读入,网络传入

"不支持单引号"
import json
stu = {"name":"何青松","sex":"male"}
ret = json.dumps(stu) #序列化
d = json.loads(ret) #反序列化
print(stu)
print(ret)
print(d)

json的优点

所有的语言都通用

缺点

只支持非常少的数据类型
对数据类型的约束很苛刻
字典的key必须是字符串
只支持:数字 字符串 列表 字典 (元组会强转成列表)

待实践 扩展 JSONEncoder

pickle 模块

import pickle
stu = {"name":"何青松","sex":"male",1:("a","b")}
ret = pickle.dumps(stu) #拿到的永远是字节
print(ret)
d = pickle.loads(ret)
print(d,type(d)) #搞定了数字类型的key以及value为元组类型

class Course():
  def __init__(self,name,price):
    self.name = name
    self.price = price
python = Course("python",29800)
ret = pickle.dumps(python)
print(ret)
p = pickle.loads(ret)
print(p.name,p.price)
"手动创建也需要单引号"
stu = {"name":"何青松","sex":"male",1:("a","b")}
str_dir1 =  json.dumps(dic,ensure_ascii=False) #可现实中文
with open("json_file","w",encoding="utf8") as f:
  f.write(str_dir1)

with open("json_file","r",encoding="utf8") as g:
    content = g.read()
ret = json.loads(content)

with open("json_file","w",encoding=utf8) as h:
json.dump(stu,f)
with open("json_file","w",encoding=utf8) as k:
dic =  json.load(k)
print(dic,dic["name"])

能不能多次向一个文件中dump?
可以多次dump但是不能多次load

stu = {"name":"何青松","sex":"male",1:("a","b")}
with open("json_file","w",encoding="utf8") as g:
  json.dump(dic,g,ensure_asii=False)
  json.dump(dic,g,ensure_asii=False)
  json.dump(dic,g,ensure_asii=False)
  json.dump(dic,g,ensure_asii=False)
with open("json_file","r",encoding="utf8") as g:
  dic = json.load(f)

有需求向文件中写入多个字典
只能用dumps转化成字符串在一一添加和用loads一行行去空白加载

def my_dumps(dic):
  with open("json_file","a",encoding="utf8") as f:
      for line in f:
        dic = json.loads(line.strip())
        print(dic["name"])      
  

json
可以在所有的语言中通用
能够处理的数据类型非常有限
在网络操作中以及多语言环境中,要传递字典,数字,字符串,列表等简单的数据类型
json的字典非常苛刻:key必须是字符串,所有的的字符串必须用“”
dumps dic/list str 序列化
loads str dic/list 反序列化方法
dump dic/list 文件 序列化方法
load 文件 dic/list 反序列 多次dump进入文件中的数据不能多次load会报错
ensureascii 希望序列化的中文显示为中文并且写到文件中

pickle
全是b,b不指定编码

with open("pick_file","wb") as f:
  pickle.dump(python,f)
with open("pick_file","rb") as f:
  course =  pickle.load(f)

当他load时需要类存在
dump
load
操作文件必须以b的形式打开
在load时候如果这个要被load的内容不在内从中会被报错

pickle 能不能多次dump?

python = Course("python",29800)
linux = Course("linux",29800)
mysql = Course("sql",25800)
def my_dump(course):
  with open ("picke","ab") as f:
        pickle.dump(course,f)
my_dump(python)
my_dump(linux)
my_dump(mysql)
"由于不知道什么时候取完需要识别异常"
with open("pickle","rb") as f:
    while True:
      try:
        content = pickle.load(f)
        print(content.name)
      except EOFError:
          break

pickle 支持多次dump和多次load,需要异常处理

作业

每次角色实例化通过类方法传name进去不会像我构建的那样影响__init__列表,我的列表只有name一个参数。,正常需要有多种字段的传入。

posted @ 2018-09-03 17:31  寓清于浊  阅读(177)  评论(0编辑  收藏  举报