分享

【Python之路】特别篇

 highoo 2019-03-20

一、预备知识:

1、接口:

  - URL形式  

  - 数据类型 (Python中不存在)

 

a.类中的方法可以写任意个,想要对类中的方法进行约束就可以使用接口;

b.定义一个接口,接口中定义一个方法f1;

c.只要继承(实现)了接口,那么类就会受约束,该类必须要有f1方法!

d.接口只用来做约束,不需要写具体功能。

由于python中无接口类型,但是可以人为构造,抛出异常!

raise Exception('子类中必须实现该方法')

demo

 

类:类中的方法可以写功能,也可以不写功能,

抽象类:类和接口的集合,抽象类中可以有抽象方法和普通方法,

          子类继承抽象类时,必须实现抽象方法!

           抽象类即做了约束,还有具体功能

python提供了模块abc,用于实现抽象类和抽象方法的功能

demo

 


 

耦合:

不同模块之间互连程度的度量(耦合性也叫块间联系)。指软件系统中各模块间相互联系紧密程度的一种度量。模块之间联系越紧密,其耦合性就越强,模块的独立性则越差。

强耦合demo

为了降低耦合,一般可以这样做:

demo

如果SqlHelper和其他类,如Foo类有依赖关系那么又要解耦了:

demo

最终发现代码,嵌套太多层了。

为了解决这种问题,可以使用依赖注入!

提案:实例化的时候,不需要自己传参数

 


 

面向对象知识点:

1
2
3
4
5
6
class Foo:
    def __init__(self,name):
        self.name = name
    def f1(self):
        print(self.name)

# 解释器解释的时候:

1.遇到 class Foo , 执行type 的__init__方法

2.Typr的init方法里做什么呢? => 创建了类

obj = Foo(123)

3.执行Type的__call__方法,

      -> 执行Foo类的__new__方法

      -> 执行Foo类的__init__方法

 

如何在执行__init__方法前,传递参数呢?

可以选择去重写Type的__call__方法

你写的任何类都是Type的对象,

1
2
3
4
5
6
7
8
9
10
class MyType(type):
    def __call__(self, *args, **kwargs):
        print(self)
class Foo(metaclass=MyType):      # 指定由MyType生成
    def __init__(self,name):
        self.name = name
obj = Foo(123)
# <class '__main__.Foo'>

最终执行流程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyType(type):
  
    def __call__(cls, *args, **kwargs):
        obj = cls.__new__(cls,*args, **kwargs)  # 创建对象
        obj.__init__(*args, **kwargs)      # 初始化
        return obj
  
class Foo(metaclass=MyType):
    def __init__(self,name):
        self.name = name
  
    def f1(self):
        print(self.name)
  
obj = Foo(123)

为了在调用时不传参数,设法在obj.__init__()执行前时,传入参数

1
2
3
4
5
6
7
8
9
10
class MyType(type):
    def __call__(cls, *args, **kwargs):
        obj = cls.__new__(cls,*args, **kwargs)
        args_list = list(args)
        args_list.append(123)
        obj.__init__(*args_list, **kwargs)
        return obj
obj = Foo()

为了不让参数固定,做进一步修改,利用第三方来传递参数!

依赖注入:

demo

有了依赖注入后,之前嵌套过多的demo可以修改为:

View Code

 

1.总体框架目录结构:

备注:

  • Infrastructure:一些公共组件,例如md5加密,分页模块,session等。
  • Model :关于数据库的逻辑处理模块
  • Repository :数据访问层,包含数据库的增删改查
  • Service :服务层,调用Model,包含带有规则的请求和返回
  • Statics:静态文件目录
  • UI层:业务处理
  • Views:模板文件
  • Application:tornado程序的起始文件
  • Config:配置文件
  • Mapper:依赖注入文件,负责整个框架不同类的依赖注入

2.首先我们从Moldel开始查看:

本文主要以用户管理为例进行介绍,因此我们来关注一下User.py文件:

代码结构:

下面对上述代码结构做一一介绍:

IUseRepository类:接口类,用于约束数据库访问类的方法
示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class IUseRepository:
    """
    用户信息仓库接口
    """
  
    def fetch_one_by_user_pwd(self, username, password):
        """
        根据用户名密码获取模型对象
        :param username: 主键ID
        :param password: 主键ID
        :return:
        """
    def fetch_one_by_email_pwd(self, email, password):
        """
        根据邮箱密码获取模型对象
        :param email: 主键ID
        :param password: 主键ID
        :return:
        """
  
    def update_last_login_by_nid(self,nid,current_date):
        """
        根据ID更新最新登陆时间
        :param nid:
        :return:
        """

  从上述代码可以看出,数据库访问类如果继承IUseRepository类,就必须实现其中的抽象方法。

接下来的三个类,VipType、UserType、User是与用户信息相关的类,是数据库需要保存的数据,

我们希望存入数据库的数据格式为:nid 、username、email、last_login、user_type_id、vip_type_id,其中User类用于保存上述数据。

因为user_type_id、vip_type_id存的是数字,即user_type_id、vip_type_id是外键,不能直接在前端进行展示,

因此,我们创建了VipType、UserType类,用于根据id,获取对应的VIP级别和用户类型。

User类
UserType类
VipType类

注:VipType、UserType这两个类获取对应的caption均是通过类的普通特性访问,即类似字段方式访问。

