315道Python面试题答案

目录

  • Python基础篇
    • 1:为什么学习Python
    • 2:通过什么途径学习Python
    • 3:谈谈对Python和其他语言的区别
    • Python的优势:
    • 4:简述解释型和编译型编程语言
    • 5:Python的解释器种类以及相关特点?
    • 6:位和字节的关系
    • 7:b、B、KB、MB、GB的关系
    • 8:PE8规范
    • 9:通过代码实现如下转换(进制之间转换)
    • 10:请编写一个函数实现将IP地址转换成一个整数
    • 11、python递归的最大层数?998
    • 12:求结果(and or or)
    • 运算符
    • 13 :ascii、unicode、utf-8、gbk 区别
    • 14:字节码和机器码的区别
    • 15:三元运算写法和应用场景?
    • 16:Python3和Python2的区别?
    • 17:用一行代码实现数值交换
    • 18:Python3和Python2中int和long区别
    • 19:xrange和range的区别
    • 20:文件操作时:xreadlines和readlines的区别?
    • 21: 列列举布尔值为False的常见值?
    • 22. 字符串、列表、元组、字典每个常用的5个方法?
    • 23、 lambda表达式格式以及应用场景?
    • 24. pass的作用
    • 25. *arg和**kwarg作用
    • 26. is和==的区别
    • 27:谈谈Python的深浅拷贝?以及实现方法和应用场景。
    • 28. Python垃圾回收机制?
    • 29. Python的可变类型和不可变类型?
    • 30、求结果
    • 31、求结果
    • 32、列举常见的内置函数
    • abs()
    • map
    • filter
    • map与filter总结
    • isinstance\type
    • zip 拉链函数
    • 33. filter、map、reduce的作用?
    • 内置函数:map、reduce、filter的用法和区别
    • 34、 一行代码实现9*9乘法表
    • 35. 如何安装第三方模块?以及用过哪些第三方模块?
    • 36、 常用模块都有那些?
    • 37. re的match和search区别?
    • 38. 什么是正则的贪婪匹配?
    • 39. 求结果:
    • 40. 求结果:
    •  41、def func(a,b=[]) 这种写法有什什么坑?
    • 42、如何实现 “1,2,3” 变成 [‘1’,’2’,’3’]
    • 43. 如何实现[‘1’,’2’,’3’]变成[1,2,3]
    • 44. a = [1,2,3] 和 b = [(1),(2),(3) ] 以及 b = [(1,),(2,),(3,) ] 的区别?
    • 45. 如何用一行代码生成[1,4,9,16,25,36,49,64,81,100]
    • 46. 一行代码实现删除列表中重复的值
    • 47. 如何在函数中设置一个全局变量
    • 48. logging模块的作用?以及应用场景?
    • 49. 请用代码简答实现stack
    • 50. 常用字符串格式化哪几种?
    • 51. 简述 生成器、迭代器、可迭代对象 以及应用场景?
    • 迭代器
    • 生成器
    • 可迭代对象
    • 装饰器
    •  52. 用Python实现一个二分查找的函数。
    • 53. 谈谈你对闭包的理解?
    • 54. os和sys模块的作用?
    • 55. 如何生成一个随机数?
    • 56. 如何使用python删除一个文件?
    • 57. 谈谈你对面向对象的理解
    • 58. Python面向对象中的继承有什么特点
    • 59. 面向对象深度优先和广度优先是什么?
    • 60. 面向对象中super的作用?
    • 61. 是否使用过functools中的函数?其作用是什么?
    • 62. 列举面向对象中带双下划线的特殊方法,如:__new__、__init__
    • 63. 如何判断是函数还是方法?
    • 64. 静态方法和类方法区别?
    • 65. 列举面向对象中的特殊成员以及应用场景
    • 66. 1、2、3、4、5 能组成多少个互不相同且无重复的三位数
    • 67. 什么是反射?以及应⽤用场景?
    • 68. metaclass作用?以及应用场景?
    • 69. 用尽量多的方法实现单例模式。
    • 70. 装饰器器的写法以及应用场景。
    • 71. 异常处理写法以及如何主动跑出异常(应用场景)
    • 72、什么是面向对象的mro
    • 73. isinstance作用以及应用场景?
    • 74. 写代码并实现
    • 75. json序列化时,可以处理的数据类型有哪些?如何定制支持datetime类型?
    • 76. json序列化时,默认遇到中文会转换成unicode,如果想要保留中文怎么办?
    • 77. 什么是断言?应用场景?
    • 78. 有用过with statement吗?它的好处是什么?
    • 79. 使用代码实现查看列举目录下的所有文件。
    • 80. 简述 yield和yield from关键字
  • 第二部分 网络编程和并发
    • 81. 简述 OSI 七层协议。
    • 82. 什么是C/S和B/S架构?
    • 83. 简述 三次握手、四次挥手的流程。
    • 84. TCP和UDP的区别?
    • 85. 为何基于tcp协议的通信比基于udp协议的通信更可靠?
    • 86. 什么是socket?简述基于tcp协议的套接字通信流程。
    • 87. 什么是粘包? socket 中造成粘包的原因是什什么? 哪些情况会发生粘包现象?
    • 88. IO多路复的作用?
    • 89.select、poll、epoll 模型的区别?(属于多路复用IO的模型)
    • 90. 什么是防火墙以及作用?
    • 91. 简述 进程、线程、协程的区别 以及应用场景?
    • 92. GIL锁是什么?
    • 93. Python中如何使用线程池和进程池?
    • 94. threading.local的作用?
    • 95. 进程之间如何进行通信?
    • 96. 什么是并发和并行?
    • 97. 进程锁和线程锁的作用?
    • 98. 解释什么是异步非阻塞?
    • 99. 路由器和交换机的区别
    • 100.什么是域名解析?
    • 101.如何修改本地hosts件?
    • 102.生产者消费者模型应用场景及优势?
    • 103.什么是cdn?
    • 104.LVS是什么及作用?
    • 105.Nginx是什么及作用?
    • 106.keepalived是什么及作用?
    • 107.haproxy是什么以及作用?
  • 数据库和缓存(46题)
    • 113.列举常见的关系型数据库和非关系型都有那些?
    • 114.MySQL常见数据库引擎及比较?
    • 115.简述数据库三大范式?
    • 116、什么是事务?MySQL如何支持事务?
    • 117.简述数据库设计中一对多和多对多的应用场景?
    • 118.如何基于数据库实现商城商品计数器?
    • 119.常见SQL(必备)
    • 120.简述触发器、函数、视图、存储过程?
    • 121.MySQL索引种类
    • 122.索引在什么情况下遵循最左前缀的规则?
    • 123.主键和外键的区别?
    • 124.MySQL常见的函数?
    • 125.列举 创建索引但是无法命中索引的8种情况。
    • 126.如何开启慢日志查询?
    • 127.数据库导入导出命令(结构+数据)?
    • 128.数据库优化方案?
    • 129.char和varchar的区别?
    • 130.简述MySQL的执行计划?
    • 131.在对name做了唯一索引前提下,简述以下区别:     
    • 132.1000w条数据,使用limit offset 分页时,为什么越往后翻越慢?如何解决?
    • 133.什么是索引合并?
    • 134.什么是覆盖索引?
    • 135.简述数据库读写分离?
    • 136.简述数据库分库分表?(水平、垂直)
    • 137.redis和memcached比较?
    • 138.redis中数据库默认是多少个db 及作用?
    • 139.python操作redis的模块?
    • 140.如果redis中的某个列表中的数据量非常大,如果实现循环显示每一个值?
    • 141.redis如何实现主从复制?以及数据同步机制?
    • 142.redis中的sentinel的作用?
    • 143.如何实现redis集群?
    • 144.redis中默认有多少个哈希槽?
    • 145.简述redis的有哪几种持久化策略及比较?
    • 146.列举redis支持的过期策略。
    • 147.MySQL 里有 2000w 数据,redis 中只存 20w 的数据,如何保证 redis 中都是热点数据? 
    • 148.写代码,基于redis的列表实现 先进先出、后进先出队列、优先级队列。
    • 149.如何基于redis实现消息队列?
    • 150.如何基于redis实现发布和订阅?以及发布订阅和消息队列的区别?
    • 151.什么是codis及作用?
    • 152.什么是twemproxy及作用?
    • 153.写代码实现redis事务操作。
    • 154.redis中的watch的命令的作用?
    • 155.基于redis如何实现商城商品数量计数器?
    • 156.简述redis分布式锁和redlock的实现机制。
    • 157.什么是一致性哈希?Python中是否有相应模块?
    • 158.如何高效的找到redis中所有以aaa开头的key?
  • 第四部分 前端、框架和其他(155题)
    • 1.谈谈你对http协议的认识。
    • 2.谈谈你对websocket协议的认识。
    •  3.什么是magic string ?
    • 4.如何创建响应式布局?
    • 5.你曾经使用过哪些前端框架?
    • 6.什么是ajax请求?并使用jQuery和XMLHttpRequest对象实现一个ajax请求。
    • 7.如何在前端实现轮训?
    • 8.如何在前端实现长轮训?
    • 9.vuex的作用?
    • 10.vue中的路由的拦截器的作用?
    • 11.axios的作用?
    • 12.列举vue的常见指令。
    • 13.简述jsonp及实现原理?
    • 14.什么是cors ?
    • 15.列举Http请求中常见的请求方式?
    • 16.列举Http请求中的状态码?
    • 17.列举Http请求中常见的请求头?
    • 18.看图写结果(js):
    • 看图写结果(js):
    • 看图写结果:(js)
    • 看图写结果:(js)
    • 看图写结果:(js)
    • 看图写结果:(js)
    • 19.django、flask、tornado框架的比较?
    • 20.什么是wsgi?
    • 21.django请求的生命周期?
    • 22.列举django的内置组件?
    • 23.列举django中间件的5个方法?以及django中间件的应用场景?
    • 24.简述什么是FBV和CBV?
    • 25.FBV与CBV的区别
    • 26.django的request对象是在什么时候创建的?
    • 27.如何给CBV的程序添加装饰器?
    • 28.列举django orm 中所有的方法(QuerySet对象的所有方法)
    • 29.only和defer的区别?
    • 30.select_related和prefetch_related的区别?
    • 31.filter和exclude的区别?
    • 32.列举django orm中三种能写sql语句的方法。
    • 33.django orm 中如何设置读写分离?
    • 34.F和Q的作用?
    • 35.values和values_list的区别?
    • 36.如何使用django orm批量创建数据?
    • 37.django的Form和ModeForm的作用?
    • 38.django的Form组件中,如果字段中包含choices参数,请使用两种方式实现数据源实时更新。
    • 39.django的Model中的ForeignKey字段中的on_delete参数有什么作用?
    • 40.django中csrf的实现机制?
    • 41.django如何实现websocket?
    • 42.基于django使用ajax发送post请求时,都可以使用哪种方法携带csrf token?
    • 43.django中如何实现orm表中添加数据时创建一条日志记录。
    • 44.django缓存如何设置?
    • 45.django的缓存能使用redis吗?如果可以的话,如何配置?
    • 46.django路由系统中name的作用?
    • 47.django的模板中filter和simple_tag的区别?
    • 48.django-debug-toolbar的作用?
    • 49.django中如何实现单元测试?
    • 50.解释orm中 db first 和 code first的含义?
    • 51.django中如何根据数据库表生成model中的类?
    • 52.使用orm和原生sql的优缺点?
    • 53.简述MVC和MTV
    • 54.django的contenttype组件的作用?
    • 55.谈谈你对restfull 规范的认识?
    • 56.接口的幂等性是什么意思?
    • 57.什么是RPC?
    • 58.Http和Https的区别?
    • 59.为什么要使用django rest framework框架?
    • 60.django rest framework框架中都有那些组件?
    • 61.django rest framework框架中的视图都可以继承哪些类
    • 62.简述 django rest framework框架的认证流程。
    • 63.django rest framework如何实现的用户访问频率控制? 
    • 64.Flask框架的优势?
    • 65.Flask框架依赖组件
    • 66.Flask蓝图的作用
    • 67.列举使用的Flask第三方组件?
    • 68.简述Flask上下文管理流程?
    • 69.Flask中的g的作用?
    • Flask中上下文管理主要涉及到了那些相关的类?并描述类主要作用?
    • 为什么要Flask把Local对象中的的值stack 维护成一个列表?
    • Flask中多app应用是怎么完成?
    • 在Flask中实现WebSocket需要什么组件?
    • wtforms组件的作用?
    • Flask框架默认session处理机制?
    • 解释Flask框架中的Local对象和threading.local对象的区别?
    • Flask中 blinker 是什么?
    • SQLAlchemy中的 session和scoped_session 的区别?
    • SQLAlchemy如何执行原生SQL?
    • ORM的实现原理?
    • DBUtils模块的作用?
    • SQLAchemy中如何为表设置引擎和字符编码?
    • SQLAchemy中如何设置联合唯一索引?
    • 简述Tornado框架的特点。
    • 简述Tornado框架中Future对象的作用?
    • Tornado框架中如何编写WebSocket程序?
    • Tornado中静态文件是如何处理的? 如:
    • Tornado操作MySQL使用的模块?
    • Tornado操作redis使用的模块?
    • 简述Tornado框架的适用场景?
    • git常见命令作用:
    • 简述以下git中stash命令作用以及相关其他命令。
    • git 中 merge 和 rebase命令 的区别。
    • 公司如何基于git做的协同开发?
    • 如何基于git实现代码review?
    • git如何实现v1.0 、v2.0 等版本的管理?
    • 什么是gitlab
    • github和gitlab的区别?
    • 如何为github上牛逼的开源项目贡献代码?
    • git中 .gitignore文件的作用
    • 什么是敏捷开发?
    • 简述 jenkins 工具的作用?
    • 公司如何实现代码发布?
    • 简述 RabbitMQ、Kafka、ZeroMQ的区别?
    • RabbitMQ如何在消费者获取任务后未处理完前就挂掉时,保证数据不丢失?
    • RabbitMQ如何对消息做持久化?
    • RabbitMQ如何控制消息被消费的顺序?
    • 以下RabbitMQ的exchange type分别代表什么意思?如:fanout、direct、topic。
    • 简述 celery 是什么以及应用场景?
    • 简述celery运行机制。
    • celery如何实现定时任务?
    • 简述 celery多任务结构目录
    • celery中装饰器 @app.task 和 @shared_task的区别?
    • 简述 requests模块的作用及基本使用?
    • 简述 beautifulsoup模块的作用及基本使用?
    • 简述 seleninu模块的作用及基本使用?
    • scrapy框架中各组件的工作流程?
    • 在scrapy框架中如何设置代理(两种方法)?
    • scrapy框架中如何实现大文件的下载?
    • scrapy中如何实现限速?
    • scrapy中如何实现暂停爬虫?
    • scrapy中如何进行自定制命令?
    • scrapy中如何实现的记录爬虫的深度?
    • scrapy中的pipelines工作原理?
    • scrapy的pipelines如何丢弃一个item对象?
    • 简述scrapy中爬虫中间件和下载中间件的作用?1
    • scrapy-redis组件的作用?
    • scrapy-redis组件中如何实现的任务的去重?
    • scrapy-redis的调度器如何实现任务的深度优先和广度优先?....
    • 简述 vitualenv 及应用场景?
    • 简述 pipreqs 及应用场景?
    • 在Python中使用过什么代码检查工具?
    • 简述 saltstack、ansible、fabric、puppet工具的作用?
    • B Tree和B+ Tree的区别?
    • 请列举常见排序并通过代码实现任意三种。
    •  请列举常见查找并通过代码实现任意三种。
    • 请列举你熟悉的设计模式?
    • 有没有刷过leetcode?
    • 列举熟悉的的Linux命令。
    • 公司线上服务器是什么系统?
    • 解释 PV、UV 的含义?
    • 解释 QPS的含义?
    • uwsgi和wsgi的区别?
    • supervisor的作用?
    • 什么是反向代理?
    • 简述SSH的整个过程。
    • 有问题都去那些找解决方案?
    • 是否有关注什么技术类的公众号?
    • 最近在研究什么新技术?
    • 是否了解过领域驱动模型?
  •  
  • 二进制与十进制之间的转换
    • 整数部分

 

