所有的作业讲解之后必须再敲一遍
讲之后在写一遍
反射
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__
哈希
- 每次执行hash值都会变化
- 再一次执行的过程中对同一个值得hash结果总是不变的
class Foo():pass
obj1 = Foo()
obj2 = Foo()
print(type(hash(obj1))) #int
print(type(hash(obj2)))
字典寻址快原因
!!!error 溜号了没听明白
!!!
字典在内存中是如何存储的?
为什么字典的key必须可hash?
字典通过key转变的hash值直接找到内存中值的地址
hash算法原理
- 对于相同的值在同一次程序的运行中是不会变化的
- 对于不同的值在一次程序的运行中总是不同的
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)
- 对每个元素进行hash计算出一个内存地址
- 到这个内存地址上查看
- 如果这块内存中没有值
- 将这个元素存到对应的内存地址上
- 如果这块内存中已经有值
- 判断这两个值时候相等
- 如果相等,就舍弃后面的值
- 如果不相等就二次须知再找一个新的内存空间
!!!
第二种用例是在动态执行环境中支持协作多重继承。
super() 被实现为用于显式点属性查找(例如 super().getitem(name))的绑定过程的一部分。它通过实现自己的 getattribute() 方法来搜索类,以可预测的顺序支持合作多重继承。因此,super() 未定义用于使用诸如 super()[name] 的语句或操作符的隐式查找。
内置方法的例子
纸牌游戏
面试题
常用模块
- 序列化模块
- 随机数模块
别人写好的功能放在一个文件里
内置模块 安装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一个参数。,正常需要有多种字段的传入。