python_interview_question/README.md

1138 lines
62 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-generate-toc again -->
* [Python基础](#python基础)
* 1、文件操作
* 1.1、有一个jsonline格式的文件file.txt大小约为10K
* 1.2、补充缺失的代码?
* 2、模块与包
* 2.1输入日期,判断这一天是这一年的第几天?
* 2.2打乱一个排好序的list对象 alist
* 3、数据类型
* 3.1、现有字典 d={a:24g:52i:12k:33}请按value值进行
* 3.2、字典推导式?
* 3.3、请反转字符串“aStr”?
* 3.4、将字符串"k:1|k1:2|k2:3|k3:4",处理成字典:{k:1 k1:2 ...
* 3.5、请按alist中元素的age由大到小排序
* 3.6下面代码的输出结果将是什么?
* 3.7、写一个列表生成式产生一个公差为11的等差数列
* 3.8、给定两个列表,怎么找出他们相同的元素和不同的元素?
* 3.9、请写出一段Python代码实现删除一个list里面的重复元素?
* 3.10、给定两个list A ,B请用找出 A ,B中相同与不同的元素
* [4、企业面试题](#企业面试题)
* 4.1、Python新式类和经典类的区别
* 4.2、python中内置的数据结构有几种
* 4.3、Python如何实现单例模式请写出两种实现方法
* 4.4、反转一个整数,例如-123-->-321,Python语言实现
* 4.5、设计实现遍历目录与子目录,抓取.pyc文件
* 4.6、一行代码实现1-100之和
* 4.7、Python-遍历列表时删除元素的正确做法
* 4.8、字符串的操作题目
* 4.9、可变类型和不可变类型
* 4.10、is和==有什么区别?
* 4.11、求出列表所有奇数并构造新列表
* 4.12、用一行python代码写出1+2+3+10248
* 4.13、Python中变量的作用域变量查找顺序
* 4.14、字符串”123″转换成123不使用内置api例如int
* 4.15、Given an array of integers
* 4.16、python代码实现删除一个list里面的重复元素
* 4.17、统计一个文本中单词频次最高的10个单词
* 4.18、请写出一个函数满足以下条件
* 4.19、使用单一的列表生成式来产生一个新的列表
* 4.20、用一行代码生成[1,4,9,16,25,36,49,64,81,100]
* 4.21、输入某年某月某日,判断这一天是这一年的第几天?
* 4.22、两个有序列表l1,l2对这两个列表进行合并不可使用extend
* 4.23、给定一个任意长度数组,实现一个函数
* 4.23、写一个函数找出一个整数数组中,第二大的数
* 4.24、阅读一下代码他们的输出结果是什么?
* 4.25、统计一段字符串中字符出现的次数
* 4.26、super函数的具体用法和场景
* [二、Python高级](#Pythong高级)
* 1、元类
* 1.1、Python中类方法、类实例方法、静态方法有何区别
* 1.2、super函数的具体用法和场景
* 1.3、历一个object的所有属性并print每一个属性名
* 1.4、写一个类,并让它尽可能多的支持操作符?
* 1.5、介绍CpythonPypy Cpython Numba各有什优缺点
* 1.6、请描述抽象类和接口类的区别和联系?
* 1.7、Python中如何动态获取和设置对象的属性
* 2、内存管理与垃圾回收机制
* 2.1、哪些操作会导致Python内存溢出怎么处理
* 2.2、关于 Python内存管理,下列说法错误的是(B)
* 2.3、Python的内存管理机制及调优手段
* 2.4、内存泄露是什么?如何避免?
* 3、函数
* 3.1、python常见的列表推导式
* 3.2、简述read、readline、readlines的区别
* 3.3、什么是Hash散列函数
* 3.4、python函数重载机制
* 3.5、写一个函数找出一个整数数组中,第二大的数
* 3.6、手写一个判断时间的装饰器
* 3.7、使用Python内置的filter()方法来过滤?
* 3.8、编写函数的4个原则
* 3.9、函数调用参数的传递方式是值传递还是引用传递?
* 3.10、如何在function里面设置一个全局变量
* 3.11、对缺省参数的理解
* 3.12、Mysql怎么限制IP访问
* 3.13、带参数的装饰器?
* 3.14、为什么函数名字可以当做参数用?
* 3.15、Python中pass语句的作用是什么
* 3.16、有这样一段代码print c会输出什么为什么
* 3.17、交换两个变量的值?
* 3.18、map函数和reduce函数
* 3.19、回调函数,如何通信的?
* 3.20、Python主要的内置数据类型都有哪些 print dir( a ) 的输出?
* 3.21、map(lambda x:xx[y for y in range(3)])的输出?
* 3.22、 hasattr() getattr() setattr() 函数使用详解?
* 3.23、一句话解决阶乘函数?
* 3.24、什么是lambda函数 有什么好处?
* 3.25、递归函数停止的条件?
* 3.26、下面这段代码的输出结果将是什么?请解释。
* 3.27、什么是lambda函数它有什么好处写一个匿名函数求两个数的
* [4、设计模式](#4设计模式)
* 4.1、对设计模式的理解,简述你了解的设计模式?
* 4.2、请手写一个单例
* 4.3、单例模式的应用场景有哪些?
* 4.4、Python 如何实现单例模式?请写出两种实现方法?
* 4.5、对装饰器的理解 ,并写出一个计时器记录方法执行性能的装饰器?
* 4.6、解释一下什么是闭包?
* 4.7、函数装饰器有什么作用?
* 4.8、生成器、迭代器的区别?
* 4.9 X是什么类型
* 4.10、请用“一行代码”实现将1-N的整数列表以3为单位分组
* 4.11、Python中yield的用法
* 5、面向对象
* 5.1、Python中的可变对象和不可变对象
* 5.2、
* 5.3、Python的魔法方法
* 5.4、面向对象中怎么实现只读属性?
* 5.5、谈谈你对面向对象的理解?
* 6、正则表达式
* 6.1、请写出一段代码用正则匹配出ip
* 6.2、a = “abbbccc”用正则匹配为abccc,不管有多少b就出现一次
* 6.3、Python字符串查找和替换
* 6.4、 用Python匹配HTML g tag的时候<.><.*?> 有什么区别
* 6.5、正则表达式贪婪与非贪婪模式的区别?
* 6.6、写出开头匹配字母和下划线,末尾是数字的正则表达式?
* 6.7、正则表达式操作
* 6.8、请匹配出变量A 中的json字符串。
* 6.9、怎么过滤评论中的表情?
* 6.10、简述Python里面search和match的区别
* 6.11、请写出匹配ip的Python正则表达式
* 6.12、Python里match与search的区别
* [7、系统编程](#7系统编程)
* 7.1、 进程总结
* 7.2、 谈谈你对多进程,多线程,以及协程的理解,项目是否用?
* 7.3、 Python异步使用场景有那些
* 7.4、 多线程共同操作同一个数据互斥锁同步?
* 7.5、 什么是多线程竞争?
* 7.6、 请介绍一下Python的线程同步
* 7.7、 解释一下什么是锁,有哪几种锁?
* 7.8、 什么是死锁呢?
* 7.9、 多线程交互访问数据,如果访问到了就不访问了
* 7.10、什么是线程安全,什么是互斥锁?
* 7.11、说说下面几个概念:同步,异步,阻塞,非阻塞?
* 7.12、什么是僵尸进程和孤儿进程?怎么避免僵尸进程?
* 7.13、Python中的进程与线程的使用场景?
* 7.14、线程是并发还是并行,进程是并发还是并行?
* 7.15、并行parallel和并发concurrency
* 7.16、IO密集型和CPU密集型区别
* 7.17 python asyncio的原理
* 8、网络编程
* 8.1、怎么实现强行关闭客户端和服务器之间的连接?
* 8.2、简述TCP和UDP的区别以及优缺点?
* 8.3、简述浏览器通过WSGI请求动态资源的过程?
* 8.4、描述用浏览器访问www.baidu.com的过程
* 8.5、Post和Get请求的区别?
* 8.6、cookie 和session 的区别?
* 8.7、列出你知道的HTTP协议的状态码说出表示什么意思
* 8.8、请简单说一下三次握手和四次挥手?
* 8.9、说一下什么是tcp的2MSL
* 8.10、为什么客户端在TIME-WAIT状态必须等待2MSL的时间
* 8.11、说说HTTP和HTTPS区别
* 8.12、谈一下HTTP协议以及协议头部中表示数据类型的字段
* 8.13、HTTP请求方法都有什么
* 8.14、使用Socket套接字需要传入哪些参数
* 8.15、HTTP常见请求头
* 8.16、七层模型?
* 8.17、url的形式
* [三、Web](#三.Web)
* [1、Flask](#1、Flask)
* 1.1、对Flask蓝图(Blueprint)的理解?
* 1.2、Flask和Django路由映射的区别
* Django
* 2.1、什么是wsgi,uwsgi,uWSGI
* 2.2、CORS和CSRF的区别
* 2.3、Session、Cookie、JWT的理解
* 2.4、简述Django请求生命周期
* 2.5、Django 、Flask、Tornado的对比
* 2.6、用的restframework完成api发送时间时区
* 2.7、nginx,tomcat,apache 都是什么?
* 2.8、请给出你熟悉关系数据库范式有那些,有什么作用
* 2.9、简述QQ登陆过程
* 2.10、post和get 的区别?
* 2.11、项目中日志的作用
* 2.12、django中间件的使用
* 2.13、谈一下你对uWSGI和 nginx的理解
* 2.14、Python中三大框架各自的应用场景
* 2.15、Django中哪里用到了线程?哪里用到了协程?哪里用到了进程?
* 2.16、有用过Django REST framework 吗?
* 2.17、对cookie与session的了解他们能单独用吗
* 爬虫
* 1.1、试列出至少三种目前流行的大型数据库
* 1.2、列举您使用过的Python网络爬虫所用到的网络数据包?
* 1.3、列举您使用过的Python网络爬虫所用到的解析数据包
* 1.4、爬取数据后使用哪个数据库存储数据的,为什么?
* 1.5、你用过的爬虫框架或者模块有哪些?优缺点?
* 1.6、写爬虫是用多进程好?还是多线程好?
* 1.7、常见的反爬虫和应对方法?
* 1.8、解析网页的解析器使用最多的是哪几个?
* 1.9、需要登录的网页如何解决同时限制ipcookie,session
* 1.10、验证码的解决?
* 1.11、使用最多的数据库,对他们的理解?
* 1.12、编写过哪些爬虫中间件?
* 1.13、“极验”滑动验证码如何破解?
* 1.14、爬虫多久爬一次,爬下来的数据是怎么存储?
* 1.15、cookie过期的处理问题
* 1.16、动态加载又对及时性要求很高怎么处理?
* 1.17、HTTPS有什么优点和缺点
* 1.18、HTTPS是如何实现安全传输数据的
* 1.19、TTLMSLRTT各是什么
* 1.20、谈一谈你对Selenium和PhantomJS了解
* 1.21、平常怎么使用代理的
* 1.22、存放在数据库(redis、mysql等)。
* 1.23、怎么监控爬虫的状态?
* 1.24、描述下scrapy框架运行的机制
* 1.25、谈谈你对Scrapy的理解
* 1.26、怎么样让 scrapy 框架发送一个 post 请求(具体写出来)
* 1.27、怎么监控爬虫的状态
* 1.28、怎么判断网站是否更新?
* 1.29、图片、视频爬取怎么绕过防盗连接
* 1.30、你爬出来的数据量大概有多大?大概多长时间爬一次?
* 1.31、用什么数据库存爬下来的数据?部署是你做的吗?怎么部署?
* 1.32、增量爬取
* 1.33、爬取下来的数据如何去重说一下scrapy的具体的算法依据。
* 1.34、Scrapy的优缺点?
* 1.35、怎么设置爬取深度?
* 1.36、scrapy和scrapy-redis有什么区别为什么选择redis数据库
* 1.37、分布式爬虫主要解决什么问题?
* 1.38、什么是分布式存储?
* 1.39、你所知道的分布式爬虫方案有哪些?
* 1.40、scrapy-redis有做过其他的分布式爬虫吗
* 五、数据库
* 1、MySQL
* 1.1、主键 超键 候选键 外键
* 1.2、视图的作用,视图可以更改么?
* 1.3、drop,delete与truncate的区别
* 1.4、索引的工作原理及其种类
* 1.5、连接的种类
* 1.6、数据库优化的思路
* 1.7、存储过程与触发器的区别
* 1.8、悲观锁和乐观锁是什么?
* 1.9、你常用的mysql引擎有哪些?各引擎间有什么区别?
* 2、Redis
* 2.1、Redis宕机怎么解决?
* 2.2、redis和mecached的区别以及使用场景
* 2.3、Redis集群方案该怎么做?都有哪些方案?
* 2.4、Redis回收进程是如何工作的
* 3、MongoDB
* 3.1、MongoDB中对多条记录做更新操作命令是什么
* 3.2、MongoDB如何才会拓展到多个shard里
* 六、测试
* 1、编写测试计划的目的是
* 2、对关键词触发模块进行测试
* 3、其他常用笔试题目网址汇总
* 4、测试人员在软件开发过程中的任务是什么
* 5、一条软件Bug记录都包含了哪些内容
* 6、简述黑盒测试和白盒测试的优缺点
* 7、请列出你所知道的软件测试种类至少5项。
* 8、Alpha测试与Beta测试的区别是什么
* 9、举例说明什么是Bug一个bug report应包含什么关键字
* 数据结构
* 1.1、数组中出现次数超过一半的数字-Python版
* 1.2、求100以内的质数
* 1.3、无重复字符的最长子串-Python实现
* 1.4、通过2个5/6升得水壶从池塘得到3升水
* 1.5、什么是MD5加密有什么特点
* 1.6、什么是对称加密和非对称加密
* 1.7、冒泡排序的思想?
* 1.8、快速排序的思想?
* 1.9、如何判断单向链表中是否有环?
* 1.10、你知道哪些排序算法(一般是通过问题考算法)
* 1.11、斐波那契数列
* 1.12、如何翻转一个单链表?
* 1.13、青蛙跳台阶问题
* 1.14、两数之和 Two Sum
* 1.15、搜索旋转排序数组 Search in Rotated Sorted Array
* 1.16、Python实现一个Stack的数据结构
* 1.17、写一个二分查找
* 1.18、set 用 in 时间复杂度是多少,为什么?
* 1.19、列表中有n个正整数范围在[01000],进行排序;
* 1.20、面向对象编程中有组合和继承的方法实现新的类
* 八、人工智能
* 1.1、找出1G的文件中高频词
* 1.2、一个大约有一万行的文本文件统计高频词
* 1.3、怎么在海量数据中找出重复次数最多的一个?
* 1.4、判断数据是否在大量数据中
<!-- markdown-toc end -->
# Python基础
## 1.1 有一个jsonline格式的文件file.txt 大小约为10K
```
def get_lines():
l = []
with open('file.txt','rb) as f:
for eachline in f:
l.append(eachline)
return l
if __name__ == '__main__':
for e in get_lines():
process(e) #处理每一行数据
```
现在要处理一个大小为10G的文件但是内存只有4G如果在只修改get_lines 函数而其他代码保持不变的情况下,应该如何实现?需要考虑的问题都有那些?
```
def get_lines():
with open('file.txt','rb') as f:
for l in f:
yield l
```
要考虑的问题有内存只有4G无法一次性读入10G文件需要分批读入分批读入数据要记录每次读入数据的位置。分批每次读取数据的大小太小会在读取操作花费过多时间。
## 1.2 补充缺失的代码
```
def print_directory_contents(sPath):
"""
这个函数接收文件夹的名称作为输入参数
返回该文件夹中文件的路径
以及其包含文件夹中文件的路径
"""
import os
for s_child in os.listdir(s_path):
s_child_path = os.path.join(s_path, s_child)
if os.path.isdir(s_child_path):
print_directory_contents(s_child_path)
else:
print(s_child_path)
```
# 模块与包
## 2.1 输入日期, 判断这一天是这一年的第几天?
```
import datetime
def dayofyear():
year = input("请输入年份: ")
month = input("请输入月份: ")
day = input("请输入天: ")
date1 = datetime.date(year=int(year),month=int(month),day=int(day))
date2 = datetime.date(year=int(year),month=1,day=1)
return (date1-date2).days+1
```
## 2.2 打乱一个排好序的list对象alist
```
import random
alist = [1,2,3,4,5]
random.shuffle(alist)
print(alist)
```
# 数据类型
## 3.1 现有字典 d= {'a':24,'g':52,'i':12,'k':33}请按value值进行排序?
```
sorted(d.items(),key=lambda x:x[1])
```
## 3.2 字典推导式
```
d = {key:value for (key,value) in iterable}
```
## 3.3 请反转字符串 "aStr"?
```
print("aStr"[::-1])
```
## 3.4 将字符串 "k:1 |k1:2|k2:3|k3:4",处理成字典 {k:1,k1:2,...}
```
str1 = "k:1|k1:2|k2:3|k3:4"
def str2dict(str1):
dict1 = {}
for iterms in str1.split('|'):
key,value = iterms.split(':')
dict1[key] = value
return dict1
```
## 3.5 请按alist中元素的age由大到小排序
```
alist = [{'name':'a','age':20},{'name':'b','age':30},{'name':'c','age':25}]
def sort_by_age(list1):
return sorted(alist,key=lambda x:x['age'],reverse=True)
```
## 3.6 下面代码的输出结果将是什么?
```
list = ['a','b','c','d','e']
print(list[10:])
```
代码将输出[],不会产生IndexError错误就像所期望的那样尝试用超出成员的个数的index来获取某个列表的成员。例如尝试获取list[10]和之后的成员会导致IndexError。然而尝试获取列表的切片开始的index超过了成员个数不会产生IndexError而是仅仅返回一个空列表。这成为特别让人恶心的疑难杂症因为运行的时候没有错误产生导致Bug很难被追踪到。
## 3.7 写一个列表生成式产生一个公差为11的等差数列
```
print([x*11 for x in range(10)])
```
## 3.8 给定两个列表,怎么找出他们相同的元素和不同的元素?
```
list1 = [1,2,3]
list2 = [3,4,5]
set1 = set(list1)
set2 = set(list2)
print(set1 & set2)
print(set1 ^ set2)
```
## 3.9 请写出一段python代码实现删除list里面的重复元素
```
l1 = ['b','c','d','c','a','a']
l2 = list(set(l1))
print(l2)
```
用list类的sort方法:
```
l1 = ['b','c','d','c','a','a']
l2 = list(set(l1))
l2.sort(key=l1.index)
print(l2)
```
也可以这样写:
```
l1 = ['b','c','d','c','a','a']
l2 = sorted(set(l1),key=l1.index)
print(l2)
```
也可以用遍历:
```
l1 = ['b','c','d','c','a','a']
l2 = []
for i in l1:
if not i in l2:
l2.append(i)
print(l2)
```
## 3.10 给定两个list AB ,请用找出AB中相同与不同的元素
```
A,B 中相同元素: print(set(A)&set(B))
A,B 中不同元素: print(set(A)^set(B))
```
# 企业面试题
## 4.1 python新式类和经典类的区别
a. 在python里凡是继承了object的类都是新式类
b. Python3里只有新式类
c. Python2里面继承object的是新式类没有写父类的是经典类
d. 经典类目前在Python里基本没有应用
## 4.2 python中内置的数据结构有几种
a. 整型 int、 长整型 long、浮点型 float、 复数 complex
b. 字符串 str、 列表list、 元祖tuple
c. 字典 dict 、 集合 set
## 4.3 python如何实现单例模式?请写出两种实现方式?
第一种方法:使用装饰器
```
def singleton(cls):
instances = {}
def wrapper(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return wrapper
@singleton
class Foo(object):
pass
foo1 = Foo()
foo2 = Foo()
print foo1 is foo2 #True
```
第二种方法:使用基类
New 是真正创建实例对象的方法所以重写基类的new 方法,以此保证创建对象的时候只生成一个实例
```
class Singleton(object):
def __new__(cls,*args,**kwargs):
if not hasattr(cls,'_instance'):
cls._instance = super(Singleton,cls).__new__(cls,*args,**kwargs)
return cls._instance
class Foo(Singleton):
pass
foo1 = Foo()
foo2 = Foo()
print foo1 is foo2 #True
```
第三种方法元类元类是用于创建类对象的类类对象创建实例对象时一定要调用call方法因此在调用call时候保证始终只创建一个实例即可type是python的元类
```
class Singleton(type):
def __call__(cls,*args,**kwargs):
if not hasattr(cls,'_instance'):
cls._instance = super(Singleton,cls).__call__(*args,**kwargs)
return cls._instance
```
```
class Foo(object):
__metaclass__ = Singleton
foo1 = Foo()
foo2 = Foo()
print foo1 is foo2 #True
```
## 4.4 反转一个整数,例如-123 --> -321
```
class Solution(object):
def reverse(self,x):
if -10<x<10:
return x
str_x = str(x)
if str_x[0] !="-":
str_x = str_x[::-1]
x = int(str_x)
else:
str_x = str_x[1:][::-1]
x = int(str_x)
x = -x
return x if -2147483648<x<2147483647 else 0
if __name__ == '__main__':
s = Solution()
reverse_int = s.reverse(-120)
print(reverse_int)
```
## 4.5 设计实现遍历目录与子目录,抓取.pyc文件
第一种方法:
```
import os
def get_files(dir,suffix):
res = []
for root,dirs,files in os.walk(dir):
for filename in files:
name,suf = os.path.splitext(filename)
if suf == suffix:
res.append(os.path.join(root,filename))
print(res)
get_files("./",'.pyc')
```
第二种方法:
```
import os
def pick(obj):
try:
if obj.[-4:] == ".pyc":
print(obj)
except:
return None
def scan_path(ph):
file_list = os.listdir(ph)
for obj in file_list:
if os.path.isfile(obj):
pick(obj)
elif os.path.isdir(obj):
scan_path(obj)
if __name__=='__main__':
path = input('输入目录')
scan_path(path)
```
## 4.6 一行代码实现1-100之和
```
count = sum(range(0,101))
print(count)
```
# Python高级
## 3 函数
## 3.6 手写一个判断时间的装饰器
```
import datetime
class TimeException(Exception):
def __init__(self, exception_info):
super().__init__()
self.info = exception_info
def __str__(self):
return self.info
def timecheck(func):
def wrapper(*args, **kwargs):
if datetime.datetime.now().year == 2019:
func(*args, **kwargs)
else:
raise TimeException("函数已过时")
return wrapper
@timecheck
def test(name):
print("Hello {}, 2019 Happy".format(name))
if __name__ == "__main__":
test("backbp")
```
## 3.7 使用Python内置的filter()方法来过滤?
```
[x for x in filter(lambda x: x % 2 == 0, range(10))]
```
## 4设计模式
## 4.1 对设计模式的理解,简述你了解的设计模式?
设计模式是经过总结,优化的,对我们经常会碰到的一些编程问题的可重用解决方案。一个设计模式并不像一个类或一个库那样能够直接作用于我们的代码,反之,设计模式更为高级,它是一种必须在特定情形下实现的一种方法模板。
常见的是工厂模式和单例模式
## 4.2 请手写一个单例
```
#python2
class A(object):
__instance = None
def __new__(cls,*args,**kwargs):
if cls.__instance is None:
cls.__instance = objecet.__new__(cls)
return cls.__instance
else:
return cls.__instance
```
## 4.3 单例模式的应用场景有那些?
单例模式应用的场景一般发现在以下条件下:
资源共享的情况下,避免由于资源操作时导致的性能或损耗等,如日志文件,应用配置。
控制资源的情况下方便资源之间的互相通信。如线程池等1,网站的计数器 2,应用配置 3.多线程池 4数据库配置 数据库连接池 5.应用程序的日志应用...
## 4.5 对装饰器的理解,并写出一个计时器记录方法执行性能的装饰器?
装饰器本质上是一个python函数它可以让其他函数在不需要做任何代码变动的前提下增加额外功能装饰器的返回值也是一个函数对象。
```
import time
def timeit(func):
def wrapper():
start = time.clock()
func()
end = time.clock()
print('used:',end-start)
return wrapper
@timeit
def foo():
print('in foo()'foo())
```
## 4.6 解释以下什么是闭包?
在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包。
## 4.7 函数装饰器有什么作用?
装饰器本质上是一个python函数它可以在让其他函数在不需要做任何代码的变动的前提下增加额外的功能。装饰器的返回值也是一个函数的对象它经常用于有切面需求的场景。比如插入日志性能测试事务处理缓存。权限的校验等场景有了装饰器就可以抽离出大量的与函数功能本身无关的雷同代码并发并继续使用。
## 4.8 生成器,迭代器的区别?
迭代器是一个更抽象的概念任何对象如果它的类有next方法和iter方法返回自己本身对于string,list,dict,tuple等这类容器对象使用for循环遍历是很方便的在后台for语句对容器对象调用iter()函数iter()是python的内置函数iter()会返回一个定义了next()方法的迭代器对象它在容器中逐个访问容器内元素next()也是python的内置函数在没有后续元素时next()会抛出一个StopIteration异常。
生成器Generator是创建迭代器的简单而强大的工具。它们写起来就像是正规的函数只是在需要返回数据的时候使用yield语句。每次next()被调用时,生成器会返回它脱离的位置(它记忆语句最后一次执行的位置和所有的数据值)
区别: 生成器能做到迭代器能做的所有事而且因为自动创建iter()和next()方法生成器显得特别简洁而且生成器也是高效的使用生成器表达式取代列表解析可以同时节省内存。除了创建和保存程序状态的自动方法当发生器终结时还会自动抛出StopIteration异常。
## 4.9 X是什么类型?
X= (fo ri in ramg(10))
X是 generator类型
## 4.10 请用一行代码 实现将1-N 的整数列表以3为单位分组
```
print ([[x for x in range(1,100)] [i:i+3] for i in range(0,len(list_a),3)])
```
## 4.11 Python中yield的用法》
yield就是保存当前程序执行状态。你用for循环的时候每次取一个元素的时候就会计算一次。用yield的函数叫generator,和iterator一样它的好处是不用一次计算所有元素而是用一次算一次可以节省很多空间generator每次计算需要上一次计算结果所以用yield,否则一return上次计算结果就没了
## 4.20 用一行代码生成[1,4,9,16,25,36,49,64,81,100]
```
print([x*x for x in range(1, 11)])
```
## 7系统编程
## 7.1 进程总结
进程程序运行在操作系统上的一个实例就称之为进程。进程需要相应的系统资源内存、时间片、pid。
创建进程:
首先要导入multiprocessing中的Process
创建一个Process对象;
创建Process对象时可以传递参数;
```
p = Process(target=XXX,args=(tuple,),kwargs={key:value})
target = XXX 指定的任务函数,不用加(),
args=(tuple,)kwargs={key:value}给任务函数传递的参数
```
使用start()启动进程
结束进程
给子进程指定函数传递参数Demo
```
import os
from mulitprocessing import Process
import time
def pro_func(name,age,**kwargs):
for i in range(5):
print("子进程正在运行中name=%s,age=%d,pid=%d"%(name,age,os.getpid()))
print(kwargs)
time.sleep(0.2)
if __name__ =="__main__":
#创建Process对象
p = Process(target=pro_func,args=('小明',18),kwargs={'m':20})
#启动进程
p.start()
time.sleep(1)
#1秒钟之后立刻结束子进程
p.terminate()
p.join()
```
注意:进程间不共享全局变量
进程之间的通信-Queue
在初始化Queue()对象时例如q=Queue(),若在括号中没有指定最大可接受的消息数量,获数量为负值时,那么就代表可接受的消息数量没有上限一直到内存尽头)
Queue.qsize():返回当前队列包含的消息数量
Queue.empty():如果队列为空返回True反之False
Queue.full():如果队列满了返回True,反之False
Queue.get([block[,timeout]]):获取队列中的一条消息然后将其从队列中移除block默认值为True。
如果block使用默认值且没有设置timeout单位秒),消息队列如果为空此时程序将被阻塞停在读中状态直到消息队列读到消息为止如果设置了timeout则会等待timeout秒若还没读取到任何消息则抛出“Queue.Empty"异常:
Queue.get_nowait()相当于Queue.get(False)
Queue.put(item,[block[,timeout]]):将item消息写入队列block默认值为True;
如果block使用默认值且没有设置timeout单位秒消息队列如果已经没有空间可写入此时程序将被阻塞停在写入状态直到从消息队列腾出空间为止如果设置了timeout则会等待timeout秒若还没空间则抛出”Queue.Full"异常
如果block值为False消息队列如果没有空间可写入则会立刻抛出"Queue.Full"异常;
Queue.put_nowait(item):相当Queue.put(item,False)
进程间通信Demo:
```
from multiprocessing import Process.Queue
import os,time,random
#写数据进程执行的代码:
def write(q):
for value in ['A','B','C']:
print("Put %s to queue...",%value)
q.put(value)
time.sleep(random.random())
#读数据进程执行的代码
def read(q):
while True:
if not q.empty():
value = q.get(True)
print("Get %s from queue.",%value)
time.sleep(random.random())
else:
break
if __name__=='__main__':
#父进程创建Queue并传给各个子进程
q = Queue()
pw = Process(target=write,args=(q,))
pr = Process(target=read,args=(q,))
#启动子进程pw ,写入:
pw.start()
#等待pw结束
pw.join()
#启动子进程pr读取
pr.start()
pr.join()
#pr 进程里是死循环,无法等待其结束,只能强行终止:
print('')
print('所有数据都写入并且读完')
```
进程池Pool
```
#coding:utf-8
from multiprocessing import Pool
import os,time,random
def worker(msg):
t_start = time.time()
print("%s 开始执行,进程号为%d"%(msg,os.getpid()))
# random.random()随机生成0-1之间的浮点数
time.sleep(random.random()*2)
t_stop = time.time()
print(msg,"执行完毕,耗时%0.2f”%t_stop-t_start))
po = Pool(3)#定义一个进程池最大进程数3
for i in range(0,10):
po.apply_async(worker,(i,))
print("---start----")
po.close()
po.join()
print("----end----")
```
进程池中使用Queue
如果要使用Pool创建进程就需要使用multiprocessing.Manager()中的Queue(),而不是multiprocessing.Queue(),否则会得到如下的错误信息:
RuntimeError Queue objects should only be shared between processs through inheritance
```
from multiprocessing import Manager,Pool
import os,time,random
def reader(q):
print("reader 启动(%s),父进程为(%s)"%(os.getpid(),os.getpid()))
for i in range(q.qsize()):
print("reader 从Queue获取到消息:%s"%q.get(True))
def writer(q):
print("writer 启动(%s),父进程为(%s)"%(os.getpid(),os.getpid()))
for i ini "itcast":
q.put(i)
if __name__ == "__main__":
print("(%s)start"%os.getpid())
q = Manager().Queue()#使用Manager中的Queue
po = Pool()
po.apply_async(wrtier,(q,))
time.sleep(1)
po.apply_async(reader,(q,))
po.close()
po.join()
print("(%s)End"%os.getpid())
```
## 7.2 谈谈你对多进程,多线程,以及协程的理解,项目是否用?
这个问题被问的概念相当之大,
进程:一个运行的程序(代码)就是一个进程,没有运行的代码叫程序,进程是系统资源分配的最小单位,进程拥有自己独立的内存空间,所有进程间数据不共享,开销大。
线程: cpu调度执行的最小单位也叫执行路径不能独立存在依赖进程存在一个进程至少有一个线程叫主线程而多个线程共享内存数据共享共享全局变量),从而极大地提高了程序的运行效率。
协程: 是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操中栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
## 7.3 Python异常使用场景有那些
异步的使用场景:
1、 不涉及共享资源,获对共享资源只读,即非互斥操作
2、 没有时序上的严格关系
3、 不需要原子操作,或可以通过其他方式控制原子性
4、 常用于IO操作等耗时操作因为比较影响客户体验和使用性能
5、 不影响主线程逻辑
## 7.4 多线程共同操作同一个数据互斥锁同步?
```
import threading
import time
class MyThread(threading.Thread):
def run(self):
global num
time.sleep(1)
if mutex.acquire(1):
num +=1
msg = self.name + 'set num to ' +str(num)
print msg
mutex.release()
num = 0
mutex = threading.Lock()
def test():
for i in range(5):
t = MyThread()
t.start()
if __name__=="__main__":
test()
```
## 7.5 什么是多线程竞争?
线程是非独立的,同一个进程里线程是数据共享的,当各个线程访问数据资源时会出现竞争状态即:数据几乎同步会被多个线程占用,造成数据混乱,即所谓的线程不安全
那么怎么解决多线程竞争问题?---锁
锁的好处: 确保了某段关键代码(共享数据资源)只能由一个线程从头到尾完整地执行能解决多线程资源竞争下的原子操作问题。
锁的坏处: 阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了
锁的致命问题: 死锁
## 7.6 请介绍一下Python的线程同步
一、 setDaemon(False)
当一个进程启动之后会默认产生一个主线程因为线程是程序执行的最小单位当设置多线程时主线程会创建多个子线程在Python中默认情况下就是setDaemon(False),主线程执行完自己的任务以后,就退出了,此时子线程会继续执行自己的任务,直到自己的任务结束。
例子
```
import threading
import time
def thread():
time.sleep(2)
print('---子线程结束---')
def main():
t1 = threading.Thread(target=thread)
t1.start()
print('---主线程--结束')
if __name__ =='__main__':
main()
#执行结果
---主线程--结束
---子线程结束---
```
二、 setDaemonTrue)
当我们使用setDaemon(True)时,这是子线程为守护线程,主线程一旦执行结束,则全部子线程被强制终止
例子
```
import threading
import time
def thread():
time.sleep(2)
print(---子线程结束---')
def main():
t1 = threading.Thread(target=thread)
t1.setDaemon(True)#设置子线程守护主线程
t1.start()
print('---主线程结束---')
if __name__ =='__main__':
main()
#执行结果
---主线程结束--- #只有主线程结束,子线程来不及执行就被强制结束
```
三、 join线程同步)
join 所完成的工作就是线程同步,即主线程任务结束以后,进入堵塞状态,一直等待所有的子线程结束以后,主线程再终止。
当设置守护线程时含义是主线程对于子线程等待timeout的时间将会杀死该子线程最后退出程序所以说如果有10个子线程全部的等待时间就是每个timeout的累加和简单的来说就是给每个子线程一个timeou的时间让他去执行时间一到不管任务有没有完成直接杀死。
没有设置守护线程时主线程将会等待timeout的累加和这样的一段时间时间一到主线程结束但是并没有杀死子线程子线程依然可以继续执行直到子线程全部结束程序退出。
例子
```
import threading
import time
def thread():
time.sleep(2)
print('---子线程结束---')
def main():
t1 = threading.Thread(target=thread)
t1.setDaemon(True)
t1.start()
t1.join(timeout=1)#1 线程同步主线程堵塞1s 然后主线程结束,子线程继续执行
#2 如果不设置timeout参数就等子线程结束主线程再结束
#3 如果设置了setDaemon=True和timeout=1主线程等待1s后会强制杀死子线程然后主线程结束
print('---主线程结束---')
if __name__=='__main___':
main()
```
## 7.7 解释以下什么是锁,有哪几种锁?
锁(Lock)是python提供的对线程控制的对象。有互斥锁可重入锁死锁。
## 7.8 什么是死锁?
若干子线程在系统资源竞争时,都在等待对方对某部分资源解除占用状态,结果是谁也不愿先解锁,互相干等着,程序无法执行下去,这就是死锁。
GIL锁 全局解释器锁只在cython里才有
作用: 限制多线程同时执行保证同一时间只有一个线程执行所以cython里的多线程其实是伪多线程
所以python里常常使用协程技术来代替多线程协程是一种更轻量级的线程。
进程和线程的切换时由系统决定而协程由我们程序员自己决定而模块gevent下切换是遇到了耗时操作时才会切换
三者的关系:进程里有线程,线程里有协程。
## 7.9 多线程交互访问数据,如果访问到了就不访问了?
怎么避免重读?
创建一个已访问数据列表,用于存储已经访问过的数据,并加上互斥锁,在多线程访问数据的时候先查看数据是否在已访问的列表中,若已存在就直接跳过。
## 7.10 什么是线程安全,什么是互斥锁?
每个对象都对应于一个可称为’互斥锁‘的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
同一进程中的多线程之间是共享系统资源的,多个线程同时对一个对象进行操作,一个线程操作尚未结束,另一线程已经对其进行操作,导致最终结果出现错误,此时需要对被操作对象添加互斥锁,保证每个线程对该对象的操作都得到正确的结果。
## 7.11说说下面几个概念:同步,异步,阻塞,非阻塞?
同步: 多个任务之间有先后顺序执行,一个执行完下个才能执行。
异步: 多个任务之间没有先后顺序,可以同时执行,有时候一个任务可能要在必要的时候获取另一个同时执行的任务的结果,这个就叫回调!
阻塞: 如果卡住了调用者,调用者不能继续往下执行,就是说调用者阻塞了。
非阻塞: 如果不会卡住,可以继续执行,就是说非阻塞的。
同步异步相对于多任务而言,阻塞非阻塞相对于代码执行而言。
## 7.12 什么是僵尸进程和孤儿进程?怎么避免僵尸进程?
孤儿进程: 父进程退出子进程还在运行的这些子进程都是孤儿进程孤儿进程将被init 进程进程号为1所收养并由init 进程对他们完成状态收集工作。
僵尸进程: 进程使用fork 创建子进程如果子进程退出而父进程并没有调用wait 获waitpid 获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中的这些进程是僵尸进程。
避免僵尸进程的方法:
1.fork 两次用孙子进程去完成子进程的任务
2.用wait()函数使父进程阻塞
3.使用信号量在signal handler 中调用waitpid,这样父进程不用阻塞
## 7.13 python中进程与线程的使用场景
多进程适合在CPU密集操作cpu操作指令比较多如位多的的浮点运算
多线程适合在IO密性型操作读写数据操作比多的的比如爬虫
## 7.14 线程是并发还是并行,进程是并发还是并行?
线程是并发,进程是并行;
进程之间互相独立,是系统分配资源的最小单位,同一个线程中的所有线程共享资源。
## 7.15 并行(parallel)和并发concurrency)?
并行: 同一时刻多个任务同时在运行
并发: 在同一时间间隔内多个任务都在运行,但是并不会在同一时刻同时运行,存在交替执行的情况。
实现并行的库有: multiprocessing
实现并发的库有: threading
程序需要执行较多的读写、请求和回复任务的需要大量的IO操作IO密集型操作使用并发更好。
CPU运算量大的程序使用并行会更好
## 7.16 IO密集型和CPU密集型区别
IO密集型 系统运行大部分的状况是CPU在等 I/O硬盘/内存)的读/写
CPU密集型 大部分时间用来做计算逻辑判断等CPU动作的程序称之CPU密集型。
## 7.17 python asyncio的原理
asyncio这个库就是使用python的yield这个可以打断保存当前函数的上下文的机制 封装好了selector 摆脱掉了复杂的回调关系
# 三.Web
## 1、Flask
## 1.1 对Flask蓝图(Blueprint)的理解?
蓝图的定义
蓝图 /Blueprint 是Flask应用程序组件化的方法可以在一个应用内或跨越多个项目共用蓝图。使用蓝图可以极大简化大型应用的开发难度也为Flask扩展提供了一种在应用中注册服务的集中式机制。
蓝图的应用场景:
把一个应用分解为一个蓝图的集合。这对大型应用是理想的。一个项目可以实例化一个应用对象,初始化几个扩展,并注册一集合的蓝图。
以URL前缀和/或子域名在应用上注册一个蓝图。URL前缀/子域名中的参数即成为这个蓝图下的所有视图函数的共同的视图参数(默认情况下)
在一个应用中用不同的URL规则多次注册一个蓝图。
通过蓝图提供模板过滤器、静态文件、模板和其他功能。一个蓝图不一定要实现应用或视图函数。
初始化一个Flask扩展时在这些情况中注册一个蓝图。
蓝图的缺点:
不能在应用创建后撤销注册一个蓝图而不销毁整个应用对象。
使用蓝图的三个步骤
1.创建一个蓝图对象
```
blue = Blueprint("blue",__name__)
```
2.在这个蓝图对象上进行操作,例如注册路由、指定静态文件夹、注册模板过滤器...
```
@blue.route('/')
def blue_index():
return "Welcome to my blueprint"
```
3.在应用对象上注册这个蓝图对象
```
app.register_blueprint(blue,url_prefix="/blue")
```
## 1.2 Flask 和 Django 路由映射的区别?
在django中路由是浏览器访问服务器时先访问的项目中的url再由项目中的url找到应用中url这些url是放在一个列表里遵从从前往后匹配的规则。在flask中路由是通过装饰器给每个视图函数提供的而且根据请求方式的不同可以一个url用于不同的作用。
## 2、 Django
## 2.1、什么是wsgi,uwsgi,uWSGI?
WSGI:
web服务器网关接口是一套协议。用于接收用户请求并将请求进行初次封装然后将请求交给web框架。
实现wsgi协议的模块wsgiref,本质上就是编写一socket服务端用于接收用户请求django)
werkzeug,本质上就是编写一个socket服务端用于接收用户请求(flask)
uwsgi:
与WSGI一样是一种通信协议它是uWSGI服务器的独占协议用于定义传输信息的类型。
uWSGI:
是一个web服务器实现了WSGI的协议uWSGI协议http协议
## 2.2、 Django、Flask、Tornado的对比
1、 Django走的大而全的方向开发效率高。它的MTV框架自带的ORM,admin后台管理,自带的sqlite数据库和开发测试用的服务器给开发者提高了超高的开发效率。
重量级web框架功能齐全提供一站式解决的思路能让开发者不用在选择上花费大量时间。
自带ORM和模板引擎支持jinja等非官方模板引擎。
自带ORM使Django和关系型数据库耦合度高如果要使用非关系型数据库需要使用第三方库
自带数据库管理app
成熟稳定开发效率高相对于FlaskDjango的整体封闭性比较好适合做企业级网站的开发。python web框架的先驱第三方库丰富
2、 Flask 是轻量级的框架自由灵活可扩展性强核心基于Werkzeug WSGI工具 和jinja2 模板引擎
适用于做小网站以及web服务的API,开发大型网站无压力,但架构需要自己设计
与关系型数据库的结合不弱于Django而与非关系型数据库的结合远远优于Django
3、 Tornado走的是少而精的方向性能优越它最出名的异步非阻塞的设计方式
Tornado的两大核心模块
iostraem:对非阻塞的socket进行简单的封装
ioloop: 对I/O 多路复用的封装,它实现一个单例
## 2.3 CORS 和 CSRF的区别
什么是CORS
CORS是一个W3C标准,全称是“跨域资源共享"(Cross-origin resoure sharing).
它允许浏览器向跨源服务器发出XMLHttpRequest请求从而客服了AJAX只能同源使用的限制。
什么是CSRF
CSRF主流防御方式是在后端生成表单的时候生成一串随机token,内置到表单里成为一个字段同时将此串token置入session中。每次表单提交到后端时都会检查这两个值是否一致以此来判断此次表单提交是否是可信的提交过一次之后如果这个页面没有生成CSRF token,那么token将会被清空,如果有新的需求那么token会被更新。
攻击者可以伪造POST表单提交但是他没有后端生成的内置于表单的tokensession中没有token都无济于事。
## 2.4 Session,Cookie,JWT的理解
为什么要使用会话管理
众所周知HTTP协议是一个无状态的协议也就是说每个请求都是一个独立的请求请求与请求之间并无关系。但在实际的应用场景这种方式并不能满足我们的需求。举个大家都喜欢用的例子把商品加入购物车单独考虑这个请求服务端并不知道这个商品是谁的应该加入谁的购物车因此这个请求的上下文环境实际上应该包含用户的相关信息在每次用户发出请求时把这一小部分额外信息也做为请求的一部分这样服务端就可以根据上下文中的信息针对具体的用户进行操作。所以这几种技术的出现都是对HTTP协议的一个补充使得我们可以用HTTP协议+状态管理构建一个的面向用户的WEB应用。
Session 和Cookie的区别
这里我想先谈谈session与cookies,因为这两个技术是做为开发最为常见的。那么session与cookies的区别是什么个人认为session与cookies最核心区别在于额外信息由谁来维护。利用cookies来实现会话管理时用户的相关信息或者其他我们想要保持在每个请求中的信息都是放在cookies中,而cookies是由客户端来保存每当客户端发出新请求时就会稍带上cookies,服务端会根据其中的信息进行操作。
当利用session来进行会话管理时客户端实际上只存了一个由服务端发送的session_id,而由这个session_id,可以在服务端还原出所需要的所有状态信息,从这里可以看出这部分信息是由服务端来维护的。
除此以外session与cookies都有一些自己的缺点
cookies的安全性不好攻击者可以通过获取本地cookies进行欺骗或者利用cookies进行CSRF攻击。使用cookies时,在多个域名下,会存在跨域问题。
session 在一定的时间里需要存放在服务端因此当拥有大量用户时也会大幅度降低服务端的性能当有多台机器时如何共享session也会是一个问题.(redis集群)也就是说用户第一个访问的时候是服务器A而第二个请求被转发给了服务器B那服务器B如何得知其状态。实际上session与cookies是有联系的比如我们可以把session_id存放在cookies中的。
JWT是如何工作的
首先用户发出登录请求服务端根据用户的登录请求进行匹配如果匹配成功将相关的信息放入payload中利用算法加上服务端的密钥生成token这里需要注意的是secret_key很重要如果这个泄露的话客户端就可以随机篡改发送的额外信息它是信息完整性的保证。生成token后服务端将其返回给客户端客户端可以在下次请求时将token一起交给服务端一般是说我们可以将其放在Authorization首部中这样也就可以避免跨域问题。
## 2.5 简述Django请求生命周期
一般是用户通过浏览器向我们的服务器发起一个请求(request),这个请求会去访问视图函数,如果不涉及到数据调用,那么这个时候视图函数返回一个模板也就是一个网页给用户)
视图函数调用模型毛模型去数据库查找数据,然后逐级返回,视图函数把返回的数据填充到模板中空格中,最后返回网页给用户。
1.wsgi ,请求封装后交给web框架FlaskDjango)
2.中间件对请求进行校验或在请求对象中添加其他相关数据例如csrf,request.session
3.路由匹配 根据浏览器发送的不同url去匹配不同的视图函数
4.视图函数在视图函数中进行业务逻辑的处理可能涉及到ormtemplates
5.中间件,对响应的数据进行处理
6.wsgi将响应的内容发送给浏览器
## 2.6 用的restframework完成api发送时间时区
当前的问题是用django的rest framework模块做一个get请求的发送时间以及时区信息的api
```
class getCurrenttime(APIView):
def get(self,request):
local_time = time.localtime()
time_zone =settings.TIME_ZONE
temp = {'localtime':local_time,'timezone':time_zone}
return Response(temp)
```
## 2.7 nginx,tomcat,apach到都是什么
Nginxengine x)是一个高性能的HTTP和反向代理服务器也是 一个IMAP/POP3/SMTP服务器工作在OSI七层负载的实现方式轮询IP_HASH,fair,session_sticky.
Apache HTTP Server是一个模块化的服务器源于NCSAhttpd服务器
Tomcat 服务器是一个免费的开放源代码的Web应用服务器属于轻量级应用服务器是开发和调试JSP程序的首选。
## 2.8 请给出你熟悉关系数据库范式有哪些,有什么作用?
在进行数据库的设计时,所遵循的一些规范,只要按照设计规范进行设计,就能设计出没有数据冗余和数据维护异常的数据库结构。
数据库的设计的规范有很多,通常来说我们在设是数据库时只要达到其中一些规范就可以了,这些规范又称之为数据库的三范式,一共有三条,也存在着其他范式,我们只要做到满足前三个范式的要求,就能设陈出符合我们的数据库了,我们也不能全部来按照范式的要求来做,还要考虑实际的业务使用情况,所以有时候也需要做一些违反范式的要求。
1.数据库设计的第一范式(最基本),基本上所有数据库的范式都是符合第一范式的,符合第一范式的表具有以下几个特点:
数据库表中的所有字段都只具有单一属性,单一属性的列是由基本的数据类型(整型,浮点型,字符型等)所构成的设计出来的表都是简单的二比表
2.数据库设计的第二范式(是在第一范式的基础上设计的),要求一个表中只具有一个业务主键,也就是说符合第二范式的表中不能存在非主键列对只对部分主键的依赖关系
3.数据库设计的第三范式,指每一个非主属性既不部分依赖与也不传递依赖于业务主键,也就是第二范式的基础上消除了非主属性对主键的传递依赖
## 2.9 简述QQ登陆过程
qq登录在我们的项目中分为了三个接口
第一个接口是请求qq服务器返回一个qq登录的界面;
第二个接口是通过扫码或账号登陆进行验证qq服务器返回给浏览器一个code和state,利用这个code通过本地服务器去向qq服务器获取access_token覆返回给本地服务器凭借access_token再向qq服务器获取用户的openid(openid用户的唯一标识)
第三个接口是判断用户是否是第一次qq登录如果不是的话直接登录返回的jwt-token给用户对没有绑定过本网站的用户对openid进行加密生成token进行绑定
## 2.10 post 和 get的区别?
1.GET是从服务器上获取数据POST是向服务器传送数据
2.在客户端GET方式在通过URL提交数据数据在URL中可以看到POST方式数据放置在HTML——HEADER内提交
3.对于GET方式服务器端用Request.QueryString获取变量的值对于POST方式服务器端用Request.Form获取提交的数据
4.GET方式提交的数据最多只能有1024字节而POST则没有限制
安全性问题,正如在(2)中提到使用GET的时候参数会显示在地址栏上而POST不会。所以如果这些数据是中文数据而且是非敏感数据那么使用GET如果用户输入的数据不是中文字符而且包含敏感数据那么还是使用POST为好
## 2.11 项目中日志的作用
一、日志相关概念
1.日志是一种可以追踪某些软件运行时所发生事件的方法
2.软件开发人员可以向他们的代码中调用日志记录相关的方法来表明发生了某些事情
3.一个事件可以用一个包含可选变量数据的消息来描述
4.此外,事件也有重要性的概念,这个重要性也可以被成为严重性级别(level)
二、日志的作用
1.通过log的分析可以方便用户了解系统或软件、应用的运行情况;
2.如果你的应用log足够丰富可以分析以往用户的操作行为、类型喜好地域分布或其他更多信息;
3.如果一个应用的log同时也分了多个级别那么可以很轻易地分析得到该应用的健康状况及时发现问题并快速定位、解决问题补救损失。
4.简单来讲就是我们通过记录和分析日志可以了解一个系统或软件程序运行情况是否正常,也可以在应用程序出现故障时快速定位问题。不仅在开发中,在运维中日志也很重要,日志的作用也可以简单。总结为以下几点:
1.程序调试
2.了解软件程序运行情况,是否正常
3,软件程序运行故障分析与问题定位
4,如果应用的日志信息足够详细和丰富,还可以用来做用户行为分析
## 2.12 django中间件的使用
Django在中间件中预置了六个方法这六个方法的区别在于不同的阶段执行对输入或输出进行干预方法如下
1.初始化:无需任何参数,服务器响应第一个请求的时候调用一次,用于确定是否启用当前中间件
```
def __init__():
pass
```
2.处理请求前在每个请求上调用返回None或HttpResponse对象。
```
def process_request(request):
pass
```
3.处理视图前:在每个请求上调用返回None或HttpResponse对象。
```
def process_view(request,view_func,view_args,view_kwargs):
pass
```
4.处理模板响应前在每个请求上调用返回实现了render方法的响应对象。
```
def process_template_response(request,response):
pass
```
5.处理响应后所有响应返回浏览器之前被调用在每个请求上调用返回HttpResponse对象。
```
def process_response(request,response):
pass
```
6.异常处理当视图抛出异常时调用在每个请求上调用返回一个HttpResponse对象。
```
def process_exception(request,exception):
pass
```
## 2.13 谈一下你对uWSGI和nginx的理解
1.uWSGI是一个Web服务器它实现了WSGI协议、uwsgi、http等协议。Nginx中HttpUwsgiModule的作用是与uWSGI服务器进行交换。WSGI是一种Web服务器网关接口。它是一个Web服务器如nginxuWSGI等服务器与web应用如用Flask框架写的程序通信的一种规范。
要注意WSGI/uwsgi/uWSGI这三个概念的区分。
WSGI是一种通信协议。
uwsgi是一种线路协议而不是通信协议在此常用于在uWSGI服务器与其他网络服务器的数据通信。
uWSGI是实现了uwsgi和WSGI两种协议的Web服务器。
nginx 是一个开源的高性能的HTTP服务器和反向代理
1.作为web服务器它处理静态文件和索引文件效果非常高
2.它的设计非常注重效率最大支持5万个并发连接但只占用很少的内存空间
3.稳定性高,配置简洁。
4.强大的反向代理和负载均衡功能,平衡集群中各个服务器的负载压力应用
## 2.14 Python中三大框架各自的应用场景
django:主要是用来搞快速开发的,他的亮点就是快速开发,节约成本,,如果要实现高并发的话就要对django进行二次开发比如把整个笨重的框架给拆掉自己写socket实现http的通信,底层用纯c,c++写提升效率ORM框架给干掉自己编写封装与数据库交互的框架,ORM虽然面向对象来操作数据库但是它的效率很低使用外键来联系表与表之间的查询;
flask: 轻量级主要是用来写接口的一个框架实现前后端分离提考开发效率Flask本身相当于一个内核其他几乎所有的功能都要用到扩展(邮件扩展Flask-Mail用户认证Flask-Login),都需要用第三方的扩展来实现。比如可以用Flask-extension加入ORM、文件上传、身份验证等。Flask没有默认使用的数据库你可以选择MySQL也可以用NoSQL。
其WSGI工具箱用Werkzeug(路由模块)模板引擎则使用Jinja2,这两个也是Flask框架的核心。
Tornado Tornado是一种Web服务器软件的开源版本。Tornado和现在的主流Web服务器框架包括大多数Python的框架有着明显的区别它是非阻塞式服务器而且速度相当快。得利于其非阻塞的方式和对epoll的运用Tornado每秒可以处理数以千计的连接因此Tornado是实时Web服务的一个理想框架
## 2.17 Django中哪里用到了线程哪里用到了协程哪里用到了进程
1.Django中耗时的任务用一个进程或者线程来执行比如发邮件使用celery.
2.部署django项目是时候配置文件中设置了进程和协程的相关配置。
## 2.18 有用过Django REST framework吗
Django REST framework是一个强大而灵活的Web API工具。使用RESTframework的理由有
Web browsable API对开发者有极大的好处
包括OAuth1a和OAuth2的认证策略
支持ORM和非ORM数据资源的序列化
全程自定义开发--如果不想使用更加强大的功能可仅仅使用常规的function-based views额外的文档和强大的社区支持
## 2.19 对cookies与session的了解他们能单独用吗
Session采用的是在服务器端保持状态的方案而Cookie采用的是在客户端保持状态的方案。但是禁用Cooki就不能得到Session。因为Session是用Session ID来确定当前对话所对应的服务器Session而Session ID是通过Cookie来传递的禁用Cookie相当于SessionID,也就得不到Session。