正文

回到顶部

Python基础篇

1:为什么学习Python

家里有在这个IT圈子里面,也想让我接触这个圈子,然后给我建议学的Python,
然后自己通过百度和向有学过Python的同学了解了Python,Python这门语言,入门比较简单,
它简单易学,生态圈比较强大,涉及的地方比较多,特别是在人工智能,和数据分析这方面。在未来我觉得是往自动化,
人工智能这方面发展的,所以学习了Python

2:通过什么途径学习Python

刚开始接触Python的时候,到网上里面跟着视频学基础,再后来网上到看技术贴,然后看到有人推荐廖雪峰的Python教程,
练项目到GitHub上面找一些小项目学习。

3:谈谈对Python和其他语言的区别

复制代码
Python属于解释型语言,当程序运行时,是一行一行的解释,并运行,所以调式代码很方便,开发效率高,
还有龟叔给Python定位是任其自由发展、优雅、明确、简单,所以在每个领域都有建树,所有它有着非常强大的第三方库,
特点:
语法简洁优美,功能强大,标准库与第三方库都非常强大,而且应用领域也非常广
可移植性,可扩展性,可嵌入性
缺点:
  运行速度慢,

- 解释型 - python/php - 编译型 - c/java/c#
  • Python弱类型
复制代码

 (1)与java相比:在很多方面,Python比Java要简单,比如java中所有变量必须声明才能使用,而Python不需要声明,用少量的代码构建出很多功能;(高效的高级数据结构)

(2)与php相比:python标准包直接提供了工具,并且相对于PHP代码更易于维护;

(3)Python与c相比:

Python 和 C Python这门语言是由C开发而来

  对于使用:Python的类库齐全并且使用简洁,如果要实现同样的功能,Python 10行代码可以解决,C可能就需要100行甚至更多.
  对于速度:Python的运行速度相较与C,绝逼是慢了

Python的优势:

1、Python 易于学习;

2、用少量的代码构建出很多功能;(高效的高级数据结构)

3、Python 拥有最成熟的程序包资源库之一;

4、Python完全支持面向对象;

5、Python 是跨平台且开源的。

6、动态类型:

4:简述解释型和编译型编程语言

