python面试

celery

什么是celery?

        celery是一个简单,方便,即插即用的处理异步任务和定时任务的分布式异步任务队列框架

celery特点?

        简单,易于使用和维护,有丰富的文档

        高效,支持多线程、多进程、协程模式运行,单个celery进程每分钟可以处理数百万个任务

        灵活,celery中几乎每个部分都可以自动义扩展

celery作用?

        应用解耦,异步处理,流量消峰,消息通讯

celery的运行架构?

        celery分为3部分,消息队列(message queue)、任务执行单元(worker)、任务执行结果存储(task result store)组成

为什么选择celery?

        简单,易于使用和维护,有丰富的文档

        高效,支持多线程、多进程、协程模式运行,单个celery进程每分钟可以处理数百万个任务

        灵活,celery中几乎每个部分都可以自动义扩展

        成熟,开发比较简单

celery在项目中应用?

        登录、注册 : 发送短信验证码

        外卖项目 : 简单说一下

队列和列表区别

        队列(Queue) :from queue import Queue  方法 get在队列中取数据  put 向队列塞数据   一般先进先出, 数据安全,多线程取一个数据,不会取重复

        队列(加锁的作用) :可以保护数据,高并发时,防止系统崩溃

        多个线程之间基于队列的中间介质进行沟通

消息队列

如何保证消息不丢失?

        看一下redis和专业消息队列对比

如何保证消息队列中的消息没有被重复消费

        

        

消息队列如何保证数据的可靠性和安全性

        

        

数据库(Redis+Mysql+pg)

Redis

     

Redis 数据库,内容是以何种结构存放在redis中?

        String(字符串),Hash(哈希),List(列表),Set(无序集合),Zset(有序集合)

Redis 和MongoDB的优缺点

        MongoDB 和 Redis都是NoSql数据库,采用的存储结构是key-value。使用场景存在一定差别,主要是由于二者在内存映射的处理过程,持久化的处理方法不同。MongoDB建议集群部署,更多的考虑到集群方案。Redis更偏重于进程顺序写入,虽然支持集群,也仅限于主-从模式

   Redis优点

        1)读写性能优异

        2) 支持数据持久化,支持AOF RDB 两种持久化方式

        3)支持主从复制,主机会自动将数据同步到从机,可以进行读写分离

        4)数据结构丰富:支持string、hash、list、set、zset等数据结构

   Redis缺点

        Redis 不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复。

        主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性。

        Redis的主从复制采用全量复制,复制过程中主机会 fork 出一个子进程对内存做一份快照,并将子进程的内存快照保存为文件发送给从机,这一过程需要确保主机有足够的空余内存,若快照文件比较大,对集群的服务能力会产生较大的影响,而且复制过程是在从机新加入集群或者从机和主机网络断开重连时都会进行,也就是网络波动都会造成主机和从机间的一次全量的数据复制,这对实际的系统运营造成了不小的麻烦。

        Redis 较难支持在线扩容,在集群容量达到上限时在线扩容就会变得复杂。为避免这一问题,运维人员在系统上线时必须确保有足够的空间,这对资源造成了很大的浪费

MongoDB优点

        1、弱一致性(最终一致),更能保证用户的访问速度

        2、文档结构的存储方式,能够更便捷的获取数

        3、内置 GridFS,高效存储二进制大对象(比如照片和视频)

        4、支持复制集、主备、互为主备、自动分片等特性

        5、动态查询

        6、全索引支持,扩展到内部对象和内嵌数组

MongoDB缺点:

        1、不支持事务

        2、 MongoDB 占用空间过大

        3、维护工具不够成熟

Redis 的并发问题怎么解决?

        方案一 : 使用独占锁的方式,类似操作系统的 mutex 机制,不过实现复杂,成本高

        方案二 : 使用乐观锁的方式进行解决(成本低,非阻塞,性能较高)

如何使用乐观锁方式进行解决?

        本质上是假设不会进行冲突,使用 redis 的命令 watch 进行构造条件

redis中list底层实现有哪几种?有什么区别?

        列表对象的编码可以是 ziplist 或者 linked list(链表)

        ziplist 是一种压缩链表,他的好处是节约内存空间,因为它存储的内容都是在连续的内存区域当中,当列表对象元素不大,就可以采用ziplist存储。数据量大的时候,ziplist不好用,因为为了保证存储内容在内存中的连续性,插入的复杂度是 O(N),即每次插入都会重新进行ralloc

Redis使用类型和场景

        字符串string : 保存 session

        哈希hash : 购物车   用户id : 物品名称 : 数量

        列表List : 消息队列

        有序集合zset : 热搜排行

        无序集合set : 候选人名单

Redis 持久化处理

          1.  RDB 快照 -->   将当前数据的快照存成一个数据文件的持久化机制

                RDB不足 : 一旦数据库出现问题,那么RDB文件中保存的数据并不是最新的

          2. AOF 日志  --->  AOF文件时可识别的纯文本,他的内容就是一个个Redis标准命令

Redis缓存雪崩,解决办法

    缓存雪崩

        -- 雪崩指的是 缓存中大批量 '热点数据过期' 后, 系统涌入大量查询请求,请求渗透到数据库层,引起数据库压力过大,造成查询阻塞甚至宕机 

    解决办法

        -- 1.  将缓存的热点数据过期时间分散一些,避免同一时间都过期

        -- 2. 如果是分布式部署,可以采用多节点缓存,这样不同节点负责不同数据

        -- 3. 条件允许,设置键永不过期

    缓存雪崩的事前事中事后的解决方案

        事前 : redis高可用,主从+哨兵, redis cluster 避免全盘崩盘

        事中 : encache 缓存 + hystrix限流和降级,避免Mysql被打死

        事后 : redis持久化,一旦重启,自动将磁盘数据加载,快速回复数据

