目录:

  1. 三层架构

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

  2. 异常

三层架构

什么是三层架构
  用户视图层:
    主要是用来和用户进行交互的,对于用户的数据进行一些简单的逻辑判断之后交给业务逻辑层进行处理。
  业务逻辑层:
    通过对数据的访问来对视图层传递过来的数据进行判断。
  数据访问层:
    专门用来对数据进行存储和读取。
为什么要用三层架构
  一个项目的本质其实就是将用户交互产生的数据存储到硬盘或者读取硬盘的数据的一个过程,但是如果我们把用户交互的过程和数据
读取的过程都写到一块的话,代码的可读性非常差,而且也不容易进行管理,程序之间的耦合性较高,为了解决这样的问题,我们牵引出
了业务逻辑层作为用户交互的数据存取的中间层,也就是接口层,这样降低了程序之间的代码耦合,而且提高了程序的可读性。
怎么使用三层架构

 

案例分享: 学生管理系统中以管理员登录和注册为例说明三层架构究竟是怎么一步一步往下面走的

第31天三层架构,异常 Python 第1张

start.py代码:

第31天三层架构,异常 Python 第2张
import os
import sys
from core import main

BASE_DIR = os.path.normpath(os.path.join(
    __file__,
    os.pardir,
    os.pardir
))

sys.path.append(BASE_DIR)

if __name__ == '__main__':
    main.run()
start.py

去调用core下面main的run函数

第31天三层架构,异常 Python 第4张
from interface import common_interface
from core import admin, student, teacher


def init():
    """初始化函数"""
    pass


def run():
    """系统入口函数"""
    init()
    sys_welcome_info = 'COURSE SELECTION SYSTEM'
    sys_func = """1.管理员操作界面\n2.学员操作界面\n3.讲师操作界面"""
    sys_func_dict = {
        '1': admin.admin_view,
        '2': student.student_view,
        '3': teacher.teacher_view
    }
    common_interface.sys_func_inter(sys_welcome_info, sys_func, sys_func_dict)
main.py

以管理员的注册和登录,在admin.py中只是对用户输入的数据进行了一些简单的处理之后就交给了interface接口:

第31天三层架构,异常 Python 第6张
from functools import wraps
import re
from interface import common_interface, admin_interface


def login_auth(func):
    @wraps(func)
    def inner(*args, **kwargs):
        if not common_interface.admin_status:
            login()
            if common_interface.admin_status:
                return func(*args, **kwargs)
            else:
                print('管理员未登录成功')
        else:
            return func(*args, **kwargs)

    return inner


def register():
    """注册"""
    temp = ''
    while True:
        name = input(temp + '输入管理员的名字(Q退出)>>').strip()
        if name.upper() == 'Q':
            return
        pwd1 = input('请输入管理员的密码>>').strip()
        pwd2 = input('请确认您的密码>>').strip()
        if name and pwd1 and pwd2:
            if pwd1 == pwd2:
                msg, state = admin_interface.register(name, pwd1)
                if state:
                    return common_interface.logger('admin', msg)
                else:
                    print(msg)
            else:
                print('两次密码不一致')
        else:
            print('输入不能为空')
        temp = '请重新'


def login():
    """登录"""
    temp = ''
    while True:
        name = input(temp + '输入用户名(Q退出)>>').strip()
        if name.upper() == 'Q':
            return
        pwd = input('请输入密码>>').strip()
        if name and pwd:
            msg, state = admin_interface.login(name, pwd)
            if state:
                common_interface.admin_status = state
                return common_interface.logger('admin', msg)
            else:
                print(msg)
        else:
            print('用户名和密码不能为空')
        temp = '请重新'
def admin_view():
    """管理员系统接口"""
    sys_welcome_info = 'ADMIN OPERATE SYSTEM'
    sys_func = """1.注册\n2.登录\n3.创建校区\n4.创建课程\n5.创建班级\n6.创建讲师"""
    sys_func_dict = {
        '1': register,
        '2': login,
        '3': create_campus,
        '4': create_course,
        '5': create_grade,
        '6': create_teacher
    }
    common_interface.sys_func_inter(sys_welcome_info, sys_func, sys_func_dict)