解释型:就是边解释边执行(Python,php)
编译型:编译后再执行(c、java、c#)

5:Python的解释器种类以及相关特点?

复制代码
CPython

是官方版本的解释器:CPython。是使用C语言开发的,所以叫CPython。在命令行下运行python就是启动CPython解释器。
CPython是使用最广的Python解释器。教程的所有代码也都在CPython下执行。

IPython
IPython是基于CPython之上的一个交互式解释器,也就是说,IPython只是在交互方式上有所增强,但是执行Python代码的功能和CPython是完全一样的。CPython用>>>作为提示符,而IPython用In [序号]:作为提示符。
复制代码
复制代码


PyPy

由Python写的解释器,它的执行速度是最快。PyPy采用JIT技术,对Python代码进行动态编译(注意不是解释),
绝大部分Python代码都可以在PyPy下运行,但是PyPy和CPython有一些是不同的,这就导致相同的Python代码在两种解释器下执行可能会有不同的结果。

Jython
Jython是运行在Java平台上的Python解释器,可以直接把Python代码编译成Java字节码执行。

IronPython
IronPython和Jython类似,只不过IronPython是运行在.Net平台上的Python解释器,可以直接把Python代码编译成.Net的字节码。

小结:
  Python的解释器很多,但使用最广泛的还是CPython。如果要和Java或.Net平台交互,最好的办法不是用Jython或IronPython,而是通过网络调用来交互,确保各程序之间的独立性。

复制代码

6:位和字节的关系

1字节 = 8 位
位(bit),数据存储是以“字节”(Byte)为单位,数据传输是以大多是以“位”(bit,又名“比特”)为单位,
一个位就代表一个0或1(即一个二进制),二进制是构成存储器的最小单位,每8个位(bit,简写为b)组成一个字节(Byte,简写为B),
字节是最小一级的信息单位

7:b、B、KB、MB、GB的关系

b --->位(bit)    

B --->字节      一个字节等于8位

1B = 8 bit

1kb = 1024 B

1 MB = 1024 KB

1 GB = 1024 MB

8:PE8规范

复制代码
1、使用4个空格而不是tab键进行缩进。
2、每行长度不能超过79
3、使用空行来间隔函数和类,以及函数内部的大块代码
4、必要时候,在每一行下写注释
5、使用文档注释,写出函数注释
6、在操作符和逗号之后使用空格,但是不要在括号内部使用
7、命名类和函数的时候使用一致的方式,比如使用CamelCase来命名类,
           使用lower_case_with_underscores来命名函数和方法
8、在类中总是使用self来作为默认
 9、尽量不要使用魔法方法
10、默认使用UTF-8,甚至ASCII作为编码方式
11、换行可以使用反斜杠,最好使用圆括号。
12、不要在一句import中多个库,
空格的使用
  1. 各种右括号前不要加空格。
  2. 逗号、冒号、分号前不要加空格。
  3. 函数的左括号前不要加空格。如Func(1)
  4. 序列的左括号前不要加空格。如list[2]
  5. 操作符左右各加一个空格,不要为了对齐增加空格
  6. 函数默认参数使用的赋值符左右省略空格
  7. 不要将多句语句写在同一行,尽管使用‘;’允许
  8. if/for/while语句中,即使执行语句只有一句,也必须另起一行
 函数命名使用全部小写的方式,常量命名使用大写,类属性(方法和变量)使用小写
类的命名首字母大写
复制代码

9:通过代码实现如下转换(进制之间转换)

复制代码
# 二进制转换成十进制-->int
v = "0b1111011"
b = int(v,2)
print(b)  # 123

十进制转换成二进制—>bin

v2 = 18
print(bin(int(v2)))

0b10010

八进制转换成十进制

v3 = “011”
print(int(v3))

11

十进制转换成八进制:—> oct

v4 = 30
print(oct(int(v4)))

0o36

十六进制转换成十进制:

v5 = “0x12”
print(int(v5,16))

18

十进制转换成十六进制:—> hex

v6 = 87
print(hex(int(v6)))

0x57

复制代码

10:请编写一个函数实现将IP地址转换成一个整数

复制代码
请编写一个函数实现将IP地址转换成一个整数。
如 10.3.9.12 转换规则为:
        10            00001010
     3            00000011

     9            00001001

    12            00001100

再将以上二进制拼接起来计算十进制结果:00001010 00000011 00001001 00001100 = ?

def v1(addr):
# 取每个数
id = [int(x) for x in addr.split(".")]
print(id)
return sum(id[i] << [24, 16, 8, 0][i] for i in range(4))

print(v1(“127.0.0.1”))

[127, 0, 0, 1]

2130706433

复制代码

------------------------------------------------

11、python递归的最大层数?998

12:求结果(and or or)

复制代码
1. 求结果:1 or 3
print(1 or 3)  # 1
  1. 求结果:1 and 3
    print(1 and 3) # 3

  2. 求结果:0 and 2 and 1
    print(0 and 2 and 1) # 0

  3. 求结果:0 and 2 or 1
    print(0 and 2 or 1) # 1

  4. 求结果:0 and 2 or 1 or 4
    print(0 and 2 or 1 or 4) # 1

  5. 求结果:0 or Flase and 1
    print(0 or False and 1) # Flase

总结:
  # x or y 如果 x为真,则值为x, 否则为y
  # x and y 如果 x 为真,则值为 y,否则为 x

复制代码

运算符

1. 求结果:2 & 5

print(2 & 5)  # 10 & 101 => 000 => 0

2. 求结果:2 ^ 5

print(2 ^ 5)  # 10 ^ 101 => 111 => 1*2**0+1*2**1+1*2**2=1+2+4=7

13 :ascii、unicode、utf-8、gbk 区别

复制代码
python2内容进行编码(默认ascii),而python3对内容进行编码的默认为utf-8。
ascii   最多只能用8位来表示(一个字节),即:2**8 = 256,所以,ASCII码最多只能表示 256 个符号。
unicode  万国码,任何一个字符==两个字节
utf-8     万国码的升级版  一个中文字符==三个字节   英文是一个字节  欧洲的是 2个字节
gbk       国内版本  一个中文字符==2个字节   英文是一个字节
gbk 转 utf-8  需通过媒介 unicode
复制代码

14:字节码和机器码的区别

机器码,学名机器语言指令,有时也被称为原生码,是电脑的CPU可直接解读的数据。

字节码是一种中间状态(中间码)的二进制代码(文件)。需要直译器转译后才能成为机器码。

复制代码
什么是机器码

机器码(machine code),学名机器语言指令,有时也被称为原生码(Native Code),是电脑的CPU可直接解读的数据。
通常意义上来理解的话,机器码就是计算机可以直接执行,并且执行速度最快的代码。

总结:机器码是电脑CPU直接读取运行的机器指令,运行速度最快,但是非常晦涩难懂,也比较难编写

什么是字节码
字节码(Bytecode)是一种包含执行程序、由一序列 op 代码/数据对 组成的二进制文件。
字节码是一种中间码,它比机器码更抽象,需要直译器转译后才能成为机器码的中间代码。

总结:字节码是一种中间状态(中间码)的二进制代码(文件)。需要直译器转译后才能成为机器码。

复制代码

-----------

复制代码
#is  比较的是内存地址
#== 比较的是值
# int     具有范围:-5---256
#对于int 小数据池
 范围:-5----256 创建的相间的数字,都指向同一个内存地址

#对于字符串 (面试)
1、小数据池 如果有空格,那指向两个内存地址,
2、长度不能超过 20
3、不能用特殊字符

i = ‘a’*20
j = ‘a’*20
print(i is j) # True

i = “a”*21
j = “a”*21
print(i is j) # False

关于编码所占字节
unicode: 所有字符(无论英文、中文等) 1个字符:2个字节
gbk:一个字符,英文1个字节,中文两个字节
utf-8:英文1个字节、 欧洲:2个字节, 亚洲:3个字节

在utf-8中,一个中文字符占用3个字节
在gbk中一个汉字占用2个字节
黎诗 = utf-8(6字节)=48
黎诗 = gbk(4字节)=32

字节和位的关系。
  #一个字节(byte) = 8 位(bit)
  # 位为最小的单位

简述变量命名规范
  #1、以字母,数字,下划线任由结合
  #2、不能以命名太长,不使用拼音,中文
  #3、不能以数字开头
  #4、不能用关键词

复制代码

15:三元运算写法和应用场景?

复制代码
应用场景:简化if语句
# 关于三元运算 # 结果+ if + 条件 + else + 结果 result='gt' if 1>3 else 'lt' print(result) # lt # 理解:如果条件为真,把if前面的值赋值给变量,否则把else后面的值赋值给变量。

lambda 表达式
temp = lambda x,y:x+y
print(temp(4,10)) # 14

可替代:
def foo(x,y):
return x+y
print(foo(4,10)) # 14

复制代码

16:Python3和Python2的区别?

复制代码
1:打印时,py2需要可以不需要加括号,py3 需要
python 2 :print ('lili')   ,   print 'lili'
python 3 : print ('lili')   
python3 必须加括号

exec语句被python3废弃,统一使用exec函数

2:内涵
Python2:1,臃肿,源码的重复量很多。
  2,语法不清晰,掺杂着C,php,Java,的一些陋习。
Python3:几乎是重构后的源码,规范,清晰,优美。

3、输出中文的区别
python2:要输出中文 需加 # -- encoding:utf-8 --
Python3 : 直接搞

4:input不同
python2 :raw_input
python3 :input 统一使用input函数

5:指定字节
python2在编译安装时,可以通过参数-----enable-unicode=ucs2 或-----enable-unicode=ucs4分别用于指定使用2个字节、4个字节表示一个unicode;
python3无法进行选择,默认使用 ucs4
查看当前python中表示unicode字符串时占用的空间:

impor sys
print(sys.maxunicode)
#如果值是65535,则表示使用usc2标准,即:2个字节表示
#如果值是1114111,则表示使用usc4标准,即:4个字节表示

6:
py2:xrange
    range
py3:range 统一使用range,Python3中range的机制也进行修改并提高了大数据集生成效率

7:在包的知识点里
包:一群模块文件的集合 + init
区别:py2 : 必须有__init__
   py3:不是必须的了

8:不相等操作符"<>“被Python3废弃,统一使用”!="

9:long整数类型被Python3废弃,统一使用int

10:迭代器iterator的next()函数被Python3废弃,统一使用next(iterator)

11:异常StandardError 被Python3废弃,统一使用Exception

12:字典变量的has_key函数被Python废弃,统一使用in关键词

13:file函数被Python3废弃,统一使用open来处理文件,可以通过io.IOBase检查文件类型

复制代码

17:用一行代码实现数值交换

a = 1 
b = 2

a, b = b, a

18:Python3和Python2中int和long区别

在python3里,只有一种整数类型int,大多数情况下,和python2中的长整型类似。

19:xrange和range的区别

都在循环时使用,xrange内存性能更好,xrange用法与range完全相同,range一个生成list对象,xrange是生成器

要生成很大的数字序列的时候,用xrange会比range性能优很多,因为不需要一上来就开辟一块很大的内存空间。

在python2中:

range([start,] stop[, step]),根据start与stop指定的范围以及step设定的步长,生成一个序列

例子

xrange用法与range完全相同,所不同的是生成的不是一个数组,而是一个生成器。

例子

由上面的示例可以知道:要生成很大的数字序列的时候,用xrange会比range性能优很多,因为不需要一上来就开辟一块很大的内存空间,这两个基本上都是在循环的时候用。

在 Python 3 中,range() 是像 xrange() 那样实现,xrange()被抛弃。

20:文件操作时:xreadlines和readlines的区别?

readlines     返回一个列表

xreadlines   返回一个生成器

21: 列列举布尔值为False的常见值?

0,“”,{},[],(),set()
0 Flask 负数 不成立的表达式  None 等

22. 字符串、列表、元组、字典每个常用的5个方法?

复制代码
字符串:
字符串用单引号(')或双引号(")括起来,不可变 1,find通过元素找索引,可切片,找不到返回-1 2,index,找不到报错。 3,split 由字符串分割成列表,默认按空格。 4,captalize 首字母大写,其他字母小写。 5,upper 全大写。 6,lower 全小写。 7,title,每个单词的首字母大写。 8,startswith 判断以什么为开头,可以切片,整体概念。 9,endswith 判断以什么为结尾,可以切片,整体概念。 10,format格式化输出
#format的三种玩法 格式化输出
res='{} {} {}'.format('egon',18,'male') ==> egon 18 male
res='{1} {0} {1}'.format('egon',18,'male') ==> 18 egon 18
res='{name} {age} {sex}'.format(sex='male',name='egon',age=18)
11,strip 默认去掉两侧空格,有条件, 12,lstrip,rstrip 14,center 居中,默认空格。 
15,count查找元素的个数,可以切片,若没有返回0
16,expandtabs 将一个tab键变成8个空格,如果tab前面的字符长度不足8个,则补全8个,
17,replace(old,new,次数)
18,isdigit 字符串由字母或数字组成 isalpha, 字符串只由字母组成 isalnum 字符串只由数字组成
19,swapcase 大小写翻转
20,for i in 可迭代对象。
字典:
1无序(不能索引)2:数据关联性强3:键值对,键值对。唯一一个映射数据类型。 #字典的键必须是可哈希的 不可变类型。 在同一个字典中,键(key)必须是唯一的。

列表是有序的对象集合,字典是无序的对象集合。两者之间的区别在于:字典当中的元素是通过键来存取的,而不是通过偏移存取 key: 输出所有的键 clear:清空 dic:删除的键如果没有则报错 pop:键值对删,有返回,没有原来的键会报错(自行设置返回键就不会报错) popitem:随机删键值对 del:删除的键如果没有则报错 改 update 查 用get时。不会报错# 没有可以返回设定的返回值 注意: 1、字典是一种映射类型,它的元素是键值对。 2、字典的关键字必须为不可变类型,且不能重复。 3、创建空字典使用 { }。 列表:
索引,切片,加,乘,检查成员。 增加:有三种, append:在后面添加。 Insert按照索引添加, expend:迭代着添加。 list.extend(seq) - 在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表) pop 删除 (pop 有返回值) remove 可以按照元素去删 clear 清空列表 del 1、可以按照索引去删除 2、切片 3、步长(隔着删) 改 1、索引 2、切片:先删除,再迭代着添加 list.count(obj) - 统计某个元素在列表中出现的次数 list.index(obj) - 从列表中找出某个值第一个匹配项的索引位置 list.reverse() - 反向列表中元素 list.sort([func]) - 对原列表进行排序 注意: 1、List写在方括号之间,元素用逗号隔开。 2、和字符串一样,list可以被索引和切片。 3、List可以使用+操作符进行拼接。 4、List中的元素是可以改变的。 元组:
()元组的元素不能修改 1、cmp(tuple1, tuple2):比较两个元组元素。 2、len(tuple):计算元组元素个数。 3、max(tuple):返回元组中元素最大值。 4、min(tuple):返回元组中元素最小值。 5、tuple(seq):将列表转换为元组。 注意 1、与字符串一样,元组的元素不能修改。 2、元组也可以被索引和切片,方法一样。 3、注意构造包含0或1个元素的元组的特殊语法规则。 4、元组也可以使用+操作符进行拼接。
Set(集合)
:集合(set )是一个无序不重复元素的序列。 可以使用大括号 { } 或者 set() 函数创建集合,注意:创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典。
复制代码

23、 lambda表达式格式以及应用场景?

复制代码
匿名函数:为了解决那些功能很简单的需求而设计的一句话函数
函数名 = lambda 参数 :返回值

#参数可以有多个,用逗号隔开
#匿名函数不管逻辑多复杂,只能写一行,且逻辑执行结束后的内容就是返回值
#返回值和正常的函数一样可以是任意数据类型

lambda 表达式
temp = lambda x,y:x+y
print(temp(4,10)) # 14

可替代:
def foo(x,y):
return x+y
print(foo(4,10)) # 14

复制代码

24. pass的作用

pass是空语句,是为了保持程序结构的完整性。pass 不做任何事情,一般用做占位语句。

25. *arg和**kwarg作用

 *args代表位置参数,它会接收任意多个参数并把这些参数作为元祖传递给函数。
**kwargs代表的关键字参数,返回的是字典,位置参数一定要放在关键字前面

26. is和==的区别

复制代码
a = 'lishi'
str1 = "li"
str2 = "shi"
str3 = str1 + str2
print("a == str3",a == str3)
print("a is str3",a is str3) print("id(a)",id(a)) print("id(str3)",id(str3)) # a == str3 True == ---> 只需要内容相等 # a is str3 False is ---> 只需要内存地址相等 # id(a) 38565848 # id(str3) 39110280
复制代码
is 比较的是两个实例对象是不是完全相同,它们是不是同一个对象,占用的内存地址是否相同。

== 比较的是两个对象的内容是否相等,即内存地址可以不一样,内容一样就可以了。默认会调用对象的 eq()方法。

27:谈谈Python的深浅拷贝?以及实现方法和应用场景。

浅拷贝只是增加了一个指针指向一个存在的地址,

而深拷贝是增加一个指针并且开辟了新的内存,这个增加的指针指向这个新的内存,
采用浅拷贝的情况,释放内存,会释放同一内存,深拷贝就不会出现释放同一内存的错误

一层的情况:

复制代码
import copy

浅拷贝

li1 = [1, 2, 3]
li2 = li1.copy()
li1.append(4)
print(li1, li2) # [1, 2, 3, 4] [1, 2, 3]

深拷贝

li1 = [1, 2, 3]
li2 = copy.deepcopy(li1)
li1.append(4)
print(li1, li2) # [1, 2, 3, 4] [1, 2, 3]

复制代码

多层的情况:

复制代码
import copy

浅拷贝 指向共有的地址

li1 = [1, 2, 3,[4,5],6]
li2 = li1.copy()
li1[3].append(7)
print(li1, li2) # [1, 2, 3, [4, 5, 7], 6] [1, 2, 3, [4, 5, 7], 6]

深拷贝 重指向

li1 = [1, 2, 3,[4,5],6]
li2 = copy.deepcopy(li1)
li1[3].append(7)
print(li1, li2) # [1, 2, 3, [4, 5, 7], 6] [1, 2, 3, [4, 5], 6]

复制代码

28. Python垃圾回收机制?

引用计数

标记清除

分代回收

29. Python的可变类型和不可变类型?

可变数据类型:列表、字典、可变集合

不可变数据类型:数字、字符串、元组、不可变集合

30、求结果

def multipliers():
    return [lambda x:i*x for i in range(4)]
print([m(2) for m in multipliers()])
复制代码
def a():
    return [lambda x:i*x for i in range(4)]
b=a()   #返回个列表函数
# b[2](1)

print(b1)

print(type(b),b)

print([m(1) for m in a()])
print([i*i for i in [1,2,3]])
[3, 3, 3, 3]
[1, 4, 9]

‘’’
def multipliers():
return [lambda x:i*x for i in range(4)]
print([m(2) for m in multipliers()])
#解释:
  函数返回值为一个列表表达式,经过4次循环结果为包含四个lambda函数的列表,
由于函数未被调用,循环中的i值未被写入函数,经过多次替代,循环结束后i值为3,
故结果为:6,6,6,6

func=lambda x:x+1
print(func(1))
#2
print(func(2))
#3

#以上lambda等同于以下函数
def func(x):
return(x+1)
‘’’

复制代码
请修改multipliers的定义来产生期望的结果(0,2,4,6)。
def multipliers():
    return (lambda x:i*x for i in range(4))         #返回一个生成器表达式
print([m(2) for m in multipliers()])
复制代码
-面试题2:
现有两个元组(('a'),('b')),(('c'),('d')),请使用python中匿名函数生成列表[{'a':'c'},{'b':'d'}]

#匿名函数形式:
l1=((‘a’),(‘b’))
l2=((‘c’),(‘d’))
ret=map(lambda n:{n[0]:n[1]},zip(l1,l2))
print(list(ret))
#列表表达式形式:
l1=((‘a’),(‘b’))
l2=((‘c’),(‘d’))
print([{n[0]:n[1]} for n in zip(l1,l2)])

复制代码

31、求结果

复制代码
v = dict.fromkeys(['k1', 'k2'], [])
v['k1'].append(666)
print(v)
v['k1'] = 777
print(v)

结果:
{‘k1’: [666], ‘k2’: [666]}
{‘k1’: 777, ‘k2’: [666]}

解释:
Python 字典(Dictionary) fromkeys() 函数用于创建一个新字典,以序列seq中元素做字典的键,value为字典所有键对应的初始值,默认为None。

v1 = dict.fromkeys([‘k1’, ‘k2’])
print(v1) # {‘k1’: None, ‘k2’: None}

v2 = dict.fromkeys([‘k1’, ‘k2’], [])
print(v2) # {‘k1’: [], ‘k2’: []}

复制代码

32、列举常见的内置函数

abs()

返回数字的绝对值

map

复制代码
根据函数对指定序列做映射
map()函数接收两个参数,一个是函数,一个是可迭代对象,map将传入的函数依次作用到序列的每个元素,并把结果作为新的list返回。

返回值:
  Python2 返回列表
  Python3 返回迭代器

例子1: def mul(x): return x*x n=[1,2,3,4,5] res=list(map(mul,n)) print(res) #[1, 4, 9, 16, 25]

例子2:abs() 返回数字的绝对值
ret = map(abs,[-1,-5,6,-7])
print(list(ret))
# [1, 5, 6, 7]
复制代码

filter

复制代码
filter()函数接收一个函数 f(函数)和一个list(可迭代对象),这个函数 f的作用是对每个元素进行判断,返回 True或 False,
filter()根据判断结果自动过滤掉不符合条件的元素,返回由符合条件元素组成的新list。
def is_odd(x):
    return x % 2 == 1

v=list(filter(is_odd, [1, 4, 6, 7, 9, 12, 17]))
print(v) #[1, 7, 9, 17]

复制代码

map与filter总结

复制代码
# filter 与 map 总结
# 参数: 都是一个函数名 + 可迭代对象
# 返回值: 都是返回可迭代对象
# 区别:
# filter 是做筛选的,结果还是原来就在可迭代对象中的项
# map 是对可迭代对象中每一项做操作的,结果不一定是原来就在可迭代对象中的项
复制代码

isinstance\type

复制代码
isinstance() 函数来判断一个对象是否是一个已知的类型,类似 type()。
isinstance() 与 type() 区别:
type() 不会认为子类是一种父类类型,不考虑继承关系。
isinstance() 会认为子类是一种父类类型,考虑继承关系。
如果要判断两个类型是否相同推荐使用 isinstance()。
# 例一
a = 2
print(isinstance(a,int)) # True
print(isinstance(a,str)) # False

type() 与 isinstance() 区别

class A:
pass

class B(A):
pass

print(“isinstance”,isinstance(A(),A)) # isinstance True
print(“type”,type(A()) == A) # type True

print(‘isinstance’,isinstance(B(),A) ) # isinstance True
print(‘type’,type(B()) == A) # type False

复制代码

zip 拉链函数

复制代码
# zip 拉链函数,
# 将对象中对应的元素打包成一个个元组,
# 然后返回由这些元组组成的列表迭代器。
# 如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同。
print(list(zip([0,1,3],[5,6,7],['a','b'])))
# [(0, 5, 'a'), (1, 6, 'b')]
复制代码
复制代码
zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
>>>a = [1,2,3]
>>> b = [4,5,6]
>>> c = [4,5,6,7,8]
>>> zipped = zip(a,b)     # 打包为元组的列表
[(1, 4), (2, 5), (3, 6)] >>> zip(a,c) # 元素个数与最短的列表一致 [(1, 4), (2, 5), (3, 6)] >>> zip(*zipped) # 与 zip 相反,可理解为解压,返回二维矩阵式 [(1, 2, 3), (4, 5, 6)]
复制代码

reduce

复制代码
'''
reduce()  函数
reduce() 函数会对参数序列中元素进行累积
函数将一个数据集合(链表、元组等)中的所有数据进行下列操作
'''

注意:
Python3已经将reduce() 函数从全局名字空间里移除了,它现在被放置在 fucntools 模块里,如果想要使用它,则需要通过引入 functools 模块来调用 reduce() 函数:

from functools import reduce
def add(x,y):
return x + y

print(reduce(add,[1,2,3,4,5]))

15

print(reduce(lambda x, y: x+y, [1,2,3,4,5])) # 15

print(reduce(add,range(1,101)))

5050

复制代码

33. filter、map、reduce的作用?

内置函数:map、reduce、filter的用法和区别

map:根据函数对指定序列做映射

复制代码
map
参数
接收两个参数:一个是函数,一个是序列(可迭代对象)
返回值
Python2 返回列表
Python3 返回迭代器

例子:

abs() 函数返回数字的绝对值

新的内容的个数等于原内容的个数

ret = map(abs,[-1,-5,6,-7])

print(list(ret))

[1, 5, 6, 7]

复制代码

filter:过滤函数 新的内容少于等于原内容的时候。才能使用filter

复制代码
filter() 函数用于过滤序列,过滤不符合条件的元素,返回由符合条件元素组成的心列表

参数:
function 函数
iterable 可迭代对象
返回值:
返回列表

筛选大于10的数

def is_odd(x):
if x>10:
return True

ret = filter(is_odd,[1,4,5,7,8,9,76]) # 为迭代器
print(list(ret))

[76]

复制代码

reduce:对于序列内所有元素进行累计操作

复制代码
'''
reduce()  函数
reduce() 函数会对参数序列中元素进行累积
函数将一个数据集合(链表、元组等)中的所有数据进行下列操作
'''

from functools import reduce
def add(x,y):
return x + y

print(reduce(add,[1,2,3,4,5]))

15

print(reduce(lambda x, y: x+y, [1,2,3,4,5])) # 15

print(reduce(add,range(1,101)))

5050

复制代码

34、 一行代码实现9*9乘法表

print('\n'.join([' '.join(['%s*%s=%-2s' % (j, i, i * j) for j in range(1, i + 1)]) for i in range(1, 10)]))

35. 如何安装第三方模块?以及用过哪些第三方模块?

复制代码
1:pip包管理器
2:源码下载
    -下载
    -解压
-python setup.py build
-python setup.py install
复制代码

用过的第三方模块:requests,pymysql,DbUtils,SQLAlchemy等

36、 常用模块都有那些?

re模块,os模块,json模块,time模块,

爬虫里面的requests/beautifulsoup4(bs4)

37. re的match和search区别?

re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。

re.search 扫描整个字符串并返回第一个成功的匹配。

38. 什么是正则的贪婪匹配?

匹配一个字符串没有节制,能匹配多少就去匹配多少,知道没有匹配的为止

39. 求结果:

a. [ i % 2 for i in range(10) ]

print([ i % 2 for i in range(10) ])  # [0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
print([ i  for i in range(10) ])     # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print([ 10 % 2])   # [0]
# %是个运算符。

b. ( i % 2 for i in range(10) )

复制代码
print(( i % 2 for i in range(10) ))
#   at 0x00000000020CEEB8> 生成器
# 在Python中,有一种自定义迭代器的方式,称为生成器(Generator)。
# 定义生成器的两种方式:
# 1.创建一个generator,只要把一个列表生成式的[]改成(),就创建了一个generator:
# generator保存的是算法,每次调用next(),就计算出下一个元素的值,直到计算到最后一个元素,
没有更多的元素时,抛出StopIteration的错误。 # 2.定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,
而是一个generator
复制代码

40. 求结果:

a. 1 or 2
b. 1 and 2
c. 1 < (2==2)
d. 1 < 2 == 2

复制代码
>>> 1 or 2
1
>>> 1 and 2
2
>>> 1 < (2==2)
False
>>> 1 < 2 == 2
True
复制代码

 41、def func(a,b=[]) 这种写法有什什么坑?

复制代码
def func(a,b = []):
    b.append(1)
    print(a,b)

func(a=2)
func(2)
func(2)

‘’’
2 [1]
2 [1, 1]
2 [1, 1, 1]
函数的默认参数是一个list 当第一次执行的时候实例化了一个list
第二次执行还是用第一次执行的时候实例化的地址存储
所以三次执行的结果就是 [1, 1, 1] 想每次执行只输出[1] ,默认参数应该设置为None
‘’’

复制代码

42、如何实现 “1,2,3” 变成 [‘1’,’2’,’3’]

list("1,2,3".split(','))

43. 如何实现[‘1’,’2’,’3’]变成[1,2,3]

复制代码
[int(x) for x in ['1','2','3']]

python 里如何把[‘1’,‘2’,‘3’] 变成[1,2,3]

a = [‘1’,‘2’,‘3’]
b = [int(i) for i in a]
print(b)

[1, 2, 3]

复制代码

44. a = [1,2,3] 和 b = [(1),(2),(3) ] 以及 b = [(1,),(2,),(3,) ] 的区别?

 补充:

 
  
复制代码
a=[1,2,3,4,5],b=a和b=a[:],有区别么?

a = [1,2,3,4,5]
b = a
b1 = a[:]
print(b) # [1, 2, 3, 4, 5]

print(b) # [1, 2, 3, 4, 5]

b.append(6) print("a",a) # a [1, 2, 3, 4, 5, 6] print("b",b) # b [1, 2, 3, 4, 5, 6] 传递引用 print("b1",b1) # b1 [1, 2, 3, 4, 5] 拷贝
复制代码
# 一个列表A=[2,3,4],Python如何将其转换成B=[(2,3),(3,4),(4,2)]?
# B = zip(A, A[1:]+A[:1])

45. 如何用一行代码生成[1,4,9,16,25,36,49,64,81,100]

[i*i for i in range(1,11)]

46. 一行代码实现删除列表中重复的值

list(set([1, 2, 3, 4, 45, 1, 2, 343, 2, 2]))

47. 如何在函数中设置一个全局变量

python中的global语句是被用来声明全局变量的。

复制代码
x = 2
def func():
    global x
    x = 1
    return x
func()
print(x)  # 1
复制代码

48. logging模块的作用?以及应用场景?

复制代码
logging 
模块定义的函数和类为应用程序和库的开发实现了一个灵活的事件日志系统

作用:可以了解程序运行情况,是否正常
    在程序的出现故障快速定位出错地方及故障分析

复制代码

49. 请用代码简答实现stack

  • Stack() 创建一个新的空栈
  • push(item) 添加一个新的元素item到栈顶
  • pop() 弹出栈顶元素
  • peek() 返回栈顶元素
  • is_empty() 判断栈是否为空
  • size() 返回栈的元素个数
复制代码
# 实现一个栈stack,后进先出

‘’’
class Stack:
def init(self):
self.items = []

def is_empty(self):
    # 判断是否为空
    return self.items == []

def push(self,item):
    # 加入元素
    self.items.append(item)

def pop(self):
    # 弹出元素
    return self.items.pop()

def peek(self):
    # 返回栈顶元素
    return self.items[len(self.items)-1]

def size(self):
    # 返回栈的大小
    return len(self.items)

if name == “main”:
stack = Stack()
stack.push(“H”)
stack.push(“E”)
stack.push(“L”)
print(stack.size()) # 3
print(stack.peek()) # L
print(stack.pop()) # L
print(stack.pop()) # E
print(stack.pop()) # H
‘’’

复制代码

50. 常用字符串格式化哪几种?

1.占位符%

%d 表示那个位置是整数;%f 表示浮点数;%s 表示字符串。

print('Hello,%s' % 'Python')
print('Hello,%d%s%.2f' % (666, 'Python', 9.99)) # 打印:Hello,666Python10.00

2.format

print('{k} is {v}'.format(k='python', v='easy'))  # 通过关键字
print('{0} is {1}'.format('python', 'easy'))      # 通过关键字

51. 简述 生成器、迭代器、可迭代对象 以及应用场景?

迭代器

含有__iter__和__next__方法 (包含__next__方法的可迭代对象就是迭代器)

生成器

:包括含有yield这个关键字,生成器也是迭代器,调动next把函数变成迭代器。

复制代码
应用场景:
range/xrange
    - py2: range(1000000)  ,会立即创建,xrange(1000000)生成器
    - py3:range(10000000)生成器 

- redis获取值
conn = Redis(...)

    def hscan_iter(self, name, match=None, count=None):
      """
      Make an iterator using the HSCAN command so that the client doesn't
      need to remember the cursor position.

      ``match`` allows for filtering the keys by pattern

      ``count`` allows for hint the minimum number of returns
      """
      cursor = '0'
      while cursor != 0:
        # 去redis中获取数据:12
        # cursor,下一次取的位置
        # data:本地获取的12条数数据
        cursor, data = self.hscan(name, cursor=cursor,match=match, count=count)
        for item in data.items():
          yield item

stark组件

def index(request):

    data = [
      {'k1':1,'name':'alex'},
      {'k1':2,'name':'老男孩'},
      {'k1':3,'name':'小男孩'},
    ]
    new_data = []
    for item in data:
      item['email'] = "[email protected]"
      new_data.append(item)

    return render(request,'xx.html',{'data':new_data})

 
复制代码

可迭代对象

 一个类内部实现__iter__方法且返回一个迭代器。

复制代码
应用场景: 
    - wtforms中对form对象进行循环时候,显示form中包含的所有字段。
        class LoginForm(Form):
            name = simple.StringField(
                label='用户名',
                validators=[ validators.DataRequired(message='用户名不能为空.'), validators.Length(min=6, max=18, message='用户名长度必须大于%(min)d且小于%(max)d') ], widget=widgets.TextInput(), render_kw={'class': 'form-control'} ) pwd = simple.PasswordField( label='密码', validators=[ validators.DataRequired(message='密码不能为空.'), validators.Length(min=8, message='用户名长度必须大于%(min)d'), validators.Regexp(regex="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&])[A-Za-z\d$@$!%*?&]{8,}", message='密码至少8个字符,至少1个大写字母,1个小写字母,1个数字和1个特殊字符') 
            ],
            widget=widgets.PasswordInput(),
            render_kw={'class': 'form-control'}
        )

    
    form = LoginForm()
    for item in form:
        print(item)
        
- 列表、字典、元组
复制代码

装饰器

复制代码
 装饰器:
能够在不修改原函数代码的基础上,在执行前后进行定制操作,闭包函数的一种应用
场景:
   - flask路由系统
   - flask before_request
   - csrf
   - django内置认证
   - django缓存 # 手写装饰器; import functools def wrapper(func): @functools.wraps(func) #不改变原函数属性 def inner(*args, **kwargs): 执行函数前 return func(*args, **kwargs) 执行函数后 return inner 1. 执行wapper函数,并将被装饰的函数当做参数。 wapper(index) 2. 将第一步的返回值,重新赋值给 新index = wapper(老index) @wrapper #index=wrapper(index) def index(x): return x+100
复制代码

调用装饰器其实是一个闭包函数,为其他函数添加附加功能,不修改被修改的源代码和不修改被修饰的方式,装饰器的返回值也是一个函数对象。
比如:插入日志、性能测试、事物处理、缓存、权限验证等,有了装饰器,就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。

 52. 用Python实现一个二分查找的函数。

二分查找算法:简单的说,就是将一个列表先排序好,比如按照从小到大的顺序排列好,当给定一个数据,比如3,查找3在列表中的位置时,可以先找到列表中间的数li[middle]和3进行比较,当它比3小时,那么3一定是在列表的右边,反之,则3在列表的左边,比如它比3小,则下次就可以只比较[middle+1, end]的数,继续使用二分法,将它一分为二,直到找到3这个数返回或者列表全部遍历完成(3不在列表中) 

优点:效率高,时间复杂度为O(logN); 
缺点:数据要是有序的,顺序存储。

复制代码
li = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

def search(someone, li):
l = -1
h = len(li)

while l + 1 != h:
    m = int((l + h) / 2)
    if li[m] < someone:
        l = m
    else:
        h = m
p = h
if p >= len(li) or li[p] != someone:
    print("元素不存在")
else:
    str = "元素索引为%d" % p
    print(str)

search(3, li) # 元素索引为2

复制代码

53. 谈谈你对闭包的理解?

复制代码
ef foo():
    m=3
    n=5
    def bar():
        a=4
        return m+n+a
    return bar

>>>bar = foo()
>>>bar()
12

复制代码

说明:
bar在foo函数的代码块中定义。我们称bar是foo的内部函数。
在bar的局部作用域中可以直接访问foo局部作用域中定义的m、n变量。
简单的说,这种内部函数可以使用外部函数变量的行为,就叫闭包。

闭包的意义与应用

54. os和sys模块的作用?

os模块负责程序与操作系统的交互,提供了访问操作系统底层的接口;
sys模块负责程序与python解释器的交互,提供了一系列的函数和变量,用于操控python的运行时环境。

复制代码
os与sys模块的官方解释如下:
os: This module provides a portable way of using operating system dependent functionality.
这个模块提供了一种方便的使用操作系统函数的方法。
sys: This module provides access to some variables used or maintained by the interpreter and to 
functions that interact strongly with the interpreter. 这个模块可供访问由解释器使用或维护的变量和与解释器进行交互的函数。 os 常用方法 os.remove() 删除文件 os.rename() 重命名文件 os.walk() 生成目录树下的所有文件名 os.chdir() 改变目录 os.mkdir/makedirs 创建目录/多层目录 os.rmdir/removedirs 删除目录/多层目录 os.listdir() 列出指定目录的文件 os.getcwd() 取得当前工作目录 os.chmod() 改变目录权限 os.path.basename() 去掉目录路径,返回文件名 os.path.dirname() 去掉文件名,返回目录路径 os.path.join() 将分离的各部分组合成一个路径名 os.path.split() 返回( dirname(), basename())元组 os.path.splitext() 返回 (filename, extension) 元组 os.path.getatime\ctime\mtime 分别返回最近访问、创建、修改时间 os.path.getsize() 返回文件大小 os.path.exists() 是否存在 os.path.isabs() 是否为绝对路径 os.path.isdir() 是否为目录 os.path.isfile() 是否为文件 sys 常用方法 sys.argv 命令行参数List,第一个元素是程序本身路径 sys.modules.keys() 返回所有已经导入的模块列表 sys.exc_info() 获取当前正在处理的异常类,exc_type、exc_value、exc_traceback当前处理的异常详细信息 sys.exit(n) 退出程序,正常退出时exit(0) sys.hexversion 获取Python解释程序的版本值,16进制格式如:0x020403F0 sys.version 获取Python解释程序的版本信息 sys.maxint 最大的Int值 sys.maxunicode 最大的Unicode值 sys.modules 返回系统导入的模块字段,key是模块名,value是模块 sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值 sys.platform 返回操作系统平台名称 sys.stdout 标准输出 sys.stdin 标准输入 sys.stderr 错误输出 sys.exc_clear() 用来清除当前线程所出现的当前的或最近的错误信息 sys.exec_prefix 返回平台独立的python文件安装的位置 sys.byteorder 本地字节规则的指示器,big-endian平台的值是'big',little-endian平台的值是'little' sys.copyright 记录python版权相关的东西 sys.api_version 解释器的C的API版本 总结: os模块负责程序与操作系统的交互,提供了访问操作系统底层的接口;
sys模块负责程序与python解释器的交互,提供了一系列的函数和变量,用于操控python的运行时环境。
复制代码

55. 如何生成一个随机数?

import random

print(random.random()) # 用于生成一个0到1的随机符点数: 0 <= n < 1.0
print(random.randint(1, 1000)) # 用于生成一个指定范围内的整数

56. 如何使用python删除一个文件?

复制代码
import os
file = r'D:\test.txt'
if os.path.exists(file):
    os.remove(file)
    print('delete success')
else:
    print('no such file:%s' % file)
复制代码

57. 谈谈你对面向对象的理解

三大特性以及解释?

面对对象是一种编程思想,以类的眼光来来看待事物的一种方式。将有共同的属性和方法的事物封装到同一个类下面。

继承:将多个类的共同属性和方法封装到一个父类下面,然后在用这些类来继承这个类的属性和方法

封装:将有共同的属性和方法封装到同一个类下面

  • 第一层面:创建类和对象会分别创建二者的名称空间,我们只能用类名.或者obj.的方式去访问里面的名字,这本身就是一种封装
  • 第二层面:类中把某些属性和方法隐藏起来(或者说定义成私有的),只在类的内部使用、外部无法访问,或者留下少量接口(函数)供外部访问。

多态:Python天生是支持多态的。指的是基类的同一个方法在不同的派生类中有着不同的功能

58. Python面向对象中的继承有什么特点

复制代码
继承概念的实现方式主要有2类:实现继承、接口继承。
     实现继承是指使用基类的属性和方法而无需额外编码的能力;
     接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力(子类重构爹类方法);

python 两种类:经典类 新式类
python3 新式类 —— 都默认继承object class Animal(object): == class Animal:
python2 经典类和新式类 并存
class Animal: 经典类 —— 继承顺序 个别使用方法
class Animal(object): 新式类

继承分为单继承和多继承
Python是支持多继承的
如果没有指定基类,python的类会默认继承object类,object是所有python类的基类,它提供了一些常见方法(如__str__)的实现。

复制代码

补充继承的应用(面试题)

复制代码
1、对象可以调用自己本类和父类的所有方法和属性, 先调用自己的 自己没有才调父类的。谁(对象)调用方法,方法中的self就指向谁

class Foo:
def init(self):
self.func()

def func(self):
    print('Foo.func')

class Son(Foo):
def func(self):
print(‘Son.func’)

s = Son()

Son.func

========================================================
class A:
def get(self):
self.say()

def say(self):
    print('AAAAA')

class B(A):
def say(self):
print(‘BBBBB’)

b = B()
b.get() #输出结果为:BBBBB

复制代码

59. 面向对象深度优先和广度优先是什么?

Python的类可以继承多个类,Python的类如果继承了多个类,那么其寻找方法的方式有两种
当类是经典类时,多继承情况下,会按照深度优先方式查找  py3
当类是新式类时,多继承情况下,会按照广度优先方式查找  py2
简单点说就是:经典类是纵向查找,新式类是横向查找
经典类和新式类的区别就是,在声明类的时候,新式类需要加上object关键字。在python3中默认全是新式类

60. 面向对象中super的作用?

用于子类继承基类的方法
复制代码
class FooParent(object):
    def __init__(self):
        self.parent = 'I\'m the parent.'
        print('Parent')
        print('1111')
def bar(self, message):
    print("%s from Parent" % message)

class FooChild(FooParent):
def init(self):
# super(FooChild,self) 首先找到 FooChild 的父类(就是类 FooParent),然后把类B的对象 FooChild 转换为类 FooParent 的对象
super(FooChild, self).init()
print(‘Child’)

# def bar(self, message):
#     # super(FooChild, self).bar(message)
#     print('Child bar fuction')
#     print(self.parent)

if name == ‘main’:
fooChild = FooChild()
fooChild.bar(‘HelloWorld’)

复制代码

61. 是否使用过functools中的函数?其作用是什么?

用于修复装饰器

复制代码
import functools

def deco(func):
@functools.wraps(func) # 加在最内层函数正上方
def wrapper(*args, **kwargs):
return func(*args, **kwargs)

return wrapper

@deco
def index():
‘’‘哈哈哈哈’’’
x = 10
print(‘from index’)

print(index.name)
print(index.doc)

加@functools.wraps

index

哈哈哈哈

不加@functools.wraps

wrapper

None

复制代码

62. 列举面向对象中带双下划线的特殊方法,如:__new__、__init__

  • __new__:生成实例
  • __init__:生成实例的属性
  • __call__:实例对象加( )会执行def __call__:... 方法里边的内容。

    __del__:析构方法,当对象在内存中被释放时,自动触发执行。如当 del obj 或者应用程序运行完毕时,执行该方法里边的内容。

    __enter__和__exit__:出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量;with中代码块执行完毕时执行__exit__里边的内容。

    __module__:表示当前操作的对象在那个模块   obj.__module__
    __class__ :表示当前操作的对象的类是什么     obj.__class__

    __doc__:类的描述信息,该描述信息无法被继承

    __str__:改变对象的字符串显示 print函数 --->obj.__str__()
    __repr__:改变对象的字符串显示 交互式解释器 --->obj.__repr__()
    __format__:自定制格式化字符串

    __slots__:一个类变量 用来限制实例可以添加的属性的数量和类型  

    __setitem__,__getitem,__delitem__:

复制代码
class Foo:
    def __init__(self,name):
        self.name=name
def __getitem__(self, item):
    print(self.__dict__[item])

def __setitem__(self, key, value):
    self.__dict__[key]=value
def __delitem__(self, key):
    print('del obj[key]时,我执行')
    self.__dict__.pop(key)
def __delattr__(self, item):
    print('del obj.key时,我执行')
    self.__dict__.pop(item)

f1=Foo(‘sb’)
f1[‘age’]=18
f1[‘age1’]=19
del f1.age1
del f1[‘age’]
f1[‘name’]=‘alex’
print(f1.dict)

复制代码

__get__():调用一个属性时,触发
__set__():为一个属性赋值时,触发
__delete__():采用del删除属性时,触发

__setattr__,__delattr__,__getattr__ :

63. 如何判断是函数还是方法?

看他的调用者是谁,如果是类,就需要传入一个参数self的值,这时他就是一个函数,

如果调用者是对象,就不需要给self传入参数值,这时他就是一个方法

print(isinstance(obj.func, FunctionType))   # False

print(isinstance(obj.func, MethodType))    # True

复制代码
class Foo(object):
    def __init__(self):
        self.name = 'lcg'
def func(self):
    print(self.name)

obj = Foo()
print(obj.func) # main.Foo object at 0x000001ABC0F15F98>>

print(Foo.func) #

------------------------FunctionType, MethodType------------#

from types import FunctionType, MethodType

obj = Foo()
print(isinstance(obj.func, FunctionType)) # False
print(isinstance(obj.func, MethodType)) # True

print(isinstance(Foo.func, FunctionType)) # True
print(isinstance(Foo.func, MethodType)) # False

------------------------------------------------------------#

obj = Foo()
Foo.func(obj) # lcg

obj = Foo()
obj.func() # lcg

“”"
注意:
方法,无需传入self参数
函数,必须手动传入self参数
“”"

复制代码

64. 静态方法和类方法区别?

尽管 classmethod 和 staticmethod 非常相似,但在用法上依然有一些明显的区别。classmethod 必须有一个指向类对象的引用作为第一个参数,而 staticmethod 可以没有任何参数。

举个栗子:

复制代码
class Num:
    # 普通方法:能用Num调用而不能用实例化对象调用   
    def one():  
        print ('1')
# 实例方法:能用实例化对象调用而不能用Num调用
def two(self):
    print ('2')

# 静态方法:能用Num和实例化对象调用
@staticmethod 
def three():  
    print ('3')

# 类方法:第一个参数cls长什么样不重要,都是指Num类本身,调用时将Num类作为对象隐式地传入方法   
@classmethod 
def go(cls): 
    cls.three() 

Num.one() #1
#Num.two() #TypeError: two() missing 1 required positional argument: ‘self’
Num.three() #3
Num.go() #3

i=Num()
#i.one() #TypeError: one() takes 0 positional arguments but 1 was given
i.two() #2
i.three() #3
i.go() #3

复制代码

65. 列举面向对象中的特殊成员以及应用场景

复制代码
__call__

new

init

doc

class

del

dict

str

在falsk源码用到…

复制代码

66. 1、2、3、4、5 能组成多少个互不相同且无重复的三位数

60个

题意理解:组成后的数值不相同,且组合的三个位数之间数字不重复。

使用python内置的排列组合函数(不放回抽样排列)

product 笛卡尔积  (有放回抽样排列)

permutations 排列  (不放回抽样排列)

combinations 组合,没有重复  (不放回抽样组合)

combinations_with_replacement 组合,有重复  (有放回抽样组合)

import itertools

print(len(list(itertools.permutations(‘12345’, 3)))) # 60

67. 什么是反射?以及应⽤用场景?

反射的核心本质就是以字符串的形式去导入个模块,利用字符串的形式去执行函数。

Django中的 CBV就是基于反射实现的。

68. metaclass作用?以及应用场景?

metaclass用来指定类是由谁创建的。

类的metaclass 默认是type。我们也可以指定类的metaclass值。在python3中:

复制代码
class MyType(type):
    def __call__(self, *args, **kwargs):
        return 'MyType'

class Foo(object, metaclass=MyType):
def init(self):
return ‘init’

def __new__(cls, *args, **kwargs):
    return cls.__init__(cls)

def __call__(self, *args, **kwargs):
    return 'call'

obj = Foo()
print(obj) # MyType

复制代码

 

69. 用尽量多的方法实现单例模式。

复制代码
1:使用模块
Python的模块就是天然的单例模式。
因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。
因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。
例如:
class V1(object):
    def foo(self)
        pass
V1 = V1()
将上面代码保存在文件test.py,要使用时,直接在其他文件中导入此文件中的对象,这个对象既是单例模式的对象

如:from a import V1

2:使用装饰器
def Singleton(cls):
_instance = {}
def _singleton(*args, **kargs):
if cls not in _instance:
_instance[cls] = cls(*args, **kargs)
return _instance[cls]
return _singleton
@Singleton
class A(object):
a = 1
def init(self, x=0):
self.x = x
a1 = A(2)
a2 = A(3)

3:使用类

4:基于__new__方法实现
当我们实例化一个对象时,是先执行了类的__new__方法
当:(我们没写时,默认调用object.new),实例化对象;然后再执行类的__init__方法,对这个对象进行初始化,所有我们可以基于这个,实现单例模式

复制代码

70. 装饰器器的写法以及应用场景。

含义:装饰器本质就是函数,为其他函数添加附加功能

原则:

不修改被修饰函数的代码

不修改被修饰函数的调用方式

应用场景:

无参装饰器在用户登录 认证中常见

有参装饰器在flask的路由系统中见到过

复制代码
import functools
def wrapper(func):
    @functools.wraps(func)
    def inner(*args, **kwargs):
        print('我是装饰器')
        return func
return inner 

@wrapper
def index():
print(‘我是被装饰函数’)
return None
index()

应用场景

- 高阶函数
- 闭包
- 装饰器 
- functools.wraps(func)
复制代码

71. 异常处理写法以及如何主动跑出异常(应用场景)

复制代码
# 触发异常
def temp_convert(var):
    try:
        return int(var)
    except ValueError as Argument:
        print ("参数没有包含数字%s"%Argument)

调用函数

temp_convert(“xyz”)

以10为基数的int()的无效文字:“xyz”


----------------------------------------------------------------------------

raise语法

#raise [Exception [, args [, traceback]]]

语句中 Exception 是异常的类型,args 是自已提供的异常参数。

class Networkerror(RuntimeError):
def init(self, arg):
self.args = arg
try:
raise Networkerror(“Bad hostname”)
except Networkerror as e:
print(e.args)

复制代码

72、什么是面向对象的mro

mro就是方法解析顺序

73. isinstance作用以及应用场景?

isinstance(对象,类)  判断这个对象是不是这个类或者这个类的子类的实例化

复制代码
# # 判断a 属不属于A这个类(可以判断到祖宗类)
class A:
    pass

class B(A):
pass
a = A()
b = B()
print(isinstance(b,A)) # ===> True 判断到祖宗类

任何与object都是True,内部都继承object

class A:pass
a = A() # 实例化
print(isinstance(a,object)) # True

复制代码

应用场景:rest framework 认证的流程

scrapy-redis

74. 写代码并实现

Given an array of integers, return indices of the two numbers such that they add up to a
specific target.You may assume that each input would have exactly one solution, and you may
not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1]