缓存穿透和解决办法

        -- 缓存穿透 : 当我们访问数据库数据,这个数据不在redis中,就一直访问,可能会打死数据库,如数据库id是从1开始,结果请求id全部是负数,这样缓存中就不会有,直接访问数据库层

        -- 解决办法 :当我们访问数据库中数据不存在,我们给他返回一个空值,并设置一个过期时间,这样下次同样请求,再缓存失效前,就会直接访问redis层,而不会直接访问数据库

缓存击穿和解决办法

        -- 缓存击穿 : 有一条热点数据涌入大量查询请求,处于集中式高并发,当redis缓存过期,大量请求直接访问数据库

        -- 解决办法 :

                可以设置热点数据永不过期。

                基于redis or zookeeper 实现互斥锁,等待第一个请求构建完缓存之后,在释放锁,进而其它请求才能通过该 key 访问数据

Redis主从复制

        -- 主从复制,是指将一台 Redis  服务器的数据,复制到其它的Redis服务器,前者称为 ‘主节点’(Master),后者称为‘从节点’(Slave)

        -- 数据的复制是‘单向’的,只能从主节点到从节点

        -- 一个主节点可以有多个从节点,但是一个从节点只能有一个主节点

   作用

        --  数据冗余

        -- 故障恢复   当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复

        -- 负载均衡 在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量

        -- 高可用基石  主从复制是哨兵和集群能够实施的基础

Redis哨兵     

        原理

            -- 哨兵是一个分布式系统,用于对主从结构中每台服务器进行监控,当出现故障时通过投票机制选择新的Master并将所有的Slave连接到新的Master,所以整个运行哨兵的集群的数量不得少于 3 个节点

        核心功能

           -- 在主从复制的基础上,哨兵引入了主节点的‘自动故障转移

        作用

            --  监控    哨兵会不断检查主节点和从节点是否运行正常

            -- 自动故障转移     当主节点不能正常工作时,哨兵会开始自动故障转移操作,会将失效的主节点的其中一个从节点升级为新的主节点,并让其他从节点改为复制新的主节点

        结构

            --  哨兵节点    哨兵系统由一个或多个哨兵节点组成,哨兵节点是特殊的redis节点,不存储数据

            --   数据节点   主节点和从节点都是数据节点

        注意

            -- 客观下线是主节点才有的概念,如果从节点和哨兵节点发生故障,被哨兵主观下线后,不会再有后续的客观下线和故障转移操作

Redis集群

        概念

            --   分布式存储方案,集群中的几点分为主节点和从节点

            --  只有主节点负责读写请求和集群信息维护,从节点只进行主节点数据和状态信息的复制

            --  集群一般需要 6 个节点,3主3从

        作用

            --  数据分区[核心功能]   集群将数据分散到多个节点,一方面突破了Redis单级内存大小的限制,存储容量大大增加,另一方面,每个主节点都可以对外提供读服务和写服务,大大提高了集群的响应能力

            --  高可用   集群支持主从复制和主节点的自动故障转移

        数据分片

           --  Redis集群引入了哈希槽的概念

           --  Redis集群有16384个哈希槽,每个主节点负责一部分哈希槽

           --  当某个主节点失败后,选举该主节点的某一个节点继续服务,当主从都失败后,集群将不可用

Redis高并发

        Redis 是基于内存的,内存读写速度非常快

        Redis 是单线程,省去上下文切换线程时间,在单线程情况下,不用考虑各种锁的问题,不存在释放锁操作。

        Redis 使用多路复用技术,可以处理并发连接

        Redis6.0之前是单线程运行的,Redis6.0以后开始支持多线程。

        Redis6.0使用单线程原因:

                1. 单线程模式方便开发和调试

                2. Redis内部使用了基于epoll的多路复用

                3. Redis主要得性能瓶颈是内存和网络带宽,并不是线程问题

数据库范式

        第一范式(确保每列保持原子性) : 字段值不可分割

        第二范式(确保表中的每列都和主键相关)

        第三范式(确保每列都和主键列直接相关,而不是间接相关)

        逆范式 : 空间换时间

Mysql、Redis、MongoDB区别

Mysql

MySQL常见数据库引擎及区别

        MyISAM     InnoDB    Merge   Memory  BDB

        MyISAM : MySQL默认搜索引擎,它是Web、数据仓储和其他应用环境最常用的存储引擎之一

        InnoDB : 用于事务处理应用程序,支持ACID,行级锁可实现高并发

        BDB : 可替代InnoDB的事务引擎,支持COMMIT, ROLLBACK和其他事务特性

        Merge : 允许MySQL DBA或开发人员将一系列等同的MyISAM表以逻辑方式组合在一起,并作为1个对象引用他们。对于诸如数据仓储等VLDB环境十分适合

数据库索引

        逻辑分类 :

                功能划分 : 主键索引、普通索引、唯一索引、全文索引

                列数划分 : 单列索引、组合索引

        物理分类:

                聚簇索引、非聚簇索引

最左前缀原则

        在MySQL建立联合索引时会遵守最左前缀匹配原则,即最左优先(查询条件精确匹配索引的左边连续一列或几列,则构建对应列的组合索引树),在检索数据时也从联合索引的最左边开始匹配。

        联合索引 : state/city/zipCode

        命中索引 :state/city/zipCode 、 state/city 、 state

        为命中索引 : state/zipCode  、 city 、city/zipCode

数据库苗卡尔

MySQL主从复制

        1. 主数据库(master)写入数据之后,会有data changes(数据变化)记录

        2.主数据库(master)有变化记录之后,将增删改的一些sql语句记录到本地的Binary log(二进制日志)中

        3. 从库(slave)会一直开启着一个线程

        4. 从库(slave)通过这个线程去读取主数据库(master)的Binary log (二进制日志)的内容

        5. 从库(slave)会将读取的数据写到自己的Relay log (中继日志)中

        6. 从库(slave)会将中继日志中的操作转化为SQL thread(SQL语句)

        7.从库(slave)通过转化的SQL语句写入到自己的数据库中,两边数据就一致了

        主从代码实现 ->> 见linux笔记

Django实现数据库读写分离