admin.py

interface接口下的admin_interface.py对注册和登录进行了一系列的处理之后去调用db去真正的处理数据

第31天三层架构,异常 Python 第8张
from db import models


def register(name, pwd):
    """注册

    name: 管理员名字 pwd:管理员密码,如果注册成功返回(msg,True),如果失败(msg, False)
    """
    admin_obj = models.Admin.get_obj_from_name(name)
    if admin_obj:
        return 'admin is exists', False
    else:
        models.Admin(name, pwd)
        return 'create %s successful' % name, True


def login(name, pwd):
    """登录

    name: 管理员名字 pwd:管理员密码,如果注册成功返回(msg,对象),如果失败(msg, False)
    """
    admin_obj = models.Admin.get_obj_from_name(name)
    if admin_obj:
        if admin_obj.pwd == pwd:
            return 'admin %s login successfully' % name, admin_obj
        else:
            return 'password is wrong !', False
    else:
        return 'admin is not exists', False
admin_interface.py

去调用db下的models,其实就是调用了类,但是类中的方法都是通过DBhandlers去实现的,因此有调用了DBhandlers下面的方法去实现

第31天三层架构,异常 Python 第10张
from db import DBhandler


class BaseClass:
    """这是一个基类,用来存放一些公共的方法和属性"""

    @classmethod
    def tell_info(cls):
        """查看当前类中的所有对象,

        将结果封装到一个列表中返回回去,如果没有对象,则返回空列表
        """
        return DBhandler.tell_info(cls)

    @classmethod
    def get_obj_from_name(cls, name):
        """根据名字查看是否有这个对象,如果存在则返回对象本身,不存在则返回None"""
        return DBhandler.get_obj_from_name(cls, name)

    @classmethod
    def save(cls, obj):
        """将传入的对象存储到文件中"""
        DBhandler.save(cls, obj)

class Admin(BaseClass):
    """管理员类

    会创建一个不同的文件分别来存储我们的管理员信息
    """

    def __init__(self, name, pwd):
        self.name = name
        self.pwd = pwd
        self.save(self)
models.py 第31天三层架构,异常 Python 第12张
import os
import pickle
from conf import settings


def save(cls, obj):
    """将对象存储到文件中

    cls:类对象,为了拼接路径用的,obj: 实际要存储的对象
    """
    obj_dir = os.path.join(settings.DB_DIR, cls.__name__)
    if not os.path.exists(obj_dir):
        os.mkdir(obj_dir)
    file_path = os.path.join(obj_dir, obj.name)
    with open(file_path, 'wb') as f:
        pickle.dump(obj, f)


def get_obj_from_name(cls, name):
    """根据名字获得对象

    cls:类本身,name: 传入的名称,此方法依然不适用于课程或者班级
    """
    file_path = os.path.join(settings.DB_DIR, cls.__name__, name)
    if os.path.exists(file_path):
        with open(file_path, 'rb') as f:
            return pickle.load(f)


def tell_info(cls):
    """查看当前类创建的所有对象

    cls: 类对象,此方法是根据在db目录下是否存在相应的文件来查看是否有对象的,因此对于课程或者班级
    这种并没有存储到文件中的类来讲是查看不到的,如果查看不到的会返回一个空的列表,所以不要用用课程或
    班级类来调用此方法
    """
    temp = []
    obj_dir = os.path.join(settings.DB_DIR, cls.__name__)
    if os.path.exists(obj_dir):
        for file_name in os.listdir(obj_dir):
            file_path = os.path.join(obj_dir, file_name)
            with open(file_path, 'rb') as f:
                temp.append(pickle.load(f))
    return temp
DBHandler.py

公共的代码库有:common_interface.py

第31天三层架构,异常 Python 第14张
import logging.config
from conf import log_config

admin_status = None
student_status = None
teacher_status = None


def sys_func_inter(sys_welcome_info, sys_func, sys_func_dict):
    """系统的功能接口函数

    sys_welcome_info: 系统功能分割信息
    sys_func: 系统的功能信息
    sys_func_dict: 系统的功能字典
    """
    temp = ''
    while True:
        print(sys_welcome_info.center(50, '*'))
        print(sys_func)
        print(sys_welcome_info.center(50, '*'))
        choice = input(temp + '输入你要选择的功能(Q退出)>>').strip()
        if choice.upper() == 'Q':
            return
        if choice not in sys_func_dict:
            print("输入有误")
            temp = '请重新'
            continue
        sys_func_dict[choice]()