75. json序列化时,可以处理的数据类型有哪些?如何定制支持datetime类型?


76. json序列化时,默认遇到中文会转换成unicode,如果想要保留中文怎么办?

 在序列化时,中文汉字总是被转换为unicode码,在dumps函数中添加参数ensure_ascii=False即可解决。

77. 什么是断言?应用场景?

复制代码
assert 是的作用?断言
条件成立(布尔值为True)则继续往下,否则跑出异常,一般用于:满足某个条件之后,才能执行,否则应该跑出异常。

写API的时候,继承GenericAPIView

class GenericAPIView(views.APIView):
“”"
Base class for all other generic views.
“”"
# You’ll need to either set these attributes,
# or override get_queryset()/get_serializer_class().
# If you are overriding a view method, it is important that you call
# get_queryset() instead of accessing the queryset property directly,
# as queryset will get evaluated only once, and those results are cached
# for all subsequent requests.
queryset = None
serializer_class = None

                # If you want to use object lookups other than pk, set 'lookup_field'.
                # For more complex lookup requirements override `get_object()`.
                lookup_field = 'pk'
                lookup_url_kwarg = None

                # The filter backend classes to use for queryset filtering
                filter_backends = api_settings.DEFAULT_FILTER_BACKENDS

                # The style to use for queryset pagination.
                pagination_class = api_settings.DEFAULT_PAGINATION_CLASS

                def get_queryset(self):

                    assert self.queryset is not None, (
                        "'%s' should either include a `queryset` attribute, "
                        "or override the `get_queryset()` method."
                        % self.__class__.__name__
                    )

                    queryset = self.queryset
                    if isinstance(queryset, QuerySet):
                        # Ensure queryset is re-evaluated on each request.
                        queryset = queryset.all()
                    return queryset