MySQL优化

        -- 构建索引
        -- 使用join来代替子查询
        -- 使用外键
        -- 避免使用 select * 
        -- 避免全表扫描
        -- 避免大事务操作
        -- 读写分离
        -- 常用数据放到缓存中

        -- 尽量减少模糊查询

        -- 少用范围查询

如何检测MySQL中建立的索引是否生效

        explain

MySQL慢查询处理方案

        sql及索引优化

        -- 数据库表结构,根据数据设计查询最优的表结构

        -- 系统配置优化,对于打开文件数和安全的限制

        -- 硬件, 选择最合适数据库的cpu,更快的IO,更大的内存

mysql事务的特性

MySQL主从搭建原理,以及如何监控

怎么解决数据库高并发的问题?

        1) 缓存式大的Web应用程序架构:

                在 Web层和DB(数据库)层之间加一层 cache 层,主要目的 : 减少数据库读取负担,提高数据读取速度。cache 存取的媒介是内存,可以考虑采用分布式的cache层,这样更容易破除内存容量的限制,同时增加了灵活性。

        2)增加 Redis 缓存数据库

        3)增加数据库索引

        4) 页面静态化:

                效率最高、消耗最小的就是纯静态化的 html 页面,所以尽可能使网站上的页面采用静态页面来实现,这是最简单有效的方法,用户可以直接获取页面,不用像MVC结构走那么多流程,比较适用页面信息大量被前台程序调用,但是更新频率很小的情况

        5)使用存储过程:

                处理一次请求需要多次访问数据库的操作,可以把操作整合到储存过程,这样只要访问一次数据库就可以了,感觉像是事物

MySQL修改一条数据的原理

        - 1. 执行器找引擎id为1的数据

        - 2. id为主键,通过B+树找到这一行数据,返回给执行器

        - 3. 执行器执行更新操作

        - 4. 执行器生成一条新的数据

        - 5. 调用InnoDB引擎的写入接口,把数据更新到内存中

        - 6. InnoDB引擎写入 redo log 日志,标记状态为 prepare,并且告诉执行器已经更新数据完成,可以随时提交事务

        - 7. 执行器把此操作写入 bin log , 并且把 bin log 写入磁盘

        - 8. 最后执行器调用引擎的提交事务接口,把 redo log 状态改为 commit

链表和数组的区别

        1. 数组静态分配内存,链表动态分配内存

        2. 数组在内存中连续,链表不连续

        3. 数组利用下标定位,时间复杂度为O(1),链表定位元素时间复杂度为O(n)

        4. 链表对于插入/删除数据更灵活

非对称加密和对称加密的区别

        对称加密 : 加密和解密的秘钥使用的是同一个

        非对称加密 : 与对称加密算法不同,非对称加密需要两个秘钥:公开密钥(publickey) 和 私有秘钥(privatekey)

MySQL锁及区别

        -- 全局锁  : 对整个数据库实例加锁

        -- 表级锁  :          

                        -- 表锁

                        -- 元数据锁

        -- 行锁 : 由引擎实现 [InnoDB]

        -- 间隙锁

        -- next-key lock

网络编程and并发编程

TCP与UDP的区别?

        面向有连接可靠的通信传输协议(先建立连接,再传输数据)

        可实现 “顺序控制”和“重发控制”的机制

        TCP连接需要3次握手,4次挥手,可靠性连接

        优点:数据传输可靠

        缺点 : 效率低

        应用 : 邮件  远程登录

        UDP协议 : 不可靠数据连接

        面向数据包(报文),不可靠,一次发送(不需要建立连接),我发给你,你接不接收到不管

        优点 : 传输效率高

        缺点 : 不可靠,容易丢包

        应用 : QQ聊天  在线视频等

TCP 三次握手四次挥手流程?

什么是进程,线程,协程,区别?

        进程广义 : 进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动

        进程狭义 :一个正在运行的应用程序在操作系统中被视为一个进程,资源管理单元,windows下 一个任务就是一个进程

                每一个进程都会有一个进程号

                进程是最小的资源管理单元

                一个程序至少有一个主进程和一个主线程

        进程状态:

                就绪 : 进程已经准备好,已分配到所需资源/内存

                执行/运行 : 进程处于就绪状态,被调度后,进程进入执行状态

                阻塞 : 正在执行的进程由于某些事件(I/O请求,input,申请缓存区失败)而暂时无法运行,进程受到阻塞,则进入就绪状态等待系统调用

                终止 : 进程结束,或出现错误,或被系统终止,今天终止状态,无法在执行

        针对阻塞状态 :  -->异步

                同步 : 调用一旦开始,必须等到调用方法返回后,才执行后续代码

                异步 : 遇到阻塞不会等待,会执行后续方法,一旦调用立即返回

        模块 : multiprocessing下的Process

        join : 防止孤儿进程 --> 主进程要等待子进程全部结束之后,主进程才可以结束  -->应用场景 抢票   查询余票

             缺点 :

                        1. 占用资源多

                        2. 切换时间长

             进程之间通信 :  

                        使用multiprocessing 模块中的Queue 类实现进程间通信

                        Pipe实现进程间通信,2个进程分别位于管道的两端,一端用来发送数据,一端用来接收数据

        线程(微进程) : 最小的执行单元,调度单元

                多个线程可以共享进程的资源

                优点 :  占用资源小,切换时间短

        协程 : 用户级线程,可以人为控制    yield关键字实现   

                用途 : celery, websocket(协程补丁)

                优点 :

                        比线程占用资源还少

                        切换时间开销最小

                缺点:

                        无法利用多核资源  --- 》 可以进程 + 协程方式利用多核实现高并发(实现步骤搜一下)

                实现协程的机制:

                        yield 关键字

                        greenlet        

                        gevent :  将任务加到事件队列中,有gevent来实现任务的调度

                        eventlet  :比较火

并发 :同一时间段内多个任务同时执行,执行多个任务的能力

并行: 同一时刻多个任务同时执行[必须多核条件才能达成]

python多线程?

        python的多线程是伪多线程,由于存在GIL锁,在同一进程下,同一时刻只有一个线程被CPU执行,不支持并行

