python之super + property +魔法属性+with+miniweb框架

单继承中的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__

注意:

  1. 以上2个代码执⾏的结果不同
  2. 如果2个⼦类中都继承了⽗类,当在⼦类中通过⽗类名调⽤时,parent被执⾏了2次
  3. 如果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__)

魔法属性和方法

魔法属性

  1. __doc__表示类的描述信息
    获取类的 类名.__doc__
    获取方法的描述 对象.方法名.__doc__
  2. __module__ 表示当前操作的对象在哪个模块(对象名.__module__),直接运行.py文件,获得__main__
  3. __class__ 获取对象所属的类 (对象名.__class__) # <class ‘main.Good’>
  4. __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里面初始化的内容,返回也是字典

魔法方法

  1. __init__ 初始化⽅法,通过类创建对象时,即:对象 = 类名()⾃动触发执⾏
  2. __del__ 删除对象的时候,会调用del对象(当对象在内存中被释放时,⾃动触发执⾏)
    注: 此⽅法⼀般⽆须定义,因为Python是⼀⻔⾼级语⾔,程序员在使⽤时⽆需关⼼内存的分配和释放,因为此⼯作都是交给Python解释器来执⾏,所以,__del__的调⽤是由解释器在进⾏垃圾回收时⾃ 动触发执⾏的。
  3. __call__ 对象后⾯加括号,触发执⾏,即对象()
  4. __str__ 如果⼀个类中定义了__str__⽅法(一定要返回字符串内容),那么在打印 对象 时,默认输出该⽅法的返回值。 如:goods = Goods() print(goods)
  5. __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!
# 进入下文

总结:

  1. Python 提供了 with 语法⽤于简化资源操作的后续清除操作,实现原理建⽴在上下⽂管理器协议 (实现__enter__和__exit__)之上
  2. with使⽤代码中如果在打开过程中发⽣异常,需要使⽤try-except进⾏捕获
  3. 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()

必须在主模块中导入这个模块,这样装饰模块函数被加载,加载的同时被装饰(就会向字典中添加路由信息)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值