复制代码

78. 有用过with statement吗?它的好处是什么?


79. 使用代码实现查看列举目录下的所有文件。


80. 简述 yield和yield from关键字

回到顶部

第二部分 网络编程和并发

81. 简述 OSI 七层协议。

 

物理层:主要是基于电器特性发送高低电压(电信号),高电压对应数字1,低电压对应数字0

数据链路层:定义了电信号的分组方式

网路层:引入一套新的地址用来区分不同的广播域/子网,这套地址即网络地址

传输层:建立端口到端口的通信

会话层:建立客户端与服务端连接

表示层:对来自应用层的命令和数据进行解释,按照一定格式传给会话层。如编码、数据格式转换、加密解密、压缩解压
应用层:规定应用程序的数据格式

82. 什么是C/S和B/S架构?

c/s架构,就是client(客户端)与server(服务端)即:客户端与服务端的架构。

b/s架构,就是brosver(浏览器端)与sever(服务端)即:浏览器端与服务端架构

优点:统一了所有应用程序的入口、方便、轻量级

83. 简述 三次握手、四次挥手的流程。

复制代码
三次握手:
    第一次握手
1:客户端先向服务端发起一次询问建立连接的请求,并随机生成一个值作为标识
    第二次握手
2:服务端向客户端先回应第一个标识,再重新发一个确认标识
    第三次握手
3:客户端确认标识,建立连接,开始传输数据
    
复制代码
复制代码
四次挥手 ---> 断开连接
第一次挥手
    客户端向服务端发起请求断开连接的请求
第二次挥手
    服务端向客户端确认请求
第三次挥手
    服务端向客户端发起断开连接请求
第四次挥手
    客户端向服务端确认断开请求