GIL锁

        GIL : 锁的是进程,同一进程下,同一时刻只有一个线程被CPU执行

        “ 因为GIL锁 : python支持多线程,但是不能并行(多核)多线程,其他语言可以,尤其是Go和C

        解决办法 : 多进程 + 协程方式(对协程语法很了解) --> 多核优势 + 协程并发,进程数要与核数差不多

        优点 : 1. 避免了大量的加锁解锁操作

                      2. 使数据更加安全,解决多线程间的数据完整性和状态同步

        锁的作用(优点): 使数据更加安全,解决多线程间(并发)的数据完整性和状态同步

        缺点 : 使多核处理器退化成单核处理器,只能并发,不能并行。

计算密集型 :多核有优势   -- >  多进程效率高

I/O密集型 :不需要多核,多核也需要等待 --> 多线程

IO多路复用

        nginx实现原理 --> epoll原理 --> 底层实现 --> 红黑树 --> 好处 --> 快速

        多个客户端连接,单线程下实现并发效果,就叫多路复用

        与多进程和多线程相比,系统开销更小,不必创建多余的进程/线程

        底层原理 : epoll

        select、poll、epoll区别?

        select、poll差不多,都是遍历整个列表,时间复杂度O(N)

        epoll只要判断就绪链表是否为空,节省CPU时间,时间复杂度O(1)

 OSI七层模型

        1. 物理层

        2. 数据链路层

        3. 网络层

        4. 传输层

        5. 会话层

        6. 表示层

        7. 应用层

        协议簇 : TCP/IP(民间形成:四层) 把OSI七层模型简化为四层(应用 传输 网络 物理)

socket 连接步骤

Server端程序

import socket
# 1. 创建Socket套接字对象(区分类型type)
sk = socket.socket(type=socket.SOCK_STREAM)
# 2. 动态绑定ip和端口(为什么绑定IP和端口? --> 因为客户端的ip和端口有可能改变(换一根网线))
sk.bind(('192.168.21.88',8808))
# 3.监听外部连接有没有3次握手
sk.listen()
# 4. 处理/接收监听到的客户端连接
# conn 表示建立好的连接通道抽象成对象
# address就是接收到客户端的ip和port(端口)
conn, address = sk.accept() # 实现3次握手过程
# accept 是一个阻塞方法,程序运行到此处就hang住,除非某种条件成立后,结束阻塞
# 结束阻塞条件就是成功的接收到一个客户端连接
# 5. 基于建立好的连接通道进行数据的收发
recv_msg = conn.recv(2014)
print('接收到数据',recv_msg)
send_msg = input("请输入发送给客户端数据:")
conn.send(send_msg.encode()) # 
conn.close()
sk.close()

Client端程序

# 1. 创建套接字对象
s = socket.socket(type=socket.SOCK_STREAM)
# 2. 连接目的服务器
s.connect(("192.168.21.88",8808))
# 3 数据的收发
send_msg = input("请输入发送数据")
s.send(send_msg.encode())

recv_msg = s.recv(1024)
print("接收到的服务器数据:",recv_msg)
s.close()

协议

HTTP/HTTPS

websocket

TCP

UDP

python基础

PEP8规范

        1. 使用4个空格而不是 Tab键进行缩进

        2. 每行长度要不能超过 79

        3. 使用空行来间隔函数和类,以及函数内部的大块代码

        4. 必要时,在每一行写上注释

        5. 命名类和函数使用一致的方式

        6. 在类中总是使用self来作为默认

        7. 尽量不要使用魔法方法

        8. 不要在一句import多个库

     空格的使用

        1. 各种右括号前不要加空格

        2. 逗号,冒号,分号前不要加空格

        3. 函数的左括号前不要加空格

        4. 操作符左右各加一个空格,不要为了对齐增加空格

        5. 函数命名使用全部小写的方式,常量命名使用大写,类属性(方法和变量)使用小写,类的命名首字母大写

垃圾回收机制

        引用计数为主,分代回收和标记清除为辅

        引用计数:

        标记清除:

        分代回收:

变量和值

        局部变量 : 在函数内部定义的变量

        全局变量 :在函数外部定义的变量,或者在函数的内部,用global关键字定义的变量

作用域: 作用的范围

        局部变量的作用范围只限定在函数的内部

             nonlocal 修改局部变量时,采用LEGB原则

                1. 跳出当前函数这一层空间,到上一层寻找

                2. 如果上一层不存在该变量,继续到上一层寻找

                3. 如果最顶级也找不到,直接报错

        全局变量的作用范围横跨整个文件

LEGB 原则 : 就近找变量原则

        找寻变量的调用顺序采用LEGB原则(即就近原则)

        B --- Builtin(Python) : Python 内置模块的命名空间                (内建作用域)

        G --- Global(module) : 函数外部所在的命名空间                 (全局作用域)

        E --- Enclosing function locals :外部嵌套函数的作用域       (嵌套作用域)

        L --- Local(function) : 当前函数内的作用域                          (局部作用域)

        依据就近原则,从下往上,从里往外 依次寻找

python语言特性

        解释性,动态语言

        优势 : 开发效率高

        劣势 : 运行速度慢

        

python方向

python语言和其他语言区别?

py3和py2区别?

        python2 print打印时不需要加括号,python3需要

        python2 默认编码 为 ASCII编码,要输出中文时,要添加encoding=utf-8

        python2 : raw_input     python3 : input

        python2 :  xrange -> 生成器   range -> 生成列表    python3 : range  -> xrange与range结合,返回迭代器

        不相等操作符"<>"被python3废弃,统一使用  !=

        python2 整型 :long   python3 整型 :int

内置模块和第三方模块

        内置模块 :

                time/datetime -- 时间模块

                OS  --  程序与操作系统交互

                sys --  程序与python解释器交互

                random -- 生成随机数

                Logging -- 日志

                序列化模块[ dump (字典 -> json字符串)、load(json字符串  -> 字典 )]

                正则re模块 : 匹配信息

        第三方模块:

                celery : 异步任务、定时任务执行框架

                simpui : 装饰admin站点

                paramiko : ssh免密登录

                requests : 爬虫

                SQLalcheiny : ORM

                支付宝 :

                短信 :

                腾讯防水墙验证码 :

                阿里云存储 : oss

                pymysql : 数据库驱动类

                channels : 用于Django连接websocket

                flask : socket_io等