def my_logger(name='admin'):
    """通过读取配置文件获得一个自己的日志生成器

    name:可以是三个值,student代表的是学生对象的日志生成器,teacher代表的是讲师对象的日志生成器,admin代表的是管理员的日志生成器
    默认的是管理员的生成器
    """
    logging.config.dictConfig(config=log_config.LOGGING_DIC)
    return logging.getLogger(name)


def logger(name, msg):
    """更高层次的一层封装"""
    log = my_logger(name)
    log.debug(msg)
common_interface.py

结论:

三层架构就像是套娃一样,一层一层的往下面走,每一层都是一个专门用来负责某一项事物的,主要解决了程序之间耦合性的问题。

异常

什么是异常
  异常就是程序发生错误时的一种信号,如果不进行处理,程序就会终止。最直观的显示就是程序运行的时候报错了。
异常分类
  1. 语法异常
    是最基本的异常,也是作为程序员最不应该出现的异常,这种异常一般在程序执行运行之前就会抛出,近而解决就是了。
  2. 逻辑上的异常
    逻辑上的异常是在程序运行的时候出现的异常,我们可以通过关键字try进行捕获。
异常组成 异常类型 异常捕获
  try:
    代码块
  except:
    代码块
主动抛出异常: raise
  raise 异常类型("异常信息")
断言: assert
  assert 条件表达式返回一个布尔值 自定义异常

 异常的组成

第31天三层架构,异常 Python 第16张

异常的类型

常见的异常:
异常类型一: SyntaxError: 语法错误 异常类型二: NameError: 名字没有定义 x IndexError: 索引超出范围 l
= [] l[3] KeyError: key不存在 d = {'a': 1} d['b'] AttributeError: 对象没有这个属性 l = [] l.sljg TypeError: 类型错误,一般是类型不是可迭代的 for i in 123: ValueError: 传入一个调用者不期望的值,即使值的类型是正确的 int('sjeg') ZeroDivisionError: 除数不能是0 KeyboardInterrupt: Ctrl+C被按下(win平台可以在终端中试一下) IndentationError: 语法错误(的子类) ;代码没有正确对齐 FileNotFoundError: 文件名字找不到 f = open('这是不存在的文件名', 'rt', encoding='utf-8') ModuleNotFoundError: 模块找不到 import 不存在的模块
第31天三层架构,异常 Python 第17张
ArithmeticError
AssertionError
AttributeError
BaseException
BufferError
BytesWarning
DeprecationWarning
EnvironmentError
EOFError
Exception
FloatingPointError
FutureWarning
GeneratorExit
ImportError
ImportWarning
IndentationError
IndexError
IOError
KeyboardInterrupt
KeyError
LookupError
MemoryError
NameError
NotImplementedError
OSError
OverflowError
PendingDeprecationWarning
ReferenceError
RuntimeError
RuntimeWarning
StandardError
StopIteration
SyntaxError
SyntaxWarning
SystemError
SystemExit
TabError
TypeError
UnboundLocalError
UnicodeDecodeError
UnicodeEncodeError
UnicodeError
UnicodeTranslateError
UnicodeWarning
UserWarning
ValueError
Warning
ZeroDivisionError
更多异常

捕获异常的六种不同的格式

格式一:

try:
    # try后面缩进的代码块是我们正常的代码(也就是可能出现错误的代码)
    l = [1, 2, 3]
    print(l[4])
# except 代表的意思是如果try中的代码块中出现了IndexError类型的异常,就会执行except下的代码块
except IndexError:
    print('索引错误了')

# 运行结果:
# 索引错误了

格式二:

try:
    a   # 当运行到这一行的时候会发生异常然后被捕捉执行NameError的代码
    l = [1, 2, 3]
    print(l[4])
except IndexError:
    print('索引错误了')
except NameError:
    print('变量没有定义')