接下来的类UserService是本py文件的重中之重,它负责调用对应的数据库访问类的方法,并被服务层service调用,具有承上启下的作用:

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class UserService:
  
    def __init__(self, user_repository):
        self.userRepository = user_repository
  
    def check_login(self, username=None, email=None, password=None):
  
        if username:
            user_model = self.userRepository.fetch_one_by_user_pwd(username, password)
        else:
            user_model = self.userRepository.fetch_one_by_email_pwd(email, password)
        if user_model:
            current_date = datetime.datetime.now()
            self.userRepository.update_last_login_by_nid(user_model.nid, current_date)
        return user_model

  这里,我们重点介绍一下上述代码:

初始化参数user_repository:通过依赖注入对应的数据库访问类的对象;

check_login:访问数据库的关键逻辑处理方法,根据用户是用户名+密码方式还是邮箱加密码的方式登录,然后调用对应的数据库处理方法,如果登陆成功,更新时间和最后登录时间,最后将User类的实例返回给调用它的服务层service。(详细见下文数据库处理类的方法)

我们先来看一下对应的数据库处理类中的一个方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def fetch_one_by_user_pwd(self, username, password):
       ret = None
       cursor = self.db_conn.connect()
       sql = """select nid,username,email,last_login,vip,user_type from UserInfo where username=%s and password=%s"""
       cursor.execute(sql, (username, password))
       db_result = cursor.fetchone()
       self.db_conn.close()
  
       if db_result:
           ret = User(nid=db_result['nid'],
                      username=db_result['username'],
                      email=db_result['email'],
                      last_login=db_result['last_login'],
                      user_type=UserType(nid=db_result['user_type']),
                      vip_type=VipType(nid=db_result['vip'])
                      )
       return ret

  这里我们使用pymysql进行数据库操作,以用户名+密码登陆为例,如果数据库有对应的用户名和密码,将查询结果放在User类中进行初始化,至此,ret中封装了用户的全部基本信息,将ret返回给上面的check_login方法,即对应上文中的返回值user_model,user_model返回给调用它的服务层service。

总结:Molde最终将封装了用户基本信息的User类的实例返回给服务层service。

3.接下来我们看一下服务层service:

service也是一个承上启下的作用,它调用Moldel文件对应的数据库业务协调方法,并被对应的UI层调用(本例中是UIadmin)。

目录结构:

同样的,我们只介绍User文件夹:它包含4个py文件:

  • ModelView:用于用户前端展示的数据格式化,重点对user_type_id、vip_type_id增加对应的用户类型和VIP级别,即将外键数据对应的caption放在外键后面,作为增加的参数。
  • Request:封装请求Moldel文件对应数据库协调类的参数
  • Response:封装需要返回UI层的参数
  • Sevice:核心服务处理文件

下面对上述目录做详细代码:

ModelView:

1
2
3
4
5
6
7
8
9
10
11
class UserModelView:
  
    def __init__(self, nid, username, email, last_login, user_type_id, user_type_caption, vip_type_id, vip_type_caption):
        self.nid = nid
        self.username = username
        self.email = email
        self.last_login = last_login
        self.user_type = user_type_id
        self.user_type_caption = user_type_caption
        self.vip_type = vip_type_id
        self.vip_type_caption = vip_type_caption

  注:对user_type_id、vip_type_id增加对应的用户类型和VIP级别,即将外键数据对应的caption放在外键后面,作为增加的参数。

Request:

1
2
3
4
5
6
class UserRequest:
  
    def __init__(self, username, email, password):
        self.username = username
        self.email = email
        self.password = password

Response:

1
2
3
4
5
6
class UserResponse:
  
    def __init__(self, status=True, message='', model_view=None):
        self.status = status    # 是否登陆成功的状态
        self.message = message  #错误信息
        self.modelView = model_view  #登陆成功后的用户数据 

UserService:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class UserService:
  
    def __init__(self, model_user_service):   #通过依赖注入Moldel对应的数据库业务协调方法,此例中对应上文中的user_service
        self.modelUserService = model_user_service 
  
    def check_login(self, user_request):  #核心服务层业务处理方法
        response = UserResponse()  #实例化返回类
  
        try:
            model = self.modelUserService.check_login(user_request.username, user_request.email, user_request.password) #接收上文中的用户基本信息,是User类的实例
            if not model:
                raise Exception('用户名或密码错误')
            else:   #如果登陆成功,通过UserModelView类格式化返回前端的数据
                model_view = UserModelView(nid=model['nid'],
                                           username=model['usename'],
                                           email=model['email'],
                                           last_login=model['last_login'],
                                           user_type_id=model['user_type'].nid,
                                           user_type_caption=model['user_type'].caption,
                                           vip_type_id=model['vip_type'].nid,
                                           vip_type_caption=model['vip_type'].caption,)
                response.modelView = model_view    #定义返回UI层的用户信息
        except Exception as e:
            response.status = False
            response.message = str(e)

  总结:至此,Service返回给Ui层的数据是是否登陆成功的状态status、错误信息、已经格式化的用户基本信息。

4.UI层

UI层主要负责业务处理完成后与前端的交互,它是服务层Service的调用者:

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Login(AdminRequestHandler):
  
    def get(self, *args, **kwargs):
        is_login=self.session["is_login"]
        current_user=""
        if is_login:
            current_user=self.session["user_info"].username
        self.render('Account/Login.html',current_user=current_user)
  
    def post(self, *args, **kwargs):
        user_request=[]
        #获取用户输入的用户名邮箱密码
        user_request.append(self.get_argument('name',None))
        user_request.append(self.get_argument('email',None))
        user_request.append(self.get_argument('pwd',None))
        checkcode=self.get_argument("checkcode",None)
        Mapper.mapper(*user_request)
        obj=UserService.check_login()
        self.session["is_login"]=True
        self.session["user_info"]=obj.modelView
        self.write("已登陆")

  

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约