字典和列表的区别

        列表       

                任意对象的有序集合

                通过索引读取

                可变的序列

                查找和插入的时间随着元素的增加而增加

        字典

                以键值的方式来存储数据

                任意对象的无序集合

                查找和插入的速度极快

                占用大量的内存

        注意 : dict 是用空间换时间的一种方法

单例模式

方式一:

        导包的形式,一次导包,再导包,就没有作用了

方式二:

        

Class Singleton():
    def __init__(self):
        pass
    def __new__(cls,*args,**kwargs):
        if not hasatter(cls,instance):
            cls.instance = super().__new__(cls)
    Return cls.instance

方式三: 基于 __new__

class Singleton(object):
    ins = None
    
    def __new__(cls,*args,**kwargs):
        if not cls.ins:
            cls.ins = super().__new__(cls,*args,**kwargs)
    return cls.ins

方式四:装饰器

from functools import wraps
 
def Singleton(cls):
    _instance = {}
    @wraps(cls)
    def _singleton(*args, **kargs):
        if cls not in _instance:
            _instance[cls] = cls(*args, **kargs)
        return _instance[cls]
 
    return _singleton
 
@Singleton
class Settings():
    """Docstring"""
    def __init__(self):
        self.a = "xxx"
        self.b = "xxx"

内置函数 : sum,max,min,abs

高阶函数

       满足两个条件 :1. 以函数为参数  2. 以函数为返回值

        map: 映射 , 按照一定规则[func]映射出去

                语法 : map(func, Iterable)

                参数 : func 自定义函数 / 内置函数

                             Iterable  可迭代性数据 [ 容器类型数据 , range对象, 迭代器]

                返回值 :迭代器

           注意 : 只有在调用迭代器的时候,才会真正的执行map函数

        filter : 过滤数据,过滤出符合规则的

                语法  : filter(func,Iterable)

                返回值 : 迭代器

                lst = [2,6,44,77,87,35,89]

                res = filter( lambda x : True if x%2 == 0 else false, lst)

                

        reduce : 计算数据

                语法 : reduce(func, Iterable)

                        一次性先从Iterable 拿出2个数据,扔到 func中做计算,然后把计算结果作为参数与Iterable中下一个数据继续进行计算,直到所有数据计算完毕,返回最后结果

                返回值:最后计算的值

                

        zip : 

        sorted : 排序

                语法 : sorted(Iterable, reverse = False, key = 函数)

                功能 : 排序数据

                        reverse  ==> 代表正序,倒序

                        key   ==> 指定排序的规则

                返回值 : 排序后的结果,永远为列表

                注意 : sorted 和 sort 功能一致,都是进行数据的排序

                            区别:

                                sorted : 可以排序所有的容器类型数据,排序完之后,返回一个新的列表

                                sort     : 只能排序列表,直接对原列表进行排序,没有返回值

匿名函数

        用一句话来表达只有返回值的函数,可以使用 lambda 表达式

        lambda 参数 : 返回值

        特点 : 简洁,高效

        无参的 lambda 表达式

                func = lambda : 123    print(func)

        有参的 lambda 表达式

                func = lambda x,y : x+y

                print( func(4,5) )

        带有判断条件的 lambda 表达式

                真值 if 表达式 else 假值

                func = lambda num :"偶数" if num % 2 == 0 else "奇数"

                print(func(34))

        

深浅拷贝

  浅拷贝  :copy.copy() 或者listvar.copy() 浅拷贝只拷贝外层列表 , 内层列表跟随原列表进行改变

     浅拷贝,指的是重新分配一块内存,创建一个新的对象,但里面的元素是原对象中各个子对象的引用

        例子:

  深拷贝 : copy.deepcopy(listvar)  拷贝整个列表,内外列表都不跟随原列表进行改变

        深拷贝,指的是重新分配一块内存,创建一个新的对象,并且将原对象中的元素,以递归的方式,通过创建新的子对象拷贝到新对象中。因此,新对象和原对象没有任何关系

        例子:

注意 :copy模块的copy方法 和python内置的函数copy一样,都是浅拷贝

生成器、迭代器、装饰器

        迭代器 :

                可迭代对象 : 类型定义了__iter__ 方法,返回一个迭代器的实现

                迭代器 :

                        1. 类型定义了__iter__ 方法

                        2. 类型定义了__next__方法,通过指定逻辑来返回具体迭代值

                概念 : 迭代器指的是迭代取值的工具,迭代是一个重复的过程,每次重复都是基于上一次的结果而继续的

                特征 : 并不依赖索引,通过 next 指针(内存地址寻址)迭代所有数据,一次只取一个值

                for 循环步骤: 先执行可迭代对象的 __iter__ 方法得到一个迭代器,然后调用迭代器的__next__方法

        生成器:yield  [特殊的迭代器]

                yield 实现了将值暂存与恢复的功能,每次调用__next__方法时,基于上一次暂停的位置继续执行

列表生成式

        l = [1,1,2,3,5]

        [i*i for i in l if i %2 == 0]

字典生成式

        dic = {"id":1001,"name":"yuan","age":22,"weight":"70kg","scores":76}

        new_dic = {k:v for k,v in dic.items()}

生成器表达式

        tup = (x for x in range(3))

                

                 

什么是闭包?

文件操作

python内置模块 : pickle、struct、第三方模块 : ujson 、 orjson

json : 用于字符串和python数据类型间进行转换

pickle : 用于python特有的类型和python的数据类型间进行转换

json提供四个功能 : dumps、loads、dump、load

pickle提供四个功能 :dumps、loads、dump、load