复制代码

84. TCP和UDP的区别?

TCP/UDP区别
 TCP协议是面向连接,保证高可靠性传输层协议
 UDP:数据丢失,无秩序的传输层协议(qq基于udp协议)

85. 为何基于tcp协议的通信比基于udp协议的通信更可靠?

tcp:可靠,因为只要对方回了确认收到信息,才发下一个,如果没收到确认信息就重发
UDP:不可靠,它是一直发数据,不需要对方回应
流式协议: TCP协议,可靠传输
数据报协议: UDP协议,不可传输

86. 什么是socket?简述基于tcp协议的套接字通信流程。

复制代码
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。
在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,
对用户来说,一组简单的接口就是全部。

服务端:
创建socket对象,
绑定ip端口bind(),
设置最大链接数listen(),
accept()与客户端的connect()创建双向管道,等到联接,
send(), recv(), 收发数据
close()

客户端:
创建socket对象,
connect()与服务端accept()创建双向管道 ,
send(),
recv(),
close()

复制代码

87. 什么是粘包? socket 中造成粘包的原因是什什么? 哪些情况会发生粘包现象?

复制代码
只有TCP有粘包现象,UDP永远不会粘包
粘包
:在获取数据时,出现数据的内容不是本应该接收的数据,如:对方第一次发送hello,第二次发送world,
  我方接收时,应该收两次,一次是hello,一次是world,但事实上是一次收到helloworld,一次收到空,这种现象叫粘包

原因
粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的。

什么情况会发生
1、发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据了很小,会合到一起,产生粘包)

2、接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,
服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包)

复制代码

88. IO多路复的作用?

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

与多进程和多线程技术相比,I/O多路复用技术的最大优势是系统开销小,系统不必创建进程/线程,也不必维护这些进程/线程,从而大大减小了系统的开销。

89.select、poll、epoll 模型的区别?(属于多路复用IO的模型)

复制代码
都是i/o多路复用的机制,监视多个socket是否发生变化,本质上都是同步i/o
    select,poll实现需要自己不断轮询所有监测对象,直到对象发生变化,在这个阶段中,
可能要睡眠和唤醒多次交替,而epoll也需要调用epoll_wait不断轮询就绪链表,但是当对象发生变化时,
会调用回调函数,将变化的对象放入就绪链接表中,并唤醒在epoll_wait中进入睡眠的进程。
虽然都会睡眠和唤醒,但是select和poll在被唤醒的时候要遍历整个监测对象集合,
而epoll只要判断就绪链表是否为空即可,节省了大量cpu的时间
复制代码
复制代码
 select、poll、epoll都是IO多路复用的机制,但select,poll,epoll本质上都是同步I/O,
 因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的.

FD(文件描述符)
select模型
优点:
1:可移植性好,在某些Unix系统不支持poll()
2:对于超时值提供了更好的精度:微妙,而poll是毫秒
缺点:
1:最大并发数限制,因为一个进程所打开的 FD (文件描述符)是有限制的,由 FD_SETSIZE 设置,默认值是 1024/2048 ,因此 Select 模型的最大并发数就被相应限制了。
2:效率问题,select每次调用都会线性扫描全部的FD集合,所以将FD_SETSIZE 改大,会越慢
3:需要维护一个用来存放大量fd的数据结构,这样会使得用户空间和内核空间在传递该结构时复制开销大。

poll本质上和select 没有区别,它将用户传入的数组拷贝到内核空间,
它没有最大连接数的限制,原因是它基于链表来存储的但是同样有一个缺点:
大量的fd的数组被整体复制于用户态和内核地址空间,而不管这样的复制是不是有意义

复制代码

90. 什么是防火墙以及作用?

复制代码
防火墙是一个分离器、一个限制器,也是一个分析器,有效地监控了内部网和Internet之间的任何活动,保证了内部网络的安全

作用
防火墙是网络安全的屏障
可以强化网络安全策略
对网络存取和访问进行监控审计
防止内部信息的外泄
除了安全作用,防火墙还支持具有Internet服务特性的企业内部网络技术体系VPN(虚拟专用网)。

复制代码

91. 简述 进程、线程、协程的区别 以及应用场景?

复制代码
线程是指进程内的一个执行单元,
# 进程
进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度。
# 线程
线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度
# 协程和线程
协程避免了无意义的调度,由此可以提高性能;但同时协程也失去了线程使用多CPU的能力

进程与线程的区别
(1)地址空间:线程是进程内的一个执行单位,进程内至少有一个线程,他们共享进程的地址空间,而进程有自己独立的地址空间
(2)资源拥有:进程是资源分配和拥有的单位,同一个进程内线程共享进程的资源
(3)线程是处理器调度的基本单位,但进程不是
(4)二者均可并发执行
(5)每个独立的线程有一个程序运行的入口

协程与线程
(1)一个线程可以有多个协程,一个进程也可以单独拥有多个协程,这样Python中则能使用多核CPU
(2)线程进程都是同步机制,而协程是异步
(3)协程能保留上一次调用时的状态

复制代码

92. GIL锁是什么?

GIL本质就是一把互斥锁,既然是互斥锁,所有互斥锁的本质都一样,都是将并发运行变成串行,以此来控制同一时间内共享数据只能被一个任务所修改,进而保证数据安全。

GIL保护的是解释器级的数据,保护用户自己的数据则需要自己加锁处理

复制代码
应用(总结):
多线程用于IO密集型,如socket,爬虫,web
多进程用于计算密集型,如金融分析
  1. 每个cpython进程内都有一个GIL
  2. GIL导致同一进程内多个进程同一时间只能有一个运行
  3. 之所以有GIL,是因为Cpython的内存管理不是线程安全的
  4. 对于计算密集型用多进程,多IO密集型用多线程
复制代码

93. Python中如何使用线程池和进程池?


94. threading.local的作用?

实现线程局部变量的传递。

ThreadLocal 最常用的地方:
为每个线程绑定一个资源(数据库连接,HTTP请求,用户身份信息等),这样一个线程的所有调用到的处理函数都可以非常方便地访问这些资源。

95. 进程之间如何进行通信?


96. 什么是并发和并行?

# 并发:同一时刻只能处理一个任务,但一个时段内可以对多个任务进行交替处理(一个处理器同时处理多个任务)
# 并行:同一时刻可以处理多个任务(多个处理器或者是多核的处理器同时处理多个不同的任务)
# 类比:并发是一个人同时吃三个馒头,而并行是三个人同时吃三个馒头。 

97. 进程锁和线程锁的作用?


98. 解释什么是异步非阻塞?

复制代码
非阻塞:不等待
即:遇到IO阻塞不等待(setblooking=False),(可能会报错->捕捉异常)
        - sk=socket.socket()
        - sk.setblooking(False)
异步:回调,当达到某个指定的状态之后,自动调用特定函数

实例
nb_async.py 实现异步非阻塞的模块

复制代码
异步体现在回调上,回调就是有消息返回时告知一声儿进程进行处理。非阻塞就是不等待,不需要进程等待下去,继续执行其他操作,不管其他进程的状态。

99. 路由器和交换机的区别

复制代码
1:交换机:是负责内网里面的数据传递(arp协议)根据MAC地址寻址
   路由器:在网络层,路由器根据路由表,寻找该ip的网段
2:路由器可以处理TCP/IP协议
3:路由器可以把一个IP分配给很多个主机使用,这些主机对外只表现出一个IP。
   交换机可以把很多主机连起来,这些主机对外各有各的IP。
4:交换机是做端口扩展的,也就是让局域网可以连进来更多的电脑。
  路由器是用来做网络连接,也就是;连接不同的网络
复制代码

100.什么是域名解析?

在互联网上,所有的地址都是ip地址,现阶段主要是IPv4(比如:110.110.110.110)。
但是这些ip地址太难记了,所以就出现了域名(比如http://baidu.com)。
域名解析就是将域名,转换为ip地址的这样一种行为。

101.如何修改本地hosts件?

复制代码
Hosts是一个没有扩展名的系统文件,可以用记事本等工具打开,其作用就是将一些常用的网址域名与其对应的IP地址建立一个关联“数据库”,
当用户在浏览器中输入一个需要登录的网址时,系统会首先自动从Hosts文件中寻找对应的IP地址,
一旦找到,系统会立即打开对应网页,如果没有找到,则系统会再将网址提交DNS域名解析服务器进行IP地址的解析。

浏览器访问网站,要首先通过DNS服务器把要访问的网站域名解析成一个唯一的IP地址,之后,浏览器才能对此网站进行定位并且访问其数据。

文件路径:C:\WINDOWS\system32\drivers\etc。
将127.0.0.1 www.163.com 添加在最下面
修改后用浏览器访问“www.163.com”会被解析到127.0.0.1,导致无法显示该网页。

复制代码

102.生产者消费者模型应用场景及优势?

复制代码
生产者与消费者模式是通过一个容器来解决生产者与消费者的强耦合关系,生产者与消费者之间不直接进行通讯,
而是利用阻塞队列来进行通讯,生产者生成数据后直接丢给阻塞队列,消费者需要数据则从阻塞队列获取,
实际应用中,生产者与消费者模式则主要解决生产者与消费者生产与消费的速率不一致的问题,达到平衡生产者与消费者的处理能力,而阻塞队列则相当于缓冲区。

应用场景:用户提交订单,订单进入引擎的阻塞队列中,由专门的线程从阻塞队列中获取数据并处理

优势:
1;解耦
假设生产者和消费者分别是两个类。如果让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合)。
将来如果消费者的代码发生变化,可能会影响到生产者。而如果两者都依赖于某个缓冲区,两者之间不直接依赖,耦合也就相应降低了。
2:支持并发
生产者直接调用消费者的某个方法,还有另一个弊端。由于函数调用是同步的(或者叫阻塞的),在消费者的方法没有返回之前,生产者只能一直等着
而使用这个模型,生产者把制造出来的数据只需要放在缓冲区即可,不需要等待消费者来取

3:支持忙闲不均
缓冲区还有另一个好处。如果制造数据的速度时快时慢,缓冲区的好处就体现出来了。
当数据制造快的时候,消费者来不及处理,未处理的数据可以暂时存在缓冲区中。等生产者的制造速度慢下来,消费者再慢慢处理掉。

复制代码

103.什么是cdn?

目的是使用户可以就近到服务器取得所需内容,解决 Internet网络拥挤的状况,提高用户访问网站的响应速度。

cdn 即内容分发网络

104.LVS是什么及作用?

复制代码
LVS :Linux虚拟服务器
作用:LVS主要用于多服务器的负载均衡。
它工作在网络层,可以实现高性能,高可用的服务器集群技术。
它廉价,可把许多低性能的服务器组合在一起形成一个超级服务器。
它易用,配置非常简单,且有多种负载均衡的方法。
它稳定可靠,即使在集群的服务器中某台服务器无法正常工作,也不影响整体效果。另外可扩展性也非常好。
复制代码

105.Nginx是什么及作用?


106.keepalived是什么及作用?


107.haproxy是什么以及作用?


108.什么是负载均衡?


109.什么是rpc及应用场景?


110.简述 asynio模块的作用和应用场景。


111.简述 gevent模块的作用和应用场景。


112.twisted框架的使用和应用

回到顶部

数据库和缓存(46题)

113.列举常见的关系型数据库和非关系型都有那些?

复制代码
关系型数据库(需要有表结构)
    mysql、oracle 、 spl、server、db2、sybase

非关系型数据库(是以key-value存储的,没有表结构)(NoSQL)
MongoDB
MongoDB 是一个高性能,开源,无模式的文档型数据库,开发语言是C++。它在许多场景下可用于替代传统的关系型数据库或键/值存储方式。
Redis
Redis 是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。目前由VMware主持开发工作。

复制代码

114.MySQL常见数据库引擎及比较?

复制代码
InnoDB 
支持事务
支持表锁、行锁(for update)
表锁:select * from tb for update
行锁:select id,name from tb where id=2 for update

myisam
查询速度快
全文索引
支持表锁
表锁:select * from tb for update

NDB
高可用、 高性能、高可扩展性的数据库集群系统

Memory
默认使用的是哈希索引

复制代码

115.简述数据库三大范式?

复制代码
 数据库的三大特性:
'实体':表
'属性':表中的数据(字段)
'关系':表与表之间的关系
----------------------------------------------------
# 数据库设计三大范式:
1:确保每列保持原子性(即数据库表中的所有字段值是不可分解的原子值)

2:确保表中的每列都是和主键相关(表中只能保存一种数据,不可以把多种数据保存在同一张表中)—>完全属于当前表的数据

3:确保每列都和主键直接相关,而不是间接相关(在一个数据库表中保存的数据只能与主键相关)----> 消除传递依赖(间接)
比如在设计一个订单数据表的时候,可以将客户编号作为一个外键和订单表建立相应的关系。
而不可以在订单表中添加关于客户其它信息(比如姓名、所属公司等)的字段。

复制代码
复制代码
数据库五大约束'
    1.primary KEY:设置主键约束;
    2.UNIQUE:设置唯一性约束,不能有重复值;
3.DEFAULT 默认值约束    
4.NOT NULL:设置非空约束,该字段不能为空;
    5.FOREIGN key :设置外键约束。
复制代码

116、什么是事务?MySQL如何支持事务?

复制代码
事务用于将某些操作的多个SQL作为原子性操作,一旦有某一个出现错误,即可回滚到原来的状态,从而保证数据库数据完整性。

事务的特性:
原子性: 确保工作单元内的所有操作都成功完成,否则事务将被中止在故障点,和以前的操作将回滚到以前的状态。
一致性: 确保数据库正确地改变状态后,成功提交的事务。
隔离性: 使事务操作彼此独立的和透明的。
持久性: 确保提交的事务的结果或效果的系统出现故障的情况下仍然存在。

Mysql实现事务
InnoDB支持事务,MyISAM不支持
# 启动事务:
# start transaction;
# update from account set money=money-100 where name=‘a’;
# update from account set money=money+100 where name=‘b’;
# commit;
‘start transaction 手动开启事务,commit 手动关闭事务’

复制代码

117.简述数据库设计中一对多和多对多的应用场景?

FK(一对多)
下拉框里面的数据就需要用FK关联另一张表

M2M(多对多)
多选的下拉框,或者checkbox

118.如何基于数据库实现商城商品计数器?

119.常见SQL(必备)

复制代码
group by 分组对聚合的条件进行筛选需要通过havhing

SQL的left join 、right join、inner join之间的区别
left join (左连接) 返回包括左表中的所有记录和右表中联结字段相等的记录
right join(右连接) 返回包括右表中的所有记录1和左表中联结字段相等的记录
inner join(内连接): 只返回两个表中联结字段相等的行

复制代码

https://www.cnblogs.com/wupeiqi/articles/5729934.html