# 运行结果:
# 变量没有定义
第31天三层架构,异常 Python 第19张
try:
    a   # 当运行到这一行的时候会发生异常然后被捕捉然后执行except语句
    l = [1, 2, 3]
    print(l[4])
except (IndexError, NameError):
    print('程序发生了未知错误')

# 运行结果:
# 程序发生了未知错误
方式二的变形

格式三: 万能捕捉语句

try:
    a   # 当运行到这一行的时候会发生异常然后被捕捉然后执行except语句
    l = [1, 2, 3]
    print(l[4])
except Exception:
    print('上面不管发生什么异常,我都能够捕捉(语法错误除外)')

# 运行结果:
# 上面不管发生什么异常,我都能够捕捉(语法错误除外)

格式四: except  NameError  as  n  

try:
    a   # 当运行到这一行的时候会发生异常然后被捕捉然后执行except语句
    l = [1, 2, 3]
    print(l[4])
# as后面的e就是上面产生异常类型的一个对象
# 异常类型其实通过__str__将输出的结果进行了格式化
# 因此当我们打印e的时候会显示异常的信息
except Exception as e:
    print(e)

# 运行结果:
# name 'a' is not defined

格式五: try........else....... 必须和except结合使用

try:
    a
    l = [1, 2, 3]
    print(l[4])
except Exception as e:
    print(e)
else:
    print('当try里面的代码块没有异常,也就是正常执行完毕之后才会执行我这里的代码'
          '如果有异常,还是执行except下面的代码')
# 运行结果:
# name 'a' is not defined

格式六: try ...... finally .......可以不except结合使用,一般用来回收系统资源

try:
    a
    l = [1, 2, 3]
    print(l[4])
except IndexError as e:
    print(e)
else:
    print('当try里面的代码块没有异常,也就是正常执行完毕之后才会执行我这里的代码'
          '如果有异常,还是执行except下面的代码')
finally:
    print('无论上面的代码是怎么执行的,都要执行我这里的代码,就算是异常没有被'
          '捕捉到也要执行我这里的代码')
# 运行结果:
# Traceback (most recent call last):
# 无论上面的代码是怎么执行的,都要执行我这里的代码,就算是异常没有被捕捉到也要执行我这里的代码
#   File "H:/python_study/day31/测试.py", line 232, in <module>
#     a
# NameError: name 'a' is not defined
第31天三层架构,异常 Python 第21张
try:
    f = open('xxx', 'wt', encoding='utf-8')
    # 当此时出现异常之后,没有被捕捉到,所以程序终止,但是当前f打开的系统资源还没
    # 有被回收掉,所以我们可以通过finally去回收当前系统中还没有被回收的资源
    f.read()   
    f.close()
except NameError:
    pass
finally:
    f.close()
回收系统资源示例

主动抛出异常

为什么要主动抛出异常
  当程序中有一些限制,但是用户没有遵守的时候,我们就可以主动的抛出异常

主动抛出异常的方式有两种
  raise: 优点: 可以自定义异常的信息 缺点:麻烦
  assert:缺点: 不能自定义异常的信息 优点: 简单

raise

class User:
    def __init__(self, name):
        if not isinstance(name, str):
            # 当用户输入的内容不是字符串的时候,我就会主动的抛出异常
            raise TypeError('用户名必须是字符串')
        print('输入的用户名是字符串,我可以执行下面的代码了')
        print('part.....')

User(123)

assert 可以把上面的代码通过assert进行简化

class User:
    def __init__(self, name):
        assert isinstance(name, str)  # 就是不能写异常信息
        print('输入的用户名是字符串,我可以执行下面的代码了')
        print('part.....')

User(123)

 自定义异常

为什么要自定义异常
  当系统提供的这些异常类型和你要描述的错误不匹配的时候,我们就需要自定义异常类型了。
class RegisterError(BaseException):
    def __init__(self, msg, name):
        self.name = name
        self.msg = msg

    def __str__(self):
        return '<%s: %s>' % (self.msg, self.name)

raise RegisterError('必须是字符串', 'teacher')

结论:

当异常发生的条件能够明确的写出一个条件的时候,我们就应该用if判断语句来代替异常处理。

 

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