json dump和dumps的区别

        json 是一种标准的数据交换格式,独立于编程语言和计算平台。它其实也是一种字符串,默认编码是Unicode。

        json.dump()  是将python对象写入json文件

                json.dump(dict,filr_pointer)

                dict : 被转换的对象

                file_pointer : 打开文件的指针

        json.dumps()   是将python对象转换成json字符串

                json.dumps(dict,indent)

                dict : 被转换对象

                indent : 打印格式的参数

read readline readlines 的区别

        read   : 一次性读取文件的全部内容      返回结果类型 :str

        readline : 每次读取一行,并且自带换行功能,每一行末尾会读到\n   返回结果类型 :str

        readlines : 一次性以行的形式读取文件的所有内容并返回一个list    返回结果类型 :list
 

实例对象能不能更改类的属性? 

        类属性 : 在类中定义的变量  --> 类属性(类变量,类的成员变量)

        实例属性 : 在实例中空间定义的变量  --> 实例属性(实例变量)        

        不可以,

变量 : 先去找实例空间  --> 类空间 -->  父级  -->  object

__new__与__init__的区别

        __new__是创建实例对象,创建空间,__init__是实例化对象,是在__new__执行之后

__str__与__repr__区别

        __str__是给人看的,__repr__是给程序员看的

py3在类的继承顺序?

        C3算法  --> 先深度优先,在广度优先,--> 先是深度优先,在深度优先的同时加上一个条件 --》 是不是最后一个儿子,所有都会读完

类方法、实例方法、静态方法区别?

int、str、tuple、list、set、dict的区别

        1. set集合 和 dict字典的区别?

                唯一区别 : set没有对应的value值

                相同点 :

                        1). 都无索引,不可以进行切片和根据索引操作

                        2). 两者都是不可哈希的可变类型

                        3). 两者内部元素都是可哈希的不可变类型

        2. set集合和list列表的区别

                相同点 : 都是可变类型

                区别:

                        set集合无序且元素唯一

                        set集合取值,只能for循环,否则因为无序,无索引

                        set集合主要用于测试数据和数据的交差并补和去重操作

                        list列表有序且元素不唯一,可以根据索引切片取值

                        set集合本质区别和dict相同

        3. list列表和dict字典的区别

                相同点 : 都是可变类型,可迭代

                区别:

                        list是有序的,dict是无序的[看着有序]

                        list可以索引取值,dict是通过键取值

                        dict的键必须是不可变对象

                        dict需要的存储空间大于list列表

                        dict查询效率远高于列表

        tuple元组和list列表的区别

                相同点 : 可迭代

                区别:

                        tuple对象创建后就不可变,不能添加和删除

                

        tuple元组、字符串、number的区别

                不可变类型(可哈希),不可以进行更改元素

                元组内元素可以包含可变类型

                        

魔术方法

        __del__  :  析构方法,实例对象被销毁,调用

编码

        base64编码 : JWT  好处  : 效率高    原因 : 网络传输含有节点,传输内容有英文数字中文等,任何一种编码都可以用,但要保证所有设备和节点都支持这种编码,否则出现乱码,所有节点和设备都支持ascii,base64属于在ascii码基础上支持中文,所有编码都可以解base64

        所有编码都兼容ascii码,但传输不能用ascii吗,不支持中文

Base64编码工具函数[重点]

        Base64是网络上最常见的用于传输8Bit字节码的编码方式之一

        Base64是一种基于64个可打印字符来表示二进制数据的方法

        64个可打印编码字符就是   小写字母 + 大写字母 + (0-9) + 符号(+ / =)

        编码 : 二进制 --> 编码字符 : HTTP环境下传递较长的标识信息,如图片

Django

MVC架构[前后端分离]

        M --> model 模型 ,编写操作数据库的代码,往往是一个类或者对象

        V --> view 视图 , 编写页面操作的代码,往往是一个具有特殊语法的html文件

        C --> controler 控制器, 主要是调用模型获取数据,并把数据写入视图中,往往就是一个类或者对象

    过程 : C调用M,M操作数据库,把数据返回给C,C调用V,将数据和视图结合起来

MVT架构[前后端不分离]

        M --> model模型,编写操作数据库代码,往往就是要一哥类或者对象

        V --> View 视图, 调用模型获取数据,并把数据写入模板中,往往就是一个个类或对象

        T --> Template 模板  编写页面效果的代码,往往就是一个具有特殊语法的html文件

Django、Flask、Tornado

        django : 主要是用来搞快速开发的,它的亮点就是快速开发,节约成本,正常的并发量不超过1W,如果要实现高并发的话,就要对Django进行二次开发,比如把整个笨重的框架拆掉,自己写socket实现http通讯、ORM框架等等

        Flask : 轻量级,主要是用来写接口的一个框架,实现前后端分离,提升开发效率,Flask本身相当于一个内核,其他几乎所有的功能都要扩展(邮件扩展Flask-Mail,用户认证Flask-Login),都需要用第三方的扩展来实现。比如可以用Flask-extension加入ORM、窗体验证工具,文件上传、身份验证等。Flask没有默认使用的数据库,你可以选择Mysql,也可以使用Nosql。其WSGI工具箱采用 Werkzeug(路由模块),模板引擎则使用 Jinja2。这两个也是Flask框架核心。Flask应该算是最灵活的框架之一。

        Tornado(异步):Tornado是一种 Web服务器软件的开源版本。 Tornado 和现在的主流 Web 服务器框架(包括大多数Python框架)有着明显的区别: 它是非阻塞式服务器,而且速度相当快。得利于其非阻塞的方式和对epoll的运用,Tornado 每秒可以处理数以千计的连接,因此 Tornado 是实时 Web服务的一个理想框架。

Django的生命周期

前后端分离 : 访问 -> wsgi(web服务器)[解压request包] -> 中间件 -> 路由分发 -> 视图 -> 模型

前后端不分离 : 访问 -> wsgi(web服务器)[解压request包] -> 中间件 -> 路由分发 -> 视图 -> 模型/模板

WSGI/UWSGI/ASGI(3.2):充当web服务器,构建socket,接收请求,响应回复