120.简述触发器、函数、视图、存储过程?

复制代码
触发器:
对数据库某张表的增加、删除,修改前后定义一些操作

函数:(触发函数是通过select)
聚合函数:max/sum/min/avg
时间格式化:date_format
字符串拼接:concat

存储过程:
将SQL语句保存到数据库中,并命名,以后在代码调用时,直接调用名称即可
参数类型:
  in 只将参数传进去
  out 只拿结果
  inout 既可以传,可以取

函数与存储过程区别:
本质上没区别。只是函数有如:只能返回一个变量的限制。而存储过程可以返回多个。而函数是可以嵌入在sql中使用的,可以在select中调用,而存储过程不行。

视图:
视图是一个虚拟表,不是真实存在的(只能查,不能改)

复制代码

121.MySQL索引种类

复制代码
单列
功能
   普通索引:加速查找
   唯一索引:加速查找 + 约束:不能重复(只能有一个空,不然就重复了)
   主键(primay key):加速查找 + 约束:不能重复 +  不能为空
多列
  联合索引(多个列创建索引)-----> 相当于单列的普通索引
  联合唯一索引            -----> 相当于单列的唯一索引
  ps:联合索引的特点:遵循最左前缀的规则
其他词语:
·· - 索引合并,利用多个单例索引查询;(例如在数据库查用户名和密码,分别给用户名和密码建立索引) - 覆盖索引,在索引表中就能将想要的数据查询到;
复制代码

122.索引在什么情况下遵循最左前缀的规则?

联合索引

123.主键和外键的区别?

主键是能确定一条记录的唯一标示。例如,身份证证号

外键:用于与另一张表的关联,是能确定另一张表记录的字段,用于保持数据的一致性

  主键 外键
定义 唯一标识一条记录,不能有重复的,不允许为空 表的外键是另一张表的主键,外键可以有重复的,可以为空
作用 用来保证数据完整性 用来与其他表建立联系的
个数 主键只能有一个 一个表可以有多个外键

 

 

 

 

 

124.MySQL常见的函数?

复制代码
聚合函数
max/sum/min/avg

时间格式化
date_format

字符串拼接
concat(当拼接了null,则返回null)

截取字符串
substring

返回字节个数
length

复制代码

125.列举 创建索引但是无法命中索引的8种情况。

复制代码
1.- like '%xx'
    select * from tb1 where name like '%cn';
2.- 使用函数
    select * from tb1 where reverse(name) = 'wupeiqi';
3.- or
    select * from tb1 where nid = 1 or email = '[email protected]'; 特别的:当or条件中有未建立索引的列才失效,以下会走索引 select * from tb1 where nid = 1 or name = 'seven'; select * from tb1 where nid = 1 or email = '[email protected]' and name = 'alex' 4.- 类型不一致 如果列是字符串类型,传入条件是必须用引号引起来,不然... select * from tb1 where name = 999; 5.- != select * from tb1 where name != 'alex' 特别的:如果是主键,则还是会走索引 select * from tb1 where nid != 123 6.- > select * from tb1 where name > 'alex' 特别的:如果是主键或索引是整数类型,则还是会走索引 select * from tb1 where nid > 123 select * from tb1 where num > 123 7.- order by select email from tb1 order by name desc; 当根据索引排序时候,选择的映射如果不是索引,则不走索引 特别的:如果对主键排序,则还是走索引: select * from tb1 order by nid desc; 

8.- 组合索引最左前缀
如果组合索引为:(name,email)
name and email – 使用索引
name – 使用索引
email – 不使用索引

复制代码

126.如何开启慢日志查询?

复制代码
修改配置文件
slow_query_log = OFF                            是否开启慢日志记录
long_query_time = 2                              时间限制,超过此时间,则记录
slow_query_log_file = /usr/slow.log        日志文件
log_queries_not_using_indexes = OFF     为使用索引的搜索是否记录

下面是开启
slow_query_log = ON
long_query_time = 2
log_queries_not_using_indexes = OFF
log_queries_not_using_indexes = ON

注:查看当前配置信息:
   show variables like ‘%query%’
修改当前配置:
    set global 变量名 = 值

复制代码

127.数据库导入导出命令(结构+数据)?

复制代码
导出现有数据库数据:(当有提示出入密码。-p就不用加密码)
  mysqldump -u用户名 -p密码 数据库名称 >导出文件路径           # 结构+数据
  mysqldump -u用户名 -p密码 -d 数据库名称 >导出文件    路径       # 结构 

导入现有数据库数据:
    mysqldump -uroot -p密码  数据库名称 < 文件路径  
复制代码

128.数据库优化方案?

复制代码
1、创建数据表时把固定长度的放在前面()
2、将固定数据放入内存: 例如:choice字段 (django中有用到,数字1、2、3…… 对应相应内容)
3、char 和 varchar 的区别(char可变, varchar不可变 )
  
4、联合索引遵循最左前缀(从最左侧开始检索)
5、避免使用 select * 
6、读写分离
    - 实现:两台服务器同步数据     - 利用数据库的主从分离:主,用于删除、修改、更新;从,用于查; 读写分离:利用数据库的主从进行分离:主,用于删除、修改更新;从,用于查 7、分库     - 当数据库中的表太多,将某些表分到不同的数据库,例如:1W张表时     - 代价:连表查询 8、分表     - 水平分表:将某些列拆分到另外一张表,例如:博客+博客详情     - 垂直分表:讲些历史信息分到另外一张表中,例如:支付宝账单 

9、加缓存
    - 利用redis、memcache (常用数据放到缓存里,提高取数据速度)

如果只想获取一条数据
- select * from tb where name=‘alex’ limit 1

复制代码

129.char和varchar的区别?

char 和 varchar 的区别(char可变, varchar不可变 )

130.简述MySQL的执行计划?

查看有没有命中索引,让数据库帮看看运行速度快不快
explain select * from table;

当type为all时,是为全表索引

131.在对name做了唯一索引前提下,简述以下区别:     

    select * from tb where name = ‘Oldboy-Wupeiqi’  
        select * from tb where name = ‘Oldboy-Wupeiqi’ limit 1

复制代码
是这样的的,用where条件过滤出符合条件的数据的同时,进行计数,
比如limit 1,那么在where过滤出第1条数据后,他就会直接把结果select出来返回给你,整个过程就结束了。

没做唯一索引的话,前者查询会全表扫描,效率低些
limit 1,只要找到对应一条数据,就不继续往下扫描.

然而 name 字段添加唯一索引了,加不加limit 1,意义都不大;

复制代码

132.1000w条数据,使用limit offset 分页时,为什么越往后翻越慢?如何解决?

复制代码
  答案一:
      先查主键,在分页。
      select * from tb where id in (
          select id from tb where limit 10 offset 30
      )
  答案二:
      按照也无需求是否可以设置只让用户看200页

答案三:
记录当前页 数据ID最大值和最小值
在翻页时,根据条件先进行筛选;筛选完毕之后,再根据limit offset 查询。

  select * from (select * from tb where id > 22222222) as B limit 10 offset 0
  
  如果用户自己修改页码,也可能导致慢;此时对url种的页码进行加密(rest framework )
复制代码

133.什么是索引合并?

复制代码
1、索引合并是把几个索引的范围扫描合并成一个索引。
2、索引合并的时候,会对索引进行并集,交集或者先交集再并集操作,以便合并成一个索引。
3、这些需要合并的索引只能是一个表的。不能对多表进行索引合并。

简单的说,索引合并,让一条sql可以使用多个索引。对这些索引取交集,并集,或者先取交集再取并集。
从而减少从数据表中取数据的次数,提高查询效率。

复制代码

134.什么是覆盖索引?

在索引表中就能将想要的数据查询到

135.简述数据库读写分离?

- 实现:两台服务器同步数据
    - 利用数据库的主从分离:主,用于删除、修改、更新;从,用于查;
复制代码
方式一:是视图里面用using方式可以进行指定到哪个数据读写
from django.shortcuts import render,HttpResponse
from app01 import models
def index(request):
models.UserType.objects.using('db1').create(title='普通用户')

# 手动指定去某个数据库取数据
result = models.UserType.objects.all().using(‘db1’)
print(result)

return HttpResponse('...')

方式二:写配置文件
class Router1:
  # 指定到某个数据库取数据
def db_for_read(self, model, **hints):
“”"
Attempts to read auth models go to auth_db.
“”"
if model._meta.model_name == ‘usertype’:
return ‘db1’
else:
return ‘default’
   # 指定到某个数据库存数据
def db_for_write(self, model, **hints):
“”"
Attempts to write auth models go to auth_db.
“”"
return ‘default’
再写到配置
DATABASES = {
‘default’: {
‘ENGINE’: ‘django.db.backends.sqlite3’,
‘NAME’: os.path.join(BASE_DIR, ‘db.sqlite3’),
},
‘db1’: {
‘ENGINE’: ‘django.db.backends.sqlite3’,
‘NAME’: os.path.join(BASE_DIR, ‘db.sqlite3’),
}
}
DATABASE_ROUTERS = [‘db_router.Router1’,]

复制代码

136.简述数据库分库分表?(水平、垂直)

复制代码
 1、分库
    当数据库中的表太多,将某些表分到不同数据库,例如:1W张表时
    代价:连表查询跨数据库,代码变多
# 2、分表
    水平分表:将某些列拆分到另一张表,例如:博客+博客详情
    垂直分表:将某些历史信息,分到另外一张表中,例如:支付宝账单
复制代码

137.redis和memcached比较?

复制代码
区别
1:redis不仅支持简单的key_value类型,还支持字典,字符串,列表,集合,有序集合类型
2:内存使用效率对比,使用简单的key-value存储的话,
Memcached的内存利用率更高而如果Redis采用hash结构来做key-value存储,由于其组合式的压缩,其内存利用率会高于Memcached。 3.性能对比:由于Redis只使用单核,而Memcached可以使用多核,.
所以平均每一个核上Redis在存储小数据时比Memcached性能更高。而在100k以上的数据中,Memcached性能要高于Redis, 4.Redis虽然是基于内存的存储系统,但是它本身是支持内存数据的持久化的,而且提供两种主要的持久化策略:RDB快照和AOF日志。
而memcached是不支持数据持久化操作的。 5.集群管理不同,Memcached本身并不支持分布式,因此只能在客户端通过像一致性哈希这样的分布式算法来实现Memcached的分布式存储。
复制代码

138.redis中数据库默认是多少个db 及作用?

Redis默认支持16个数据库,可以通过配置databases来修改这一数字。客户端与Redis建立连接后会自动选择0号数据库,不过可以随时使用SELECT命令更换数据库

Redis支持多个数据库,并且每个数据库的数据是隔离的不能共享,并且基于单机才有,如果是集群就没有数据库的概念。

139.python操作redis的模块?

复制代码
- 连接
- 直接连接:
    import redis 
    r = redis.Redis(host='10.211.55.4', port=6379)
    r.set('foo', 'Bar')
    print r.get('foo')
- 连接池:
    import redis
    pool = redis.ConnectionPool(host='10.211.55.4', port=6379)
r = redis.Redis(connection_pool=pool)
r.set('foo', 'Bar')
print r.get('foo')
复制代码

140.如果redis中的某个列表中的数据量非常大,如果实现循环显示每一个值?

复制代码
    - 如果一个列表在redis中保存了10w个值,我需要将所有值全部循环并显示,请问如何实现?
       一个一个取值,列表没有iter方法,但能自定义
     def list_scan_iter(name,count=3):
            start = 0
            while True:
                result = conn.lrange(name, start, start+count-1)
                start += count
                if not result:
                    break
                for item in result:
                    yield item
    for val in list_scan_iter('num_list'):
        print(val)

场景:投票系统,script-redis

复制代码

141.redis如何实现主从复制?以及数据同步机制?

复制代码
优势:
    - 高可用
    - 分担主压力
注意: 
    - slave设置只读

从的配置文件添加以下记录,即可:
slaveof 1.1.1.1 3306

复制代码

142.redis中的sentinel的作用?

复制代码
   帮助我们自动在主从之间进行切换
    检测主从中 主是否挂掉,且超过一半的sentinel检测到挂了之后才进行进行切换。
    如果主修复好了,再次启动时候,会变成从。
启动主redis:
redis-server /etc/redis-6379.conf  启动主redis
redis-server /etc/redis-6380.conf  启动从redis
    
在linux中:
    找到 /etc/redis-sentinel-8001.conf  配置文件,在内部:
        - 哨兵的端口 port = 8001
        - 主redis的IP,哨兵个数的一半/1
    
    找到 /etc/redis-sentinel-8002.conf  配置文件,在内部:
        - 哨兵的端口 port = 8002
        - 主redis的IP, 1 

    启动两个哨兵   
复制代码

143.如何实现redis集群?

复制代码
 redis集群、分片、分布式redis     
    redis-py-cluster
    集群方案:
        - redis cluster 官方提供的集群方案。
        - codis,豌豆荚技术团队。
        - tweproxy,Twiter技术团队。
    redis cluster的原理?
        - 基于分片来完成。
        - redis将所有能放置数据的地方创建了 16384 个哈希槽。
        - 如果设置集群的话,就可以为每个实例分配哈希槽:
            - 192.168.1.20【0-5000】
            - 192.168.1.21【5001-10000】
            - 192.168.1.22【10001-16384】
        - 以后想要在redis中写值时,
            set k1 123 
将k1通过crc16的算法,将k1转换成一个数字。然后再将该数字和16384求余,如果得到的余数 3000,那么就将该值写入到 192.168.1.20 实例中。
复制代码

144.redis中默认有多少个哈希槽?

16384

145.简述redis的有哪几种持久化策略及比较?

复制代码
RDB:每隔一段时间对redis进行一次持久化。
      - 缺点:数据不完整
      - 优点:速度快
AOF:把所有命令保存起来,如果想到重新生成到redis,那么就要把命令重新执行一次。
      - 缺点:速度慢,文件比较大
      - 优点:数据完整
复制代码

146.列举redis支持的过期策略。

复制代码
  voltile-lru:    从已设置过期时间的数据集(server.db[i].expires)中挑选最近频率最少数据淘汰
  volatile-ttl:   从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
  volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰

allkeys-lru: 从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
allkeys-random: 从数据集(server.db[i].dict)中任意选择数据淘汰
no-enviction(驱逐):禁止驱逐数据

复制代码

147.MySQL 里有 2000w 数据,redis 中只存 20w 的数据,如何保证 redis 中都是热点数据? 

复制代码
  相关知识:redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略(回收策略)。redis 提供 6种数据淘汰策略:

volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
no-enviction(驱逐):禁止驱逐数据

复制代码

148.写代码,基于redis的列表实现 先进先出、后进先出队列、优先级队列。

复制代码
 参看script—redis源码
