文章目录
单继承中的super
supe() 使用的时候,传递参数的时候,self不用传递
super() 调用顺序,按照mro顺序来完成
class Parent(object):
def __init__(self, name):
self.name = name
print("parent 的 init结束被调用")
class Son1(Parent):
def __init__(self, name, age):
self.age = age
super().__init__(name)
print("Son1 的init结果被调用")
class Grandson(Son1):
def __init__(self, name, age, gender):
self.gender = "男"
super().__init__(name, age)
print("Grandson 的 init结束被调用")
gs = Grandson("grandson", 12, "男")
print(Grandson.__mro__) # 结果是一个元组
print("姓名: ", gs.name)
print("年龄: ", gs.age)
print("性别: ", gs.gender)
# 输出
# parent 的 init结束被调用
# Son1 的init结果被调用
# Grandson 的 init结束被调用
# (<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Parent'>, <class 'object'>)
# 姓名: grandson
# 年龄: 12
# 性别: 男
多继承以及MRO顺序
什么是多继承?
⼀个⼦类同时继承⾃多个⽗类,⼜称菱形继承、钻⽯继承。
class Parent(object):
def __init__(self, name):
self.name = name
print("parent 的init被调用")
class Son1(Parent):
def __init__(self, name, age):
self.age = age
Parent.__init__(self, name) # self 不能省略
print("Son1 的init被调用")
class Son2(Parent):
def __init__(self, name, gender):
self.gender = gender
Parent.__init__(self, name)
print("Son2 的init被调用")
class Grandson(Son1, Son2):
def __init__(self, name, age, gender):
Son1.__init__(self, name, age) #单独调用父类的初始化方法
Son2.__init__(self, name, gender)
print("Grandson 的init被调用")
# 创建对象
gs = Grandson("grandson", 12, "男")
# parent 的init被调用=======
# Son1 的init被调用
# parent 的init被调用=======
# Son2 的init被调用
# Grandson 的init被调用
问题: 从代码运⾏结果看,Grandson 被初始化⼀次,⽽Parent类中的初始化⽅法被调⽤多次,这显然 不合理,
解决方案:我们可以使⽤super() 来调⽤⽗类的⽅法
class Parent(object):
def __init__(self, name, *args, **kwargs):
self.name = name
print("parent 的init被调用")
class Son1(Parent):
def __init__(self, name, age, *args, **kwargs):
self.age = age
super().__init__(name, *args, **kwargs)
print("Son1 的init被调用")
class Son2(Parent):
def __init__(self, name, gender, *args, **kwargs):
self.gender = gender
super().__init__(name, *args, **kwargs)
print("Son2 的init被调用")
class Grandson(Son1, Son2):
def __init__(self, name, age, gender):
super().__init__(name, age, gender)
#Son1.__init__(self, name, age) #单独调用父类的初始化方法
#Son2.__init__(self, name, gender)
print("Grandson 的init被调用")
# 创建对象
gs = Grandson("grandson", 12, "男")
print(Grandson.mro())
#[<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>]
# parent 的init被调用
# Son2 的init被调用
# Son1 的init被调用
# Grandson 的init被调用
parent 只被调⽤了1次!这是因为⼀旦使⽤了super() 后,调⽤顺序不 是按照继承顺序,⽽是遵守 MRO顺序。
super本质上就是使用MRO这个顺序去调用 当前类在MRO顺序中的下一个类
查看mro顺序的方法: 类名.mro() 类名.__mro__
注意:
- 以上2个代码执⾏的结果不同
- 如果2个⼦类中都继承了⽗类,当在⼦类中通过⽗类名调⽤时,parent被执⾏了2次
- 如果2个⼦类中都继承了⽗类,当在⼦类中通过super调⽤时,parent被执⾏了1次
@property装饰
- 特点: 使得我们通过对象.方法名 的 方式可以调用方法
- 定义时,在实例方法的基础上添加@property装饰器;并且仅有一个self参数
- 调用时,无需括号
- 语法格式:
@property
def xxx(self):
pass
class Foo(object):
def __init__(self, num):
self.num = num
#获取值的方法
@property
def prop(self):
return self.num
# 创建对象
foo = Foo(100)
# 调用对象的方法
# print(foo.prop())
# @property 像使用属性一样去使用方法,获取值
print(foo.prop) # foo.prop ----> foo.prop()
property属性的两种方法setter、deleter
- 经典类:@property 一种方式
- 新式类:
@property goods.price 获取价格的方法
@xxx.setter goods.price =xxx
@xxx.deleter del goods.price
class Good(object):
def __init__(self):
self.org_price = 1000
self.discount = 0.7
# 获取价格的方法
@property
def price(self):
return self.org_price * self.discount
# 设置价格的方法
@price.setter
def price(self, val):
if val > 0:
self.org_price = val
# 删除价格的方法
@price.deleter
def price(self):
print("执行了 deleter 方法")
# 创建对象
goods = Good()
# goods.price == goods.price()
print(goods.price) # ⾃动执⾏ @property 修饰的 price ⽅法,并获取⽅法的返回值
goods.price = 500 # ⾃动执⾏ @price.setter 修饰的 price ⽅法,并将 500 赋值给⽅法的参数
print(goods.price) # ⾃动执⾏ @price.deleter 修饰的 price ⽅法
del goods.price
# 700.0
# 350.0
# 执行了 deleter 方法
property作为 类属性
- 定义property 对象的类属性:
xxx = property(参数1,参数2,参数3,参数4)
第一个参数是方法名,当我们 goods.BAR 自动调用第一个参数的方法
第二个参数是方法名,当我们 goods.BAR = 100, 自动调用第二个参数的方法
第三个参数是方法名,当我们 del goods.BAR , 自动调用第三个参数的方法
第四个参数是字符串,当我们 Good.BAR.doc,自动获取第四个参数的内容 - 使用
1.对象.xxx 获取值
2.对象.xxx = 100 设置值
3.del 对象.xxx 调用第三个参数方法
4.类.xxx.__doc__
获取第四个参数的内容
class Good(object):
def __init__(self):
self.org_price = 1000
self.discount = 0.7
# 获取价格的方法
def get_price(self):
return self.org_price * self.discount
# 设置价格的方法
def set_price(self, val):
if val > 0:
self.org_price = val
# 删除价格的方法
def del_price(self):
print("执行了 deleter 方法")
# property(第一个参数,第二个参数,第三个参数,第四个参数)
# 第一个参数,当我们 goods.BAR 自动调用第一个参数的方法
# 第二个参数,当我们 goods.BAR = 100, 自动调用第二个参数的方法
# 第三个参数,当我们 del goods.BAR , 自动调用第三个参数的方法
# 第四个参数,当我们 Good.BAR.__doc__,自动获取第四个参数的内容
BAR = property(get_price, set_price, del_price, "BAR 是一个property对象")
if __name__ == '__main__':
# 创建对象
goods = Good()
print(goods.BAR)
# 设置价格
goods.BAR = 500
print(goods.BAR)
# 删除价格
del goods.BAR
# 获取对象描述
print(Good.BAR.__doc__)
魔法属性和方法
魔法属性
__doc__
表示类的描述信息
获取类的类名.__doc__
获取方法的描述对象.方法名.__doc__
__module__
表示当前操作的对象在哪个模块(对象名.__module__
),直接运行.py文件,获得__main__
__class__
获取对象所属的类 (对象名.__class__
) # <class ‘main.Good’>__dict__
获取类或对象中的所有属性
1)获取类的属性、方法,类名.__dict__
返回值是一个字典
{‘module’: ‘main’, ‘init’: <function Good.init at 0x000001CCBEEB5400>, ‘get_price’: <function Good.get_price at 0x000001CCBEEB5488>, ‘set_price’: <function Good.set_price at 0x000001CCBEEB5510>, ‘del_price’: <function Good.del_price at 0x000001CCBEEB5598>, ‘BAR’: <property object at 0x000001CCBEBABB38>, ‘dict’: <attribute ‘dict’ of ‘Good’ objects>, ‘weakref’: <attribute ‘weakref’ of ‘Good’ objects>, ‘doc’: None}
2)获取对象的属性,对象名.__dict__
,也就是init里面初始化的内容,返回也是字典
魔法方法
__init__
初始化⽅法,通过类创建对象时,即:对象 = 类名()⾃动触发执⾏__del__
删除对象的时候,会调用del对象(当对象在内存中被释放时,⾃动触发执⾏)
注: 此⽅法⼀般⽆须定义,因为Python是⼀⻔⾼级语⾔,程序员在使⽤时⽆需关⼼内存的分配和释放,因为此⼯作都是交给Python解释器来执⾏,所以,__del__的调⽤是由解释器在进⾏垃圾回收时⾃ 动触发执⾏的。__call__
对象后⾯加括号,触发执⾏,即对象()__str__
如果⼀个类中定义了__str__⽅法(一定要返回字符串内容),那么在打印 对象 时,默认输出该⽅法的返回值。 如:goods = Goods() print(goods)__getitem__
.__setitem__
.__delitem__
⽤于索引操作,如字典。以上分别表示获取(对象[‘xxx’])、设置(对象[‘xxx’] = xxx)、删除数据(del 对象[‘xxx’])
with 管理上下文
新的方法:Python引⼊了 with 语句来自动帮我们调用 close() ⽅法
上下文管理器:
__enter__
上文方法
__exit__
下文方法
以 with open 来说,打开文件在上文,关闭文件在下文(上下⽂管理器本质就是能够⽀持with操作)
==========================自定义一个满足上下文管理的类========================
class MyFile(object):
# 接收参数并初始化
def __init__(self, file_name, file_model):
# 保存文件名和文件打开模式,到实例属性中
self.file_name = file_name
self.file_model = file_model
# 上文方法
def __enter__(self):
print("进入上文.....")
# 1.打开文件 2.返回打开的文件资源
self.file = open(self.file_name,self.file_model)
return self.file
# 下文方法
def __exit__(self, exc_type, exc_val, exc_tb):
print("进入下文......")
# 关闭文件资源
self.file.close()
if __name__ == '__main__':
with MyFile("hello.txt", "r") as file:
file_data = file.read() # 无需显示的调用close方法,由系统自动东去调用
print(file_data)
with open("hello.txt", "r") as f:
f_data = f.read()
print(f_data)
# 输出
# 进入上文.....
# hello,python2020!
# 进入下文......
# hello,python2020!
==========================使用装饰器实现with上下文管理========================
from contextlib import contextmanager
@contextmanager
def myopen(file_name, file_model):
print("进入上文")
# 打开文件
file = open(file_name, file_model)
# 返回资源
yield file
print("进入下文")
# 下文 关闭资源
file.close()
with myopen("hello.txt", "r") as file:
file_data = file.read()
print(file_data) # 如果没有装饰器,报错:AttributeError: __enter__
# 输出
# 进入上文
# hello,python2020!
# 进入下文
总结:
- Python 提供了 with 语法⽤于简化资源操作的后续清除操作,实现原理建⽴在上下⽂管理器协议 (实现__enter__和__exit__)之上
- with使⽤代码中如果在打开过程中发⽣异常,需要使⽤try-except进⾏捕获
- Python 还提供了⼀个 contextmanager 装饰器,更进⼀步简化上下管理器的实现⽅式。
miniweb 框架
动静分离效果:
实现方案一: 通过普通的if elif else 来判断是哪一个请求文件,然后对应相应的响应
实现方案二: 如果条件分支很多显得代码杂乱,因此使用路由列表(Django) 将请求文件和对应的响应 封装在一个字典中,每个对应的响应封装为不同的方法
路由概念 这是web后台程序⾮常重要的⼀个特点.路由根据⽤户的请求,选择对应的函数来处理相应 的请求
实现方案三: 路由装饰器(Flask),使⽤装饰器⼯⼚函数接收路径参数并把路径添加到字典中,进⽽实现装饰器路由
# 定义若干函数,实现不同的功能
import time
from miniweb.application import urls
# 装饰工厂
# path 想装饰器内部传递的参数
def route(path):
# 装饰器
# 字典 {"/index.py":index函数引用}
def function_out(func):
urls.route_dict[path] = func
print("装饰 [%s]" % path)
def function_in():
return func()
return function_in
return function_out
#@route("/index.py")
# 1.route("/index.py") ----> function_out 引用
# 2.@function_out
# index = function_out(index)
# index() -----> funciton_in
@route("/index.py")
def index():
return "This is index show!---it is me"
@route("/center.py")
def center():
return "This is center show!----"
@route("/gettime.py")
def gettime():
return "This is gettime show! %s" % time.ctime()
必须在主模块中导入这个模块,这样装饰模块函数被加载,加载的同时被装饰(就会向字典中添加路由信息)