中间件[类似钩子] :具体找一下

        * 应用 -- 黑白名单   

        防止别人爬取数据(requests 爬虫)  --> 监控频率

        中间件执行顺序 : 客户端请求 -> process_request(对于一些请求拦截,可以写) -> 服务端 -> process_response(想要对响应的数据进行更改,写在这)

路由控制系统

        请求路径和指定视图函数的映射

        include , re_path

        类视图路由分发原理(见源码) : url[与路由绑定的是as.view()的返回值 --> view, view中的dispatch  ->  dispatch (路由分发)]

地址栏 :

        协议://IP或域名:端口/路径?查询字符串#锚点

        protocol://hostname:port/pathname?query_string#hash

        协议 : http  https  ws(websocket)  wss

        ip : 127.0.0.1

        域名 : baidu.com

请求:

        request是一个对象,是客户端请求web服务器时,wsgi服务器把客户端请求的报文解析成数据保存到request

        request.GET  获取查询字符串   

                 request.GET.get("name") 获取一个   

                 request.GET.getlist("lve")获取多个

                 request.GET.dict()  将查询字符串格式转为字典格式

获取请求数据 : request.boby  获取原始的请求体,request.POST  只能获取表单数据

Django有哪些组件

        ORM、Admin、中间件、cookie、session、auth

        

Restful规范[状态码]

        1.  风格 : 以资源为主,后端开发任务就是提供数据的,对外提供的是数据资源的访问接口,所以在定义接口时,客户端访问的URL路径就表示这种要操作的数据资源

        2.  https协议: 以http请求动作对数据进行增删改查

        3.  安全性和幂等性 : 多次请求结果相同,幂等。   安全: 不改变数据

        4.  状态码:

                200 OK -  [GET] : 服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)

                201 CREATED - [POST/PUT/PATCH] : 用户新建或修改数据成功

                202 Accepted - [*] : 表示一个请求已经进入后台排队(异步任务)

                204 NO CONTENT - [DELETE] : 用户删除数据成功

                301 : 永久重定向

                302: 暂时重定向

                400 INVALID REQUEST - [POST/PUT/PATCH]: 用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的

                401 Unauthorized - [*] : 表示用户没有权限(令牌、用户名、密码错误)

                403 Forbidden - [*] : 表示用户得到授权(与401错误相对),但是访问是被禁止的

                404 NOT FOUND - [*]: 用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的

                406 Not Acceptable - [GET] : 用户请求的格式不可得(比如用户请求JSON格式,但是只有xml格式)

                500 INTERNAL SERVER ERROR - [*]: 服务器发生错误,用户将无法判断发出的请求是否成功

Django实现高并发

        django是单线程

        nginx + uwsgi 提供高并发

                uwsgi : 默认 , 但是并发量不够,所以部署使用nginx --> Web服务器

                nginx : 1. 反向代理的目的是实现负载均衡  -->并发量拷贝了

                               2. 静态文件响应,动态文件转发 

        nginx 的并发能力超高,单台并发能力过万,在纯静态的web服务中更是突出其优越的地方,由于其底层使用epoll 异步IO模型进行处理,使其深受欢迎

Django的ORM

        O是object,类对象

        R是relation, 关系型数据库的数据表意思

        M是map , 映射, 表示类对象和数据表的映射关系

ORM框架 : 把类对象和数据表进行了一对一的映射,通过类对象来操作对应的数据表,根据设计的类自动生成数据库中的表格

优点 : 

        代码更新维护方便 --> 数据模型类写在一个文件中定义

        ORM有现成的工具,很多功能都可以自动完成,比如数据消除,预处理,事务等等

        基于 ORM 的业务代码比较简单,代码量少,语义性好,容易理解

        开发中应用ORM将来如果切换数据库,只需要切换ORM底层对接数据库的驱动

缺点:

        ORM 库不是轻量级工具,需要花费很多精力学习和设置,甚至不同的框架,会存在不同操作的ORM

        对于复杂的业务查询,ORM表达起来比原生的SQL要更加困难

        ORM操作数据库的性能要比使用原生的SQL差,[ORM内部要拼接SQL语句,之后在执行]

ORM面试问题

        ORM优化

                惰性查询

                

        Django ORM 事务

                在完成一个整体功能时,操作到了多个表数据,或者同一个表的多条记录,如果要保证这些SQL语句操作作为一个整体保存到数据库中,那么可以使用事务(transation),保证这些操作作为不可分割的整体,要么一起成功,要么一起失败

        事务具有的4个特性(ACID),5个隔离等级

                A : 原子性(Atomicity) , 所有的数据是不可分割的,原子性操作

                C:一致性(Consistency) : 数据在操作前后的的状态要一致

                 I :隔离性(Isolation) : 事务与事务之间

                 D:持久性(Durability):数据变化之后,就保存了,

orm原生SQL的方法和区别

        1.  connection 连接 游标对象 cursor.execute   

        2.  extra

        3.  raw : Student.objects.raw(SQL语句)

Django内部组件和外部组件

        内部组件:

                ORM、Cookie、session、中间件、分页器、DRF、认证组件[Auth]

        外部组件:

                pymysql、celery、mysql、redis

ORM的abstact和managed

        abstact :

        managed :

数据迁移时出错如何解决

        DBA负责,我们一般不涉及数据迁移

        先把数据备份,之后删除sickpackeg的migration的日志和子应用下的日志,删除所有表,再进行数据迁移

django中间件及自定义的中间件

        内置中间件:

                SessionMiddleware : session加密

                CommonMiddleware : 通用中间件,自动给url后面加/

                CsrfViewMiddleware: 防止网站遭到csrf攻击

                AuthenticationMiddleware : 用户认证中间件

                MessageMiddleware : 错误提示信息的中间件

                SecurityMiddleware : 安全监测相关的中间件,防止页面过期,js跨站脚本攻击xss

                XFrameOptionsMiddleware : 用于防止点击劫持攻击的 iframe标签

        自定义:

                django-cors-hearders  跨域

        自定义中间件[函数/类]:

                process_request : 用途 -- 权限,路由分发,cdn,用户身份识别,白名单,黑名单。注意,此方法不能使用return,使用则报错!!!

                process_response : 用途 -- 记录操作历史,记录访问历史,修改返回给客户端的数据,建立缓存,必须返回response对象,否则报错!!!

                process_view : 用途 -- 进行缓存处理,识别参数,根据参数查询是否建立缓存

                process_exception:进行异常的处理或者记录错误日志

                process_template_response : 建立页面缓存