from scrapy.utils.reqser import request_to_dict, request_from_dict

from . import picklecompat

class Base(object):
“”“Per-spider base queue class”""

  def __init__(self, server, spider, key, serializer=None):
      """Initialize per-spider redis queue.

      Parameters
      ----------
      server : StrictRedis
          Redis client instance.
      spider : Spider
          Scrapy spider instance.
      key: str
          Redis key where to put and get messages.
      serializer : object
          Serializer object with ``loads`` and ``dumps`` methods.

      """
      if serializer is None:
          # Backward compatibility.
          # TODO: deprecate pickle.
          serializer = picklecompat
      if not hasattr(serializer, 'loads'):
          raise TypeError("serializer does not implement 'loads' function: %r"
                          % serializer)
      if not hasattr(serializer, 'dumps'):
          raise TypeError("serializer '%s' does not implement 'dumps' function: %r"
                          % serializer)

      self.server = server
      self.spider = spider
      self.key = key % {'spider': spider.name}
      self.serializer = serializer

  def _encode_request(self, request):
      """Encode a request object"""
      obj = request_to_dict(request, self.spider)
      return self.serializer.dumps(obj)

  def _decode_request(self, encoded_request):
      """Decode an request previously encoded"""
      obj = self.serializer.loads(encoded_request)
      return request_from_dict(obj, self.spider)

  def __len__(self):
      """Return the length of the queue"""
      raise NotImplementedError

  def push(self, request):
      """Push a request"""
      raise NotImplementedError

  def pop(self, timeout=0):
      """Pop a request"""
      raise NotImplementedError

  def clear(self):
      """Clear queue/stack"""
      self.server.delete(self.key)

class FifoQueue(Base):
“”“Per-spider FIFO queue”""

  def __len__(self):
      """Return the length of the queue"""
      return self.server.llen(self.key)

  def push(self, request):
      """Push a request"""
      self.server.lpush(self.key, self._encode_request(request))

  def pop(self, timeout=0):
      """Pop a request"""
      if timeout > 0:
          data = self.server.brpop(self.key, timeout)
          if isinstance(data, tuple):
              data = data[1]
      else:
          data = self.server.rpop(self.key)
      if data:
          return self._decode_request(data)

class PriorityQueue(Base):
“”“Per-spider priority queue abstraction using redis’ sorted set”""

  def __len__(self):
      """Return the length of the queue"""
      return self.server.zcard(self.key)

  def push(self, request):
      """Push a request"""
      data = self._encode_request(request)
      score = -request.priority
      # We don't use zadd method as the order of arguments change depending on
      # whether the class is Redis or StrictRedis, and the option of using
      # kwargs only accepts strings, not bytes.
      self.server.execute_command('ZADD', self.key, score, data)

  def pop(self, timeout=0):
      """
      Pop a request
      timeout not support in this queue class
      """
      # use atomic range/remove using multi/exec
      pipe = self.server.pipeline()
      pipe.multi()
      pipe.zrange(self.key, 0, 0).zremrangebyrank(self.key, 0, 0)
      results, count = pipe.execute()
      if results:
          return self._decode_request(results[0])

class LifoQueue(Base):
“”“Per-spider LIFO queue.”""

  def __len__(self):
      """Return the length of the stack"""
      return self.server.llen(self.key)

  def push(self, request):
      """Push a request"""
      self.server.lpush(self.key, self._encode_request(request))

  def pop(self, timeout=0):
      """Pop a request"""
      if timeout > 0:
          data = self.server.blpop(self.key, timeout)
          if isinstance(data, tuple):
              data = data[1]
      else:
          data = self.server.lpop(self.key)

      if data:
          return self._decode_request(data)

TODO: Deprecate the use of these names.

SpiderQueue = FifoQueue
SpiderStack = LifoQueue
SpiderPriorityQueue = PriorityQueue

复制代码

149.如何基于redis实现消息队列?

复制代码
# 通过发布订阅模式的PUB、SUB实现消息队列
# 发布者发布消息到频道了,频道就是一个消息队列。
# 发布者:
import redis
conn = redis.Redis(host='127.0.0.1',port=6379)
conn.publish('104.9MH', "hahahahahaha")
# 订阅者:
import redis
conn = redis.Redis(host='127.0.0.1',port=6379)
pub = conn.pubsub() pub.subscribe('104.9MH') while True: msg= pub.parse_response() print(msg) 对了,redis 做消息队列不合适 业务上避免过度复用一个redis,用它做缓存、做计算,还做任务队列,压力太大,不好。
复制代码

150.如何基于redis实现发布和订阅?以及发布订阅和消息队列的区别?

复制代码
   发布和订阅,只要有任务就给所有订阅者没人一份
发布者: import redis
  conn = redis.Redis(host='127.0.0.1',port=6379)
  conn.publish('104.9MH', "hahaha")

订阅者:
import redis

  conn = redis.Redis(host='127.0.0.1',port=6379)
  pub = conn.pubsub()
  pub.subscribe('104.9MH')

  while True:
      msg= pub.parse_response()
      print(msg)
复制代码

151.什么是codis及作用?

 Codis 是一个分布式 Redis 解决方案, 对于上层的应用来说, 连接到 Codis Proxy 和连接原生的 Redis Server 没有明显的区别 
(不支持的命令列表), 上层应用可以像使用单机的 Redis 一样使用, Codis 底层会处理请求的转发, 不停机的数据迁移等工作,
所有后边的一切事情, 对于前面的客户端来说是透明的, 可以简单的认为后边连接的是一个内存无限大的 Redis 服务.

152.什么是twemproxy及作用?

  是 Twtter 开源的一个 Redis 和 Memcache 代理服务器,主要用于管理 Redis 和 Memcached 集群,
减少与Cache 服务器直接连接的数量。

153.写代码实现redis事务操作。

复制代码
  import redis

pool = redis.ConnectionPool(host=‘10.211.55.4’, port=6379)

conn = redis.Redis(connection_pool=pool)

pipe = r.pipeline(transaction=False)

pipe = conn.pipeline(transaction=True)

开始事务

pipe.multi()

pipe.set(‘name’, ‘bendere’)
pipe.set(‘role’, ‘sb’)

提交

pipe.execute()

注意:咨询是否当前分布式redis是否支持事务

复制代码

154.redis中的watch的命令的作用?

复制代码
  在Redis的事务中,WATCH命令可用于提供CAS(check-and-set)功能。
假设我们通过WATCH命令在事务执行之前监控了多个Keys,倘若在WATCH之后有任何Key的值发生了变化,
EXEC命令执行的事务都将被放弃,同时返回Null multi-bulk应答以通知调用者事务执行失败。

面试题:你如何控制剩余的数量不会出问题?
方式一:- 通过redis的watch实现
import redis
conn = redis.Redis(host=‘127.0.0.1’,port=6379)

      # conn.set('count',1000)
      val = conn.get('count')
      print(val)

      with conn.pipeline(transaction=True) as pipe:

          # 先监视,自己的值没有被修改过
          conn.watch('count')

          # 事务开始
          pipe.multi()
          old_count = conn.get('count')
          count = int(old_count)
          print('现在剩余的商品有:%s',count)
          input("问媳妇让不让买?")
          pipe.set('count', count - 1)

          # 执行,把所有命令一次性推送过去
          pipe.execute()
 方式二 - 数据库的锁 
复制代码

155.基于redis如何实现商城商品数量计数器?

复制代码
import redis

conn = redis.Redis(host=‘192.168.1.41’,port=6379)

conn.set(‘count’,1000)

with conn.pipeline() as pipe:

# 先监视,自己的值没有被修改过
conn.watch('count')

# 事务开始
pipe.multi()
old_count = conn.get('count')
count = int(old_count)
if count > 0:  # 有库存
    pipe.set('count', count - 1)

# 执行,把所有命令一次性推送过去
pipe.execute()
复制代码

156.简述redis分布式锁和redlock的实现机制。

复制代码
在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段。 
有很多三方库和文章描述如何用Redis实现一个分布式锁管理器,但是这些库实现的方式差别很大
,而且很多简单的实现其实只需采用稍微增加一点复杂的设计就可以获得更好的可靠性。
用Redis实现分布式锁管理器的算法,我们把这个算法称为RedLock。

实现

  • 写值并设置超时时间
  • 超过一半的redis实例设置成功,就表示加锁完成。
  • 使用:安装redlock-py
    from redlock import Redlock

dlm = Redlock(
[
{“host”: “localhost”, “port”: 6379, “db”: 0},
{“host”: “localhost”, “port”: 6379, “db”: 0},
{“host”: “localhost”, “port”: 6379, “db”: 0},
]
)

加锁,acquire

my_lock = dlm.lock(“my_resource_name”,10000)
if my_lock:
# J进行操作
# 解锁,release
dlm.unlock(my_lock)
else:
print(‘获取锁失败’)

复制代码
复制代码
 redis分布式锁?
# 不是单机操作,又多了一/多台机器
# redis内部是单进程、单线程,是数据安全的(只有自己的线程在操作数据)
----------------------------------------------------------------
\A、B、C,三个实例(主)
1、来了一个'隔壁老王'要操作,且不想让别人操作,so,加锁;
    加锁:'隔壁老王'自己生成一个随机字符串,设置到A、B、C里(xxx=666)
2、来了一个'邻居老李'要操作A、B、C,一读发现里面有字符串,擦,被加锁了,不能操作了,等着吧~
3、'隔壁老王'解决完问题,不用锁了,把A、B、C里的key:'xxx'删掉;完成解锁
4、'邻居老李'现在可以访问,可以加锁了 # 问题: 1、如果'隔壁老王'加锁后突然挂了,就没人解锁,就死锁了,其他人干看着没法用咋办? 2、如果'隔壁老王'去给A、B、C加锁的过程中,刚加到A,'邻居老李'就去操作C了,加锁成功or失败? 3、如果'隔壁老王'去给A、B、C加锁时,C突然挂了,这次加锁是成功还是失败? 4、如果'隔壁老王'去给A、B、C加锁时,超时时间为5秒,加一个锁耗时3秒,此次加锁能成功吗? # 解决 1、安全起见,让'隔壁老王'加锁时设置超时时间,超时的话就会自动解锁(删除key:'xxx') 2、加锁程度达到(1/2)+1个就表示加锁成功,即使没有给全部实例加锁; 3、加锁程度达到(1/2)+1个就表示加锁成功,即使没有给全部实例加锁; 4、不能成功,锁还没加完就过期,没有意义了,应该合理设置过期时间 # 注意 使用需要安装redlock-py ---------------------------------------------------------------- from redlock import Redlock dlm = Redlock(     [         {"host": "localhost", "port": 6379, "db": 0},        nbsp; {"host": "localhost", "port": 6379, "db": 0},         {"host": "localhost", "port": 6379, "db": 0},     ] ) # 加锁,acquire my_lock = dlm.lock("my_resource_name",10000) if my_lock:     # 进行操作     # 解锁,release     dlm.unlock(my_lock) else:     print('获取锁失败') \通过sever.eval(self.unlock_script)执行一个lua脚本,用来删除加锁时的key
复制代码

157.什么是一致性哈希?Python中是否有相应模块?

 一致性哈希
一致性hash算法(DHT)可以通过减少影响范围的方式,解决增减服务器导致的数据散列问题,从而解决了分布式环境下负载均衡问题;
如果存在热点数据,可以通过增添节点的方式,对热点区间进行划分,将压力分配至其他服务器,重新达到负载均衡的状态。
Python模块--hash_ring,即Python中的一致性hash

158.如何高效的找到redis中所有以aaa开头的key?

复制代码
redis 有一个keys命令。
# 语法:KEYS pattern
# 说明:返回与指定模式相匹配的所用的keys。
该命令所支持的匹配模式如下:
1、?:用于匹配单个字符。例如,h?llo可以匹配hello、hallo和hxllo等;
2、*:用于匹配零个或者多个字符。例如,h*llo可以匹配hllo和heeeello等;
2、[]:可以用来指定模式的选择区间。例如h[ae]llo可以匹配hello和hallo,但是不能匹配hillo。同时,可以使用“/”符号来转义特殊的字符
# 注意
KEYS 的速度非常快,但如果数据太大,内存可能会崩掉, 如果需要从一个数据集中查找特定的key,最好还是用Redis的集合结构(set)来代替。
复制代码
回到顶部

第四部分 前端、框架和其他(155题)

1.谈谈你对http协议的认识。

复制代码
  浏览器本质,socket客户端遵循Http协议
  HTTP协议本质:通过\r\n分割的规范+ 请求响应之后断开链接   ==  >  无状态、 短连接
具体:
  Http协议是建立在tcp之上的,是一种规范,它规范定了发送的数据的数据格式,
然而这个数据格式是通过\r\n 进行分割的,请求头与请求体也是通过2个\r\n分割的,响应的时候,
响应头与响应体也是通过\r\n分割,并且还规定已请求已响应就会断开链接   
即--->  短连接、无状态
复制代码

2.谈谈你对websocket协议的认识。

复制代码
websocket是给浏览器新建的一套(类似与http)协议,协议规定:(\r\n分割)浏览器和服务器连接之后不断开,
    以此完成:服务端向客户端主动推送消息。

websocket协议额外做的一些操作
握手 ----> 连接钱进行校验
加密 ----> payload_len=127/126/<=125 --> mask key

复制代码
本质
创建一个连接后不断开的socket
当连接成功之后:
    客户端(浏览器)会自动向服务端发送消息,包含: Sec-WebSocket-Key: iyRe1KMHi4S4QXzcoboMmw==
    服务端接收之后,会对于该数据进行加密:base64(sha1(swk + magic_string))
    构造响应头:
            HTTP/1.1 101 Switching Protocols\r\n
            Upgrade:websocket\r\n
            Connection: Upgrade\r\n
            Sec-WebSocket-Accept: 加密后的值\r\n
            WebSocket-Location: ws://127.0.0.1:8002\r\n\r\n        
    发给客户端(浏览器)
建立:双工通道,接下来就可以进行收发数据
    发送数据是加密,解密,根据payload_len的值进行处理
        payload_len <= 125
        payload_len == 126
        payload_len == 127
    获取内容:
        mask_key
        数据
        根据mask_key和数据进行位运算,就可以把值解析出来。
复制代码
复制代码

 3.什么是magic string ?

 客户端向服务端发送消息时,会有一个'sec-websocket-key'和'magic string'的随机字符串(魔法字符串)
# 服务端接收到消息后会把他们连接成一个新的key串,进行编码、加密,确保信息的安全性

4.如何创建响应式布局?

复制代码
响应式布局是通过@media实现的
@media (min-width:768px){
     .pg-header{
           background-color:green;
      }      
}
@media   (min-width:992px){
     .pg-header{
            background-color:pink;
     }
}    

代码






Title