CSRF攻击

JWT的cookie,session的区别

        cookie原理

        session原理

JWT【djangorestframework-jwt】

        Json web token (JWT) : 是为了在网络应用环境间传递声明而执行的一种基于JSON的开发标准。该token被设计为紧凑且安全,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者(客户端)和服务提供者(服务端)间传递被认证的用户身份信息,以便于从资源服务获取资源,也可以增加一些格外的其他业务逻辑所必须的声明信息,该token也可直接被用于身份认证,也可被数据加密传输

        JWT构成

        头部(header) [类型和加密方式] + 载荷(payload)[用户信息] + 签证(Signature)[秘钥]

JWT认证流程

什么是单点登录(JWT)

DRF[Django-rest-framework]

权限分发[RBAC] 

DRF功能

序列化器Serializer 与 ModelSerializer区别---看一下笔记

        1. ModelSerializer是Serializer的子类,ModelSerializer支持Serializer所有的操作,ModelSerializer可以简化代码

        **2.  继承ModelSerializer 序列化器需要声明调用模型信息class Meta: model = Student

        **3. 基于模型类自动生成一系列字段 fields = ["id","name"]

        4.基于模型类自动为Serializer生成validators,比如unique_together

        5. 包含默认的create()和update()的实现

        6. 具体看一下2个序列化器的代码构成

如何使用序列化器获取外键关联模型的字段

        方法一 : 序列化器嵌套 : source

        方法二 : 关联深度 : depth = 1

ORM中的filter实现原理

        ORM原理 -- ORM先转化为sql语句再去执行

限流

        DRF : Throtting

        消息队列[先进先出] : 串行化

        装饰器

Flask

        

linux

linux命令

        pwd : 

        cat :

        mkdir

        touch

        mv

        cp

        whereis    which

        head -4 demo.txt 

        tail -2 demo.txt

        **grep 文本处理

                用法一 : 文本搜索 grep 关键字 文件名

                用法二 : 上一个命令 | grep 关键字

                ps aux | grep django

       tar -zcf demo.tar.gz 001

       tar -zxf demo.tar.gz

        kill -9 进程id

基础数据结构和算法

Git

项目

在项目中如何实现读写分离

        1. 在配置文件settings.py中配置两个数据库,一个主库,用来进行数据的操作,一个从库,用来从数据库中读取数据。

        2. 创建db_router.py,自定义一个数据库路由类进行读写分离 db_for_read、db_for_write

        3. 配置 DATABASE_ROUTERS 数据库路由分发

怎么处理跨域

        1. 客户端 : 客户端配置 vue.config.js 代理实现跨域请求

        2. 服务端 : 服务端通过组件 cors-headers 中间件来实现跨域

项目中用到了那些设计模式

        MVT设计模式   -- 前后端不分离?

        数据库 --- 链式模式

        celery异步任务 --- 生产者消费者模式

        redis --- 工厂模式(生成redis对象)

        优惠活动 --- 策略模式

        faker  --- 工厂模式

        订单超时  --- 发布订阅模式

        轮播图,导航 --- 装饰器模式

        日志 --- 代理模式

        连接池  --- 享元模式

elasticsearch能够快速实现全文搜索的原因

        1. es 查询速度快的原因是采用了  倒排索引

        2. 倒序索引的概念 : 建立关键词到文档的映射关系,给你几个关键词,找出包含关键词的文档

docker

dockerfile  ADD与COPY的区别

        COPY:直接复制
        ADD : 可以进行解压

       

Nginx

概念

        Nginx 是一个高性能的HTTP和反向代理服务器,其特点是占用内存少,并发能力强

代理服务器的功能

        突破自身IP访问限制,访问国外站点

        提高访问速度

        隐藏真实IP

反向代理

        客户端向反向代理命名空间发送普通请求,,将获得的内容返回给客户端[客户端不知道谁是真正的服务器]

        反向代理可以为后端的多态服务器提供负载平衡或后端较慢的服务器提供缓冲服务

正向代理

        -- 正向代理允许客户端通过它访问任意网站并且隐藏客户端自身

负载均衡

-- 将服务器接收到的请求按照规则进行分发的过程

负载均衡调度算法

        -- 1.weight轮询(默认) 接收到的请求按照顺序逐一分配到不同的后端服务器
        -- 2.ip_hash 每个请求按照发起客户端的ip的hash结果进行匹配
        -- 3.fair:智能调整调度算法,动态的根据后端服务器的请求处理到响应的时间进行均衡分配,响应时间短处理效率高的服务器分配到请求的概率高,Nginx默认不支持fair算法
        -- 4.url_hash 按照访问的url的hash结果分配请求,每个请求的url会指向后端固定的某个服务器,可以在Nginx作为静态服务器的情况下提高缓存效率,Nginx默认不支持这种调度算法

Nginx 优势:

        -- 作为Web服务器,Nginx处理静态文件、索引文件,自动索引的效率非常高
        -- 作为代理服务器,Nginx可以实现无缓存的反向代理加速,提高网站运行速度
        -- 作为负载均衡服务器,Nginx既可以在内部直接支持Rails和PHP,也可以支持HTTP代理服务器对外进行服务,同时还支持简单的容错和利用算法进行负载均衡
        -- 在性能方面,Nginx是专门为性能优化而开发的,实现上非常注重效率。它采用内核Poll模型,可以支持更多的并发连接
        -- 在稳定性方面,Nginx采取了分阶段资源分配技术,使得CPU与内存的占用率非常低
        -- 在高可用性方面,Nginx支持热部署,启动速度特别迅速

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值