一.基础语法
1.输入与输出
1.1 print 调用 Python 中底层的什么方法?
print 方法默认调用 sys.stdout.write 方法,即往控制台打印字符串
1.2 简述你对 input()函数的理解?
在 Python3 中,input()获取用户输入,不论用户输入的是什么,获取到的都是字符串类型的。
在 Python2 中有 raw_input()和 input(), raw_input()和 Python3 中的 input()作用是一样的,input()输入的是什么数据类型的,获取到的就是什么数据类型的。
2.条件与循环
2.1 range 和 xrange 的区别?
两者用法相同,不同的是 range 返回的结果是一个列表,而 xrange 的结果是一个生成器,前者是直接开辟一块内存空间来保存列表,后者是边循环边使用,只有使用时才会开辟内存空间,所以当列表很长时,使用 xrange 性能要比 range 好
2.2 比较两个输出结果l1 versus l2
l1 = []
for i in range(10):
l1.append({"num": i})
print(l1)
l2 = []
a = {"num": 0}
for i in range(10):
a['num'] = i
l2.append(a)
print(l2)
3.文件操作
3.1 4G 内存怎么读取一个 5G 的数据?
方法一:
可以通过生成器,分多次读取,每次读取数量相对少的数据(比如 500MB)进行处理,处理结束后再读取后面的 500MB 的数据。
方法二:
可以通过 linux 命令 split 切割成小文件,然后再对数据进行处理,此方法效率比较高。可以按照行数切割,可以按照文件大小切割。
3.2 大文件处理
现在考虑有一个 jsonline 格式的文件 file.txt 大小约为 10K,之前处理文件的
代码如下所示
def process(): # process the data
pass
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():
l = []
with open('file.txt', 'rb') as f:
data = f.readlines(60000)
l.append(data)
yield l
要考虑到的问题有:
内存只有 4G 无法一次性读入 10G 的文件,需要分批读入。分批读入数据要记录每次读入数据的位置。分批每次读入数据的大小,太小就会在读取操作上花费过多时间。
3.3 read、readline 和 readlines 的区别?
read:读取整个文件。
readline:读取下一行,使用生成器方法。
readlines:读取整个文件到一个迭代器以供我们遍历
3.4 一个打印路径的函数
def print_directory_contents(sPath):
"""
这个函数接收文件夹的名称作为输入参数
返回该文件夹中文件的路径
以及其包含文件夹中的文件路径
:param sPath:
:return:
"""
import os
for sChildPath in os.listdir(sPath):
sChildPath = os.path.join(sPath, sChildPath)
if os.path.isdir(sChildPath):
print_directory_contents(sChildPath)
else:
print(sChildPath)
4. 异常
4.1 介绍一下 except 的作用和用法?
except: #捕获所有异常
except: <异常名>: #捕获指定异常
except:<异常名 1, 异常名 2> : 捕获异常 1 或者异常 2
except:<异常名>,<数据>:捕获指定异常及其附加的数据
except:<异常名 1,异常名 2>:<数据>:捕获异常名 1 或者异常名 2,及附加的数据
5. 模块和包
5.1 常用的 Python 标准库都有哪些?
内置模块:
os 操作系统,time 时间,random 随机,pymysql 连接数据库,threading 线程,multiprocessing进程,queue 队列。
第三方库:
django 和 flask 也是第三方库,requests,virtualenv,selenium,scrapy,xadmin,celery,
re,hashlib,md5。
常用的科学计算库(如 Numpy,Scipy,Pandas)。
5.2 赋值、浅拷贝和深拷贝的区别?
assignment:
在 Python 中,对象的赋值就是简单的对象引用,这点和 C++不同,如下所示
a = [1, 2, 'hello', ['python', 'C++']]
b = a
在上述情况下,a 和 b 是一样的,他们指向同一片内存,b 不过是 a 的别名,是引用.
我们可以使用 b is a 去判断,返回 True,表明他们地址相同,内容相同,也可以使用 id()函数来查看两个列表的地址是否相同。
赋值操作(包括对象作为参数、返回值)不会开辟新的内存空间,它只是复制了对象的引用。也就是说除了 b 这个名字之外,没有其他的内存开销。修改了 a,也就影响了 b,同理,修改了 b,也就影响了 a。
shallow copy:
浅拷贝会创建新对象,其内容非原对象本身的引用,而是原对象内第一层对象的引用。
浅拷贝有三种形式:切片操作、工厂函数、copy 模块中的 copy 函数。
比如上述的列表 a;
切片操作:b = a[:] 或者 b = [x for x in a];
工厂函数:b = list(a);
copy 函数:b = copy.copy(a);
浅拷贝产生的列表 b 不再是列表 a 了,使用 is 判断可以发现他们不是同一个对象,使用 id 查看,他们也不指向同一片内存空间。但是当我们使用 id(x) for x in a 和 id(x) for x in b 来查看 a 和 b 中元素的地址时,可以看到二者包含的元素的地址是相同的。
在这种情况下,列表 a 和 b 是不同的对象,修改列表 b 理论上不会影响到列表 a。但是要注意的是,浅拷贝之所以称之为浅拷贝,是它仅仅只拷贝了一层,在列表 a 中有一个嵌套的list,如果我们修改了它,情况就不一样了。
比如:a[3].append('java')。查看列表 b,会发现列表 b 也发生了变化,这是因为,我们修改了嵌套的 list,修改外层元素,会修改它的引用,让它们指向别的位置,修改嵌套列表中的元素,列表的地址并未发生变化,指向的都是用一个位置。
deep copy
深拷贝只有一种形式,copy 模块中的 deepcopy()函数。
深拷贝和浅拷贝对应,深拷贝拷贝了对象的所有元素,包括多层嵌套的元素。因此,它的时间和空间开销要高。
同样的对列表 a,如果使用 b = copy.deepcopy(a),再修改列表 b 将不会影响到列表 a,即使嵌套的列表具有更深的层次,也不会产生任何影响,因为深拷贝拷贝出来的对象根本就是一个全新的对象,不再与原来的对象有任何的关联。
拷贝注意点
对于非容器类型,如数字、字符,以及其他的“原子”类型,没有拷贝一说,产生的都是原对象的引用。
如果元组变量值包含原子类型对象,即使采用了深拷贝,也只能得到浅拷贝。
5.3 双下方法init和new的区别?
__init__ # initial 在对象创建后,对对象进行初始化
__new__ # 是在对象创建之前,开辟一个对象空间,并将该对象空间返回给__init__
5.4 说明os.path 和 sys.path 的区别?
# os.path 主要是用于对系统路径文件的操作
# sys.path 主要是对 Python 解释器的系统环境参数的操作(动态的改变 Python 解释器搜索路径)
5.5unittest是什么?
# 在 Python 中,unittest 是 Python 中的单元测试框架。它拥有支持共享搭建、自动测试、在测试
# 中暂停代码、将不同测试迭代成一组,等的功能。
5.6模块和包是什么?
# 在 Python 中,模块是搭建程序的一种方式。每一个 Python 代码文件都是一个模块,并可以引用
# 其他的模块,比如对象和属性。
# 一个包含许多 Python 代码的文件夹是一个包。一个包可以包含模块和子文件夹
6.Python特性
6.1 Python 是强语言类型还是弱语言类型?
# 强类型:不允许不同类型相加
# 动态:不使用显示数据类型声明,且确定一个变量的类型是在第一次给它赋值的时候
# 脚本语言:一般也是解释型语言,运行代码只需要一个解释器,不需要编译。
Python 是强类型的动态脚本语言
6.2谈一下什么是解释性语言,什么是编译性语言?
# 计算机不能直接理解高级语言,只能直接理解机器语言,所以必须要把高级语言翻译成机器语言,
# 计算机才能执行高级语言编写的程序
# 解释性语言在运行程序的时候才会进行翻译
# 编译型语言写的程序在执行之前,需要一个专门的编译过程,把程序编译成机器语言(可执行文件)
6.3 Python 是如何进行类型转换的?
内建函数封装了各种转换函数,可以使用目标类型关键字强制类型转换,进制之间的转换可以用
int(‘str’,base=’n’)将特定进制的字符串转换为十进制,再用相应的进制转换函数将十进制转换
为目标进制。
可以使用内置函数直接转换的有:
list(tuple_01)
tuple(list_01)
6.3 Python2 与 Python3 的区别?
1) 核心类差异
Python3 对 Unicode 字符的原生支持。
Python2 中使用 ASCII 码作为默认编码方式导致 string 有两种类型 str 和 unicode,Python3 只
支持 unicode 的 string。Python2 和 Python3 字节和字符对应关系为:
python2
python3
表现
转换
作用
str
bytes
字节
encode
存储
unicode
str
字符
decode
显示
Python3 采用的是绝对路径的方式进行 import
Python2中存在老式类和新式类的区别,Python3统一采用新式类。新式类声明要求继承object,
必须用新式类应用多重继承
Python3 使用更加严格的缩进。Python2 的缩进机制中,1 个 tab 和 8 个 space 是等价的,所
以在缩进中可以同时允许 tab 和 space 在代码中共存。这种等价机制会导致部分 IDE 使用存在问题。
Python3 中 1 个 tab 只能找另外一个 tab 替代,因此 tab 和 space 共存会导致报错:TabError:
inconsistent use of tabs and spaces in indentation.
2) 废弃类差异
print 语句被 Python3 废弃,统一使用 print 函数
exec 语句被 python3 废弃,统一使用 exec 函数
execfile 语句被 Python3 废弃,推荐使用 exec(open("./filename").read())
不相等操作符"<>"被 Python3 废弃,统一使用"!="
long 整数类型被 Python3 废弃,统一使用 int
xrange 函数被 Python3 废弃,统一使用 range,Python3 中 range 的机制也进行修改并提高
了大数据集生成效率
Python3 中这些方法再不再返回 list 对象:dictionary 关联的 keys()、values()、items(),zip(),
map(),filter(),但是可以通过 list 强行转换:
mydict = dict()
mydict = {"a": 1, "b": 2, "c": 3}
mydict.keys() #
list(mydict.keys()) # ['a', 'c', 'b']
迭代器 iterator 的 next()函数被 Python3 废弃,统一使用 next(iterator)
raw_input 函数被 Python3 废弃,统一使用 input 函数
字典变量的 has_key 函数被 Python 废弃,统一使用 in 关键词
file 函数被 Python3 废弃,统一使用 open 来处理文件,可以通过 io.IOBase 检查文件类型
apply 函数被 Python3 废弃
异常 StandardError 被 Python3 废弃,统一使用 Exception
3)修改类差异
浮点数除法操作符“/”和“//”的区别
“ / ”:
Python2:若为两个整形数进行运算,结果为整形,但若两个数中有一个为浮点数,则结果为
浮点数;
Python3:为真除法,运算结果不再根据参加运算的数的类型。
“//”:
Python2:返回小于除法运算结果的最大整数;从类型上讲,与"/"运算符返回类型逻辑一致。
Python3:和 Python2 运算结果一样。
异常抛出和捕捉机制区别
python2
raise IOError, "file error" # 抛出异常
except NameError, err: # 捕捉异常
python3
raise IOError("file error") #抛出异常
except NameError as err: #捕捉异常
for 循环中变量值区别
Python2,for 循环会修改外部相同名称变量的值
i = 1
print('comprehension: ', [i for i in range(5)])
print('after:i = ', i) # i = 4
Python3,for 循环不会修改外部相同名称变量的值
i = 1
print("comprehension: ", [i for i in range(5)])
print('after: i = ', i) # i = 1
round 函数返回值区别
Python2,round 函数返回 float 类型值
isinstance(round(15.5),int) #True
Python3,round 函数返回 int 类型值
isinstance(round(15.5),float) #True
比较操作符区别
Python2 中任意两个对象都可以比较
11 < 'test' # True
Python3 中只有同一数据类型的对象可以比较
11 < 'test' # TypeError: unorderable types: int() < str()
4)第三方工具包差异
我们在pip官方下载源pypi搜索Python2.7和Python3.5的第三方工具包数可以发现,Python2.7
版本对应的第三方工具类目数量是 28523,Python3.5 版本的数量是 12457,这两个版本在第三方工具
包支持数量差距相当大。
我们从数据分析的应用角度列举了常见实用的第三方工具包(如下表),并分析这些工具包在
Python2.7 和 Python3.5 的支持情况:
分类
工具名
用途
数据收集
scrapy
网页采集,爬虫
数据收集
scrapy-redis
分布式爬虫
数据收集
selenium
web 测试,仿真浏览器
数据处理
beautifulsoup
网页解释库,提供 lxml 的支持
数据处理
lxml
xml 解释库
数据处理
xlrd
excel 文件读取
数据处理
xlwt
excel 文件写入
数据处理
xlutils
excel 文件简单格式修改
数据处理
pywin32
excel 文件的读取写入及复杂格式定制
数据处理
Python-docx
Word 文件的读取写入
数据分析
numpy
基于矩阵的数学计算库
数据分析
pandas
基于表格的统计分析库
数据分析
scipy
科学计算库,支持高阶抽象和复杂模型
数据分析
statsmodels
统计建模和计量经济学工具包
数据分析
scikit-learn
机器学习工具库
数据分析
gensim
自然语言处理工具库
数据分析
jieba
中文分词工具库
数据存储
MySQL-python
mysql 的读写接口库
数据存储
mysqlclient
mysql 的读写接口库
数据存储
SQLAlchemy
数据库的 ORM 封装
数据存储
pymsql
sql server 读写接口库
数据存储
redis
redis 的读写接口
数据存储
PyMongo
mongodb 的读写接口
数据呈现
matplotlib
流行的数据可视化库
数据呈现
seaborn
美观的数据可是湖库,基于 matplotlib
工具辅助
chardet
字符检查工具
工具辅助
ConfigParser
配置文件读写支持
工具辅助
requests
HTTP 库,用于网络访问
5)工具安装问题
windows 环境
Python2 无法安装 mysqlclient。Python3 无法安装 MySQL-python、 flup、functools32、Gooey、Pywin32 、webencodings。
matplotlib 在 python3 环境中安装报错:The following required packages can not be built:freetype, png。需要手动下载安装源码包安装解决。
scipy 在 Python3 环境中安装报错,numpy.distutils.system_info.NotFoundError,需要自己手工下载对应的安装包,依赖 numpy,pandas 必须严格根据 python 版本、操作系统、64 位与否。运行matplotlib 后发现基础包 numpy+mkl 安装失败,需要自己下载,国内暂无下载源
centos 环境下
Python2 无法安装mysql-python和 mysqlclient包,报错:EnvironmentError: mysql_config not found,解决方案是安装 mysql-devel 包解决。使用 matplotlib 报错:no module named _tkinter,安装 Tkinter、tk-devel、tc-devel 解决。
pywin32 也无法在 centos 环境下安装
6.4关于 Python 程序的运行方面,有什么手段能提升性能?
使用多进程,充分利用机器的多核性能
对于性能影响较大的部分代码,可以使用 C 或 C++编写
对于 IO 阻塞造成的性能影响,可以使用 IO 多路复用来解决
尽量使用 Python 的内建函数
尽量使用局部变量
6.5 什么是 Python?
Python 是一种编程语言,它有对象、模块、线程、异常处理和自动内存管理,可以加入其他语言的对比
Python 是一种解释型语言,Python 在代码运行之前不需要解释
Python 是动态类型语言,在声明变量时,不需要说明变量的类型
Python 适合面向对象的编程,因为它支持通过组合与继承的方式定义类
在 Python 语言中,函数是第一类对象
Python 代码编写快,但是运行速度比编译型语言通常要慢
Python 用途广泛,常被用走"胶水语言",可帮助其他语言和组件改善运行状况
使用 Python,程序员可以专注于算法和数据结构的设计,而不用处理底层的细节
6.6 什么是 Python 自省?
Python 自省是 Python 具有的一种能力,使程序员面向对象的语言所写的程序在运行时,能够获得对象的类Python 型。Python 是一种解释型语言,为程序员提供了极大的灵活性和控制力
6.7 你所遵循的代码规范是什么?请举例说明其要求?
PEP8 规范。
变量
# 常量:大写加下划线
USER_CONSTANT = "a constant"
# 私有变量 : 小写和一个前导下划线
"""
Python 中不存在私有变量一说,若是遇到需要保护的变量,使用小写和一个前导下划线。但这只是
程序员之间的一个约定,用于警告说明这是一个私有变量,外部类不要去访问它。但实际上,外部类还
是可以访问到这个变量。
"""
_private_value = "my private value"
# 内置变量 : 小写,两个前导下划线和两个后置下划线
"""
两个前导下划线会导致变量在解释期间被更名。这是为了避免内置变量和其他变量产生冲突。用户
定义的变量要严格避免这种风格。以免导致混乱
"""
__class__ = "inner value"
函数和方法
总体而言应该使用,小写和下划线。但有些比较老的库使用的是混合大小写,即首单词小写,之后每个单词第一个字母大写,其余小写。但现在,小写和下划线已成为规范
私有方法 :小写和一个前导下划线
这里和私有变量一样,并不是真正的私有访问权限。同时也应该注意一般函数不要使用两个前导下划线(当遇到两个前导下划线时,Python 的名称改编特性将发挥作用)。
特殊方法 :小写和两个前导下划线,两个后置下划线
这种风格只应用于特殊函数,比如操作符重载等。
函数参数 : 小写和下划线,缺省值等号两边无空格
类
类总是使用驼峰格式命名,即所有单词首字母大写其余字母小写。类名应该简明,精确,并足以从
中理解类所完成的工作。常见的一个方法是使用表示其类型或者特性的后缀,例如:
SQLEngine,MimeTypes 对于基类而言,可以使用一个 Base 或者 Abstract 前缀 BaseCookie,
AbstractGroup
模块和包
除特殊模块 init 之外,模块名称都使用不带下划线的小写字母。
若是它们实现一个协议,那么通常使用 lib 为后缀,例如:
import smtplib
import os
import sys
关于参数
不要用断言来实现静态类型检测。断言可以用于检查参数,但不应仅仅是进行静态类型检测。
Python 是动态类型语言,静态类型检测违背了其设计思想。断言应该用于避免函数不被毫无意义的调用。
不要滥用 *args 和 **kwargs。*args 和 **kwargs 参数可能会破坏函数的健壮性。它们使签名变得模糊,而且代码常常开始在不应该的地方构建小的参数解析器。
其它
# 使用 has 或 is 前缀命名布尔元素
is_connect = True
has_member = False
# 用复数形式命名序列
members = ['user_1', 'user_2']
# 用显式名称命名字典
person_address = {'user_1': '10 road WD', 'user_2': '20 street huafu'}
# 避免通用名称
诸如 list, dict, sequence 或者 element 这样的名称应该避免
# 避免现有名称
诸如 os, sys 这种系统已经存在的名称应该避免
一些数字
一行列数 : PEP 8 规定为 79 列。根据自己的情况,比如不要超过满屏时编辑器的显示数。
一个函数 : 不要超过 30 行代码, 即可显示在一个屏幕类,可以不使用垂直游标即可看到整函数。
一个类 : 不要超过 200 行代码,不要有超过 10 个方法。一个模块 不要超过 500 行。
验证脚本
可以安装一个 pep8 脚本用于验证你的代码风格是否符合 PEP8
7.Linux基础和git
7.1 Linux 的基本命令(怎么区分一个文件还是文件夹)?
# 在显示名称的时候会在文件夹后添加“/”,在文件后面加“*”
ls -F
7.2日志以什么格式,存放在哪里?
日志以文本可以存储在“/var/log/”目录下后缀名为.log
7.3 Linux 查看某个服务的端口?
netstat -anp | grep service_name
7.4ubuntu 系统如何设置开机自启动一个程序?
直接修改/etc/rc0.d ~ /etc/rc6.d 和/etc/rcS.d 文件夹的内容,添加需启动的程序,S 开头的表示启动,K 开头的表示不启动
7.5 在 linux 中 find 和 grep 的区别?
Linux 系统中 grep 命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。grep 全称是 Global Regular Expression Print,表示全局正则表达式版本,它的使用权限是所有用户。
linux 下的 find:
功能:在目录结构中搜索文件,并执行指定的操作。此命令提供了相当多的查找条件,功能很强大。
语法:find 起始目录寻找条件操作
说明:find 命令从指定的起始目录开始,递归地搜索其各个子目录,查找满足寻找条件的文件并对之采取相关的操作。
简单点说说,grep 是查找匹配条件的行,find 是搜索匹配条件的文件
7.6Linux 重定向命令有哪些?有什么区别?
1、重定向>
Linux 允许将命令执行结果重定向到一个文件,本应显示在终端上的内容保存到指定文件中。如:ls >test.txt ( test.txt 如果不存在,则创建,存在则覆盖其内容 )。
2、重定向>>
这个是将输出内容追加到目标文件中。如果文件不存在,就创建文件;如果文件存在,则将新的内容追加到那个文件的末尾,该文件中的原有内容不受影响。
7.7 软连接和硬链接的区别?
软连接类似 Windows 的快捷方式,当删除源文件时,那么软链接也失效了。
硬链接可以理解为源文件的一个别名,多个别名所代表的是同一个文件。当 rm 一个文件的时候,那么此文件的硬链接数减1,当硬链接数为 0 的时候,文件被删除。
7.8 10 个常用的 Linux 命令?
pwd 显示工作路径
ls 查看目录中的文件
cd /home 进入 '/ home' 目录'
cd .. 返回上一级目录
cd ../.. 返回上两级目录
mkdir dir1 创建一个叫做 'dir1' 的目录'
rm -f file1 删除一个叫做 'file1' 的文件',-f 参数,忽略不存在的文件,从不给出提示。
rmdir dir1 删除一个叫做 'dir1' 的目录'
groupadd group_name 创建一个新用户组
groupdel group_name 删除一个用户组
tar -cvf archive.tar file1 创建一个非压缩的 tarball
tar -cvf archive.tar file1 file2 dir1 创建一个包含了 'file1', 'file2' 以及 'dir1'的档案文件
tar -tf archive.tar 显示一个包中的内容
tar -xvf archive.tar 释放一个包
tar -xvf archive.tar -C /tmp 将压缩包释放到 /tmp 目录下
tar -cvfj archive.tar.bz2 dir1 创建一个 bzip2 格式的压缩包
tar -xvfj archive.tar.bz2 解压一个 bzip2 格式的压缩包
tar -cvfz archive.tar.gz dir1 创建一个 gzip 格式的压缩包
tar -xvfz archive.tar.gz 解压一个 gzip 格式的压缩包
7.9 Linux 关机命令有哪些?
reboot 重新启动操作系统
shutdown –r now 重新启动操作系统,shutdown 会给别的用户提示
shutdown -h now 立刻关机,其中 now 相当于时间为 0 的状态
shutdown -h 20:25 系统在今天的 20:25 会关机
shutdown -h +10 系统再过十分钟后自动关机
init 0 关机
init 6 重启
7.10 git 合并文件有冲突,如何处理?
1.git merge 冲突了,根据提示找到冲突的文件,解决冲突如果文件有冲突,那么会有类似标记
2.修改完之后,执行 git add 冲突文件名
3.git commit 注意:没有-m 选项 进去类似于 vim 的操作界面,把 conflict 相关的行删除掉直接 push 就可以了,因为刚刚已经执行过相关 merge 操作了
二.数据类型
1.字典
1.1说一下字典和 json 的区别?
字典是一种数据结构,json 是一种数据的表现形式,字典的 key 值只要是能 hash 的就行,json 的必须是字符串
1.2什么是可变、不可变类型?
可变不可变指的是内存中的值是否可以被改变,不可变类型指的是对象所在内存块里面的值不可以改变,有数值、字符串、元组;可变类型则是可以改变,主要有列表、字典。
1.3 字典推导式?
d = {key: value for (key, value) in iterable}
1.4字典排序
# 请按字 典中的 value值进行排序
d = {'a': 24, 'g': 52, 'l': 12, 'k': 33}
sorted(d.items(), key=lambda x: x[1]) # [('l', 12), ('a', 24), ('k', 33), ('g', 52)]
2.字符串
2.1 如何理解 Python 中字符串中的\字符?
有三种不同的含义:
1、转义字符
2、路径名中用来连接路径名
3、编写太长代码手动软换行
2.2 请反转字符串“aStr”?
str1 = "aStr"
str2 = str1[::-1]
2.3 请按 alist 中元素的 age 由大到小排序
alist = [{'name':'a','age':20},{'name':'b','age':30},{'name':'c','age':25}]
def sort_by_age(lst):
return sorted(lst, key=lambda x:x['age'], reverse=True)
res = sort_by_age(alist)
3.列表
3.1 写一个列表生成式,产生一个公差为 11 的等差数列
[i*11 for i in range(10)]
3.2 给定两个列表,怎么找出他们相同的元素和不同的元素?
list1 = [1, 2, 3]
list2 = [3, 4, 5]
set1 = set(list1)
set2 = set(list2)
print(set1&set2)
print(set1^set2)
3.3 下面这段代码的输出结果是什么?请解释?
def extend_list(val, lst=[]):
lst.append(val)
return lst
list1 = extend_list(10)
list2 = extend_list(123, [])
list3 = extend_list('a')
print(list1, list2, list3, sep='\n')
新的默认列表只在函数被定义的那一刻创建一次。当 extendList 被没有指定特定参数 list 调用时,这组 list 的值随后将被使用。这是因为带有默认参数的表达式在函数被定义的时候被计算,不是在调用的时候被计算
4.元组
tuple:元组,元组将多样的对象集合到一起,不能修改,通过索引进行查找,使用括号”()”;
应用场景:把一些数据当做一个整体去使用,不能修改;
5.集合
set:set 集合,在 Python 中的书写方式的{},集合与之前列表、元组类似,可以存储多个数据,但是这些数据是不重复的。集合对象还支持
union(联合)
intersection(交)
difference(差)
sysmmetric_difference(对称差集)
等数学运算
三.python高级
1.元类
1.1 Python 中类方法、类实例方法、静态方法有何区别?
类方法:是类对象的方法,在定义时需要在上方使用@classmethod进行装饰,形参为cls,表示类对象,类对象和实例对象都可调用;
类实例方法:是类实例化对象的方法,只有实例对象可以调用,形参为 self,指代对象本身;
静态方法:是一个任意函数,在其上方使用@staticmethod进行装饰,可以用对象直接调用,
静态方法实际上跟该类没有太大关系
2.内存管理与垃圾回收机制
2.1 Python 的内存管理机制及调优手段?
内存管理机制:引用计数、垃圾回收、内存池
引用计数:
引用计数是一种非常高效的内存管理手段, 当一个 Python 对象被引用时其引用计数增加 1, 当其不再被一个变量引用时则计数减 1. 当引用计数等于 0 时对象被删除
垃圾回收 :
引用计数
引用计数也是一种垃圾收集机制,而且也是一种最直观,最简单的垃圾收集技术。当 Python 的某个对象的引用计数降为 0 时,说明没有任何引用指向该对象,该对象就成为要被回收的垃圾了。比如某个新建对象,它被分配给某个引用,对象的引用计数变为 1。如果引用被删除,对象的引用计数为 0,那么该对象就可以被垃圾回收。不过如果出现循环引用的话,引用计数机制就不再起有效的作用了
标记清除
如果两个对象的引用计数都为 1,但是仅仅存在他们之间的循环引用,那么这两个对象都是需要被回收的,也就是说,它们的引用计数虽然表现为非 0,但实际上有效的引用计数为 0。所以先将循环引用摘掉,就会得出这两个对象的有效计数。
分代回收
从前面“标记-清除”这样的垃圾收集机制来看,这种垃圾收集机制所带来的额外操作实际上与系统中总的内存块的数量是相关的,当需要回收的内存块越多时,垃圾检测带来的额外操作就越多,而垃圾回收带来的额外操作就越少;反之,当需回收的内存块越少时,垃圾检测就将比垃圾回收带来更少的额外操作。
内存池:
Python 的内存机制呈现金字塔形状,-1,-2 层主要有操作系统进行操作;
第 0 层是 C 中的 malloc,free 等内存分配和释放函数进行操作;
第 1 层和第 2 层是内存池,有 Python 的接口函数 PyMem_Malloc 函数实现,当对象小于256K 时有该层直接分配内存;
第 3 层是最上层,也就是我们对 Python 对象的直接操作;Python 在运行期间会大量地执行 malloc 和 free 的操作,频繁地在用户态和核心态之间进行切换,这将严重影响 Python 的执行效率。为了加速 Python 的执行效率,Python 引入了一个内存池机制,用于管理对小块内存的申请和释放。Python 内部默认的小块内存与大块内存的分界点定在 256 个字节,当申请的内存小于 256 字节时,PyObject_Malloc 会在内存池中申请内存;当申请的内存大于 256 字节时,PyObject_Malloc 的行为将蜕化为 malloc 的行为。当然,通过修改 Python 源代码,我们可以改变这个默认值,从而改变 Python 的默认内存管理行为。
调优手段(了解)
1.手动垃圾回收
2.调高垃圾回收阈值
3.避免循环引用(手动解循环引用和使用弱引用)
2.2 内存泄露是什么?如何避免?
指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费。导致程序运行速度减慢甚至系统崩溃等严重后果。
有 __del__()函数的对象间的循环引用是导致内存泄漏的主凶。不使用一个对象时使用:del object 来删除一个对象的引用计数就可以有效防止内存泄漏问题。
通过 Python 扩展模块 gc 来查看不能回收的对象的详细信息。可以通过 sys.getrefcount(obj) 来获取对象的引用计数,并根据返回值是否为 0 来判断是否内存泄漏。
3.函数
3.1 Python 函数调用的时候参数的传递方式是值传递还是引用传递?
Python 的参数传递有:
位置参数、
默认参数、
可变参数、
关键字参数
函数的传值到底是值传递还是引用传递,要分情况:
不可变参数用值传递:
像整数和字符串这样的不可变对象,是通过拷贝进行传递的,因为你无论如何都不可能在原处改变不可变对象
可变参数是引用传递的:
比如像列表,字典这样的对象是通过引用传递、和 C 语言里面的用指针传递数组很相似,可变对象能在函数内部改变。
3.2 对缺省参数的理解 ?
缺省参数指在调用函数的时候没有传入参数的情况下,调用默认的参数,在调用函数的同时赋值时,
所传入的参数会替代默认参数。
*args 是不定长参数,他可以表示输入参数是不确定的,可以是任意多个。
**kwargs 是关键字参数,赋值的时候是以键 = 值的方式,参数是可以任意多对在定义函数的时候不确定会有多少参数会传入时,就可以使用两个参数。
3.3 为什么函数名字可以当做参数用?
Python 中一切皆对象,函数名是函数在内存中的空间,也是一个对象
3.4 Python 中 pass 语句的作用是什么?
在编写代码时只写框架思路,具体实现还未编写就可以用 pass 进行占位,使程序不报错,不会进行任何操作
3.5 有这样一段代码,print c 会输出什么,为什么?
a = 10
b = 20
c = [a]
a = 15
print(c)
答:10 对于不可变类型的数据(字符串、数字),传递是相应的值。
3.6 map 函数和 reduce 函数?
①从参数方面来讲:
map()包含两个参数,第一个参数是一个函数,第二个是序列(列表 或元组)。其中,函数(即 map的第一个参数位置的函数)可以接收一个或多个参数。
reduce()第一个参数是函数,第二个是序列(列表或元组)。但是,其函数必须接收两个参数。
②从对传进去的数值作用来讲:
map()是将传入的函数依次作用到序列的每个元素,每个元素都是独自被函数“作用”一次 。
reduce()是将传入的函数作用在序列的第一个元素得到结果后,把这个结果继续与下一个元素作用(累积计算)。
3.7 回调函数,如何通信的?
回调函数是把函数的指针(地址)作为参数传递给另一个函数,将整个函数当作一个对象,赋值给调用的函数。
3.8 hasattr() getattr() setattr() 函数使用详解?
hasattr(object, name):
判断一个对象里面是否有name属性或者name方法,返回bool值,有name属性(方法)返回True,
否则返回 False。注意:name为str, 要使用引号括起来。
class FunctionDemo(object):
name = 'demo'
def run(self):
return "hello function %s" % self.name
function_demo = FunctionDemo()
res1 = hasattr(function_demo, 'name')
res2 = hasattr(function_demo, 'run')
res3 = hasattr(function_demo, 'age')
print(res1, res2, res3, sep='\n')
getattr(object, name[,default]) :
获取对象 object 的属性或者方法,如果存在则打印出来,如果不存在,打印默认值,默认值可选。
注意:如果返回的是对象的方法,则打印结果是:方法的内存地址,如果需要运行这个方法,可以在后面添加括号()
class FunctionDemo(object):
name = 'demo'
def run(self):
return "hello function %s" % self.name
function_demo = FunctionDemo()
res1 = getattr(function_demo, 'name')
res2 = getattr(function_demo, 'run') # >
# res3 = getattr(function_demo, 'age') # AttributeError: 'FunctionDemo' object has no attribute 'age'
res4 = getattr(function_demo, 'age', 18) # 解决不存在抛出异常
print(res1, res2, res4, sep='\n')
setattr(object,name,values):
给对象的属性赋值,若属性不存在,先创建再赋值, 无返回值
3.9 什么是 lambda 函数? 有什么好处?
lambda 函数是一个可以接收任意多个参数(包括可选参数)并且返回单个表达式值的函数
1、lambda 函数比较轻便,即用即仍,很适合需要完成一项功能,但是此功能只在此一处使用,连名字都很随意的情况下;
2、匿名函数,一般用来给 filter, map 这样的函数式编程服务;
3、作为回调函数,传递给某些应用,比如消息处理
4.设计模式
4.1 请手写一个单例
class SingletonPattern(object):
__instance = None
def __new__(cls, *args, **kwargs):
if cls.__instance is None:
cls.__instance = object.__new__(cls)
return cls.__instance
4.2 解释一下什么是闭包?
在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包
4.3函数装饰器有什么作用?
装饰器本质上是一个 Python 函数,它可以在让其他函数在不需要做任何代码的变动的前提下增加额外的功能。装饰器的返回值也是一个函数的对象,它经常用于有切面需求的场景。 比如:插入日志、性能测试、事务处理、缓存、权限的校验等场景 有了装饰器就可以抽离出大量的与函数功能本身无关的雷同代码并发并继续使用。
4.4 生成器、迭代器的区别?
迭代器是一个更抽象的概念,任何对象,如果它的类有 next 方法和 iter 方法返回自己本身,对于 string、list、dict、tuple 等这类容器对象,使用 for 循环遍历是很方便的。在后台 for 语句对容器对象调用 iter()函数,iter()是 python 的内置函数。iter()会返回一个定义了 next()方法的迭代器对象,它在容器中逐个访问容器内元素,next()也是 python 的内置函数。在没有后续元素时,next()会抛出一个 StopIteration 异常
生成器(Generator)是创建迭代器的简单而强大的工具。它们写起来就像是正规的函数,只是在需要返回数据的时候使用 yield 语句。每次 next()被调用时,生成器会返回它脱离的位置(它记忆语句最后一次执行的位置和所有的数据值)
区别:生成器能做到迭代器能做的所有事,而且因为自动创建了 iter()和 next()方法,生成器显得特别简洁,而且生成器也是高效的,使用生成器表达式取代列表解析可以同时节省内存。除了创建和保存程序状态的自动方法,当发生器终结时,还会自动抛StopIteration 异常。
4.5 请尝试用“一行代码”实现将 1-N 的整数列表以 3 为单位分组,比如 1-100分组后为?
N = 100
lst1 = [[x for x in range(1, N)][i: i+3] for i in range(0, N-1, 3)]
4.6Python 中 yield 的用法?
yield 就是保存当前程序执行状态。你用 for 循环的时候,每次取一个元素的时候就会计算一次。用 yield 的函数叫 generator,和 iterator 一样,它的好处是不用一次计算所有元素,而是用一次算一次,可以节省很多空间。generator每次计算需要上一次计算结果,所以用 yield,否则一 return,上次计算结果就没了
5.面向对象
5.1 Python 中的可变对象和不可变对象?
不可变对象,该对象所指向的内存中的值不能被改变。当改变某个变量时候,由于其所指的值不能被改变,相当于把原来的值复制一份后再改变,这会开辟一个新的地址,变量再指向这个新的地址。
可变对象,该对象所指向的内存中的值可以被改变。变量(准确的说是引用)改变后,实际上是其所指的值直接发生改变,并没有发生复制行为,也没有开辟新的出地址,通俗点说就是原地改变。
Python 中,数值类型(int 和 float)、字符串 str、元组 tuple 都是不可变类型。而列表 list、字典 dict、集合set 是可变类型。
5.2 Python 中 is 和==的区别?
is 判断的是 a 对象是否就是 b 对象,是通过 id 来判断的。
==判断的是 a 对象的值是否和 b 对象的值相等,是通过 value 来判断的
5.3 Python 的魔法方法?
魔法方法就是可以给你的类增加魔力的特殊方法,如果你的对象实现 (重载)了这些方法中的某一个,那么这个方法就会在特殊的情况下被 Python 所调用,你可以定义自己想要的行为,而这一切都是自动发生的。 它们经常是两个下划线包围来命名的(比如 init,lt),Python 的魔法方法是非常强大的,所以了解其使用方法也变得尤为重要!
__init__ 构造器,当一个实例被创建的时候初始化的方法。但是它并 不是实例化调用的第一个方法。
__new__才是实例化对象调用的第一个方法,它只取下 cls 参数,并把 其他参数传给 __init__。
__new__很少使用,但是也有它适合的场景,尤其 是当类继承自一个像元组或者字符串这样不经常改变的类型的时候。
__call__ 允许一个类的实例像函数一样被调用 。
__getitem__定义获取容器中指定元素的行为,相当于self[key]
__getattr__定义当用户试图访问一个不存在属性的时候的行为
__setattr__ 定义当一个属性被设置的时候的行为
__getattribute__ 定义当一个属性被访问的时候的行为
5.4谈谈你对面向对象的理解?
面向对象是相对于面向过程而言的。面向过程语言是一种基于功能分析的、以算法为中心的程序设计方法;而面向对象是一种基于结构分析的、以数据为中心的程序设计思想。在面向对象语言中有一个有很重要东西,叫做类。
面向对象有三大特性:封装、继承、多态
6.系统编程
6.1 谈谈你对多进程,多线程,以及协程的理解,项目是否用?
这个问题被问的概率相当之大,其实多线程,多进程,在实际开发中用到的很少,除非是那些对项
目性能要求特别高的,有的开发工作几年了,也确实没用过,你可以这么回答,给他扯扯什么是进程,
线程(cpython 中是伪多线程)的概念就行,实在不行你就说你之前写过下载文件时,用过多线程技术,或者业余时间用过多线程写爬虫,提升效率。
进程:一个运行的程序(代码)就是一个进程,没有运行的代码叫程序,进程是系统资源分配的最
小单位,进程拥有自己独立的内存空间,所以进程间数据不共享,开销大。
线程: 调度执行的最小单位,也叫执行路径,不能独立存在,依赖进程存在一个进程至少有一个
线程,叫主线程,而多个线程共享内存(数据共享,共享全局变量),从而极大地提高了程序的运行效率。
协程:是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和
栈。 协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存
器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切
换非常快。
6.2 什么是多线程竞争?
线程是非独立的,同一个进程里线程是数据共享的,当各个线程访问数据资源时会出现竞争状态即:数据几乎同步会被多个线程占用,造成数据混乱 ,即所谓的线程不安全
那么怎么解决多线程竞争问题?-- 锁。
锁的好处:
确保了某段关键代码(共享数据资源)只能由一个线程从头到尾完整地执行能解决多线程资源竞争下
的原子操作问题。
锁的坏处:
阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了
锁的致命问题:死锁
6.3 什么是死锁呢?
锁(Lock)是 Python 提供的对线程控制的对象。有互斥锁、可重入锁、死锁。
若干子线程在系统资源竞争时,都在等待对方对某部分资源解除占用状态,结果是谁也不愿先解锁,互相干等着,程序无法执行下去,这就是死锁。
GIL 锁(有时候,面试官不问,你自己要主动说,增加 b 格,尽量别一问一答的尬聊,不然最后等
到的一句话就是:你还有什么想问的么?)
GIL 锁 全局解释器锁(只在 cpython 里才有)
作用:限制多线程同时执行,保证同一时间只有一个线程执行,所以 cpython 里的多线程其实是伪
多线程!
所以 Python 里常常使用协程技术来代替多线程,协程是一种更轻量级的线程,进程和线程的切换时由系统决定,而协程由我们程序员自己决定,而模块 gevent 下切换是遇到了耗时操作才会切换。
三者的关系:进程里有线程,线程里有协程
6.4 什么是线程安全,什么是互斥锁?
每个对象都对应于一个可称为" 互斥锁" 的标记,这个标记用来保证在任一时刻,只能有一个线程
访问该对象。
同一个进程中的多线程之间是共享系统资源的,多个线程同时对一个对象进行操作,一个线程操作
尚未结束,另一个线程已经对其进行操作,导致最终结果出现错误,此时需要对被操作对象添加互斥锁,
保证每个线程对该对象的操作都得到正确的结果。
6.5 说说下面几个概念:同步,异步,阻塞,非阻塞?
同步:多个任务之间有先后顺序执行,一个执行完下个才能执行。
异步:多个任务之间没有先后顺序,可以同时执行, 有时候一个任务可能要在必要的时候获取另一个
同时执行的任务的结果,这个就叫回调!
阻塞:如果卡住了调用者,调用者不能继续往下执行,就是说调用者阻塞了。
非阻塞:如果不会卡住,可以继续执行,就是说非阻塞的。
同步异步相对于多任务而言,阻塞非阻塞相对于代码执行而言。
6.6 什么是僵尸进程和孤儿进程?怎么避免僵尸进程?
孤儿进程:父进程退出,子进程还在运行的这些子进程都是孤儿进程,孤儿进程将被 init 进程(进
程号为 1)所收养,并由 init 进程对它们完成状态收集工作。
僵尸进程:进程使用 fork 创建子进程,如果子进程退出,而父进程并没有调用 wait 或 waitpid 获
取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中的这些进程是僵尸进程。
避免僵尸进程的方法:
1.fork 两次用孙子进程去完成子进程的任务;
2.用 wait()函数使父进程阻塞;
3.使用信号量,在 signal handler 中调用 waitpid,这样父进程不用阻塞。
6.7 Python 中的进程与线程的使用场景?
多进程适合在 CPU 密集型操作(cpu 操作指令比较多,如位数多的浮点运算)。
多线程适合在 IO 密集型操作(读写数据操作较多的,比如爬虫)。
6.8线程是并发还是并行,进程是并发还是并行?
线程是并发,进程是并行;
进程之间相互独立,是系统分配资源的最小单位,同一个线程中的所有线程共享资源。
6.9并行(parallel)和并发(concurrency)?
并行:同一时刻多个任务同时在运行。
并发:在同一时间间隔内多个任务都在运行,但是并不会在同一时刻同时运行,存在交替执行的情
况。
实现并行的库有:multiprocessing
实现并发的库有:threading
程序需要执行较多的读写、请求和回复任务的需要大量的 IO 操作,IO 密集型操作使用并发更好。
CPU 运算量大的程序程序,使用并行会更好。
6.10 IO 密集型和 CPU 密集型区别?
IO 密集型:系统运作,大部分的状况是 CPU 在等 I/O (硬盘/内存)的读/写。
CPU 密集型:大部份时间用来做计算、逻辑判断等 CPU 动作的程序称之 CPU 密集型。
7. 网络编程
7.1怎么实现强行关闭客户端和服务器之间的连接?
在 socket 通信过程中不断循环检测一个全局变量(开关标记变量),一旦标记变量变为关闭,则 调
用 socket 的 close 方法,循环结束,从而达到关闭连接的目的。
7.2简述 TCP 和 UDP 的区别以及优缺点?
UDP 是面向无连接的通讯协议,UDP 数据包括目的端口号和源端口号信息。
优点:UDP 速度快、操作简单、要求系统资源较少,由于通讯不需要连接,可以实现广播发送
缺点:UDP 传送数据前并不与对方建立连接,对接收到的数据也不发送确认信号,发送端不知道数据是否会正确接收,也不重复发送,不可靠。
TCP 是面向连接的通讯协议,通过三次握手建立连接,通讯完成时四次挥手
优点:TCP 在数据传递时,有确认、窗口、重传、阻塞等控制机制,能保证数据正确性,较为靠。
缺点:TCP 相对于 UDP 速度慢一点,要求系统资源较多。
7.3 简述浏览器通过 WSGI 请求动态资源的过程?
发送 http 请求动态资源给 web 服务器
web 服务器收到请求后通过 WSGI 调用一个属性给应用程序框架
应用程序框架通过引用 WSGI 调用 web 服务器的方法,设置返回的状态和头信息。
调用后返回,此时 web 服务器保存了刚刚设置的信息
应用程序框架查询数据库,生成动态页面的 body 的信息
把生成的 body 信息返回给 web 服务器
web 服务器吧数据返回给浏览器
7.4描述用浏览器访问 www.baidu.com 的过程
先要解析出 baidu.com 对应的 ip 地址
要先使用 arp 获取默认网关的 mac 地址
组织数据发送给默认网关(ip 还是 dns 服务器的 ip,但是 mac 地址是默认网关的 mac 地址)
默认网关拥有转发数据的能力,把数据转发给路由器
路由器根据自己的路由协议,来选择一个合适的较快的路径转发数据给目的网关
目的网关(dns 服务器所在的网关),把数据转发给 dns 服务器
dns 服务器查询解析出 baidu.com 对应的 ip 地址,并原路返回请求这个域名的 client
得到了 baidu.com 对应的 ip 地址之后,会发送 tcp 的 3 次握手,进行连接
使用 http 协议发送请求数据给 web 服务器
web 服务器收到数据请求之后,通过查询自己的服务器得到相应的结果,原路返回给浏览器。
浏览器接收到数据之后通过浏览器自己的渲染功能来显示这个网页。
浏览器关闭 tcp 连接,即 4 次挥手结束,完成整个访问过程
7.5Post 和 Get 请求的区别?
GET 请求,请求的数据会附加在 URL 之后,以?分割 URL 和传输数据,多个参数用&连接。URL 的
编码格式采用的是 ASCII 编码,而不是 uniclde,即是说所有的非 ASCII 字符都要编码之后再传输。
POST 请求:POST 请求会把请求的数据放置在 HTTP 请求包的包体中。上面的 item=bandsaw 就
是实际的传输数据。因此,GET 请求的数据会暴露在地址栏中,而 POST 请求则不会。
传输数据的大小:
在 HTTP 规范中,没有对 URL 的长度和传输的数据大小进行限制。但是在实际开发过程中,对于 GET,特定的浏览器和服务器对 URL 的长度有限制。因此,在使用 GET 请求时,传输数据会受到 URL 长度的限制。
对于 POST,由于不是 URL 传值,理论上是不会受限制的,但是实际上各个服务器会规定对 POST提交数据大小进行限制,Apache、IIS 都有各自的配置。
安全性:
POST 的安全性比 GET 的高。这里的安全是指真正的安全,而不同于上面 GET 提到的安全方法中的安全,上面提到的安全仅仅是不修改服务器的数据。比如,在进行登录操作,通过 GET 请求,用户名和密码都会暴露再URL 上,因为登录页面有可能被浏览器缓存以及其他人查看浏览器的历史记录的原因,此时的用户名和密码就很容易被他人拿到了。除此之外,GET 请求提交的数据, 还可能会造成 Cross-site request frogery 攻击。
效率:GET 比 POST 效率高。
POST 请求的过程:
1.浏览器请求 tcp 连接(第一次握手)
2.服务器答应进行 tcp 连接(第二次握手)
3.浏览器确认,并发送 post 请求头(第三次握手,这个报文比较小,所以 http 会在此时进行第一次数据发送)
4.服务器返回 100 continue 响应
5.浏览器开始发送数据
6.服务器返回 200 ok 响应
GET 请求的过程:
1.浏览器请求 tcp 连接(第一次握手)
2.服务器答应进行 tcp 连接(第二次握手)
3.浏览器确认,并发送 get 请求头和数据(第三次握手,这个报文比较小,所以 http 会在此时进行第一次数据发送)
4.服务器返回 200 OK 响应
7.6cookie 和 session 的区别?
1、cookie 数据存放在客户的浏览器上,session 数据放在服务器上。
2、cookie 不是很安全,别人可以分析存放在本地的 cookie 并进行 cookie 欺骗考虑到安全应当使用 session。
3、session 会在一定时间内保存在服务器上。当访问增多,会比较占用服务器的性能考虑到减轻服务器性能方面,应当使用 cookie。
4、单个 cookie 保存的数据不能超过 4K,很多浏览器都限制一个站点最多保存 20 个 cookie。
5、建议: 将登陆信息等重要信息存放为 SESSION 其他信息如果需要保留,可以放在 cookie 中
7.7 HTTP 协议状态码有什么用,列出你知道的 HTTP 协议的状态码,然后讲出他们都表示什么意思?
通过状态码告诉客户端服务器的执行状态,以判断下一步该执行什么操作。
常见的状态机器码有:
100-199:表示服务器成功接收部分请求,要求客户端继续提交其余请求才能完成整个处理过程。
200-299:表示服务器成功接收请求并已完成处理过程,常用 200(OK 请求成功)。
300-399:为完成请求,客户需要进一步细化请求。302(所有请求页面已经临时转移到新的 url)。
304、307(使用缓存资源)。
400-499:客户端请求有错误,常用 404(服务器无法找到被请求页面),403(服务器拒绝访问,权限不够)。
500-599:服务器端出现错误,常用 500(请求未完成,服务器遇到不可预知的情况)。
7.8 请简单说一下三次握手和四次挥手?
三次握手过程:
1 首先客户端向服务端发送一个带有 SYN 标志,以及随机生成的序号 100(0 字节)的报文
2 服务端收到报文后返回一个报文(SYN200(0 字节),ACk1001(字节+1))给客户端
3 客户端再次发送带有 ACk 标志 201(字节+)序号的报文给服务端
至此三次握手过程结束,客户端开始向服务端发送数据。
1 客户端向服务端发起请求:我想给你通信,你准备好了么?
2 服务端收到请求后回应客户端:I'ok,你准备好了么
3 客户端礼貌的再次回一下客户端:准备就绪,咱们开始通信吧!
整个过程跟打电话的过程一模一样:1 喂,你在吗 2 在,我说的你听得到不 3 恩,听得到(接下来请
开始你的表演)
补充:SYN:请求询问,ACk:回复,回应。
四次挥手过程:
由于 TCP 连接是可以双向通信的(全双工),因此每个方向都必须单独进行关闭(这句话才是精辟,后面四个挥手过程都是其具体实现的语言描述)
四次挥手过程,客户端和服务端都可以先开始断开连接
1 客户端发送带有 fin 标识的报文给服务端,请求通信关闭
2 服务端收到信息后,回复 ACK 答应关闭客户端通信(连接)请求
3 服务端发送带有 fin 标识的报文给客户端,也请求关闭通信
4 客户端回应 ack 给服务端,答应关闭服务端的通信(连接)请求
7.9说一下什么是 tcp 的 2MSL?
主动发送 fin 关闭的一方,在 4 次挥手最后一次要等待一段时间我们称这段时间为 2MSL
TIME_WAIT 状态的存在有两个理由:
1.让 4 次挥手关闭流程更加可靠
2.防止丢包后对后续新建的正常连接的传输造成破坏
7.10 为什么客户端在 TIME-WAIT 状态必须等待 2MSL 的时间?
1、为了保证客户端发送的最后一个 ACK 报文段能够达到服务器。 这个 ACK 报文段可能丢失,因而使处在 LAST-ACK 状态的服务器收不到确认。服务器会超时重传 FIN+ACK 报文段,客户端就能在 2MSL 时间内收到这个重传的 FIN+ACK 报文段,接着客户端重传一次确认,重启计时器。最好,客户端和服务器都正常进入到 CLOSED 状态。如果客户端在 TIME-WAIT 状态不等待一段时间,而是再发送完 ACK 报文后立即释放连接,那么就无法收到服务器重传的 FIN+ACK 报文段,因而也不会再发送一次确认报文。这样,服务器就无法按照正常步骤进入 CLOSED 状态。
2、防止已失效的连接请求报文段出现在本连接中。客户端在发送完最后一个 ACK 确认报文段后,再经过时间 2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样就可以使下一个新的连接中不会出现这种旧的连接请求报文段。
7.11说说 HTTP 和 HTTPS 区别?
HTTP 协议传输的数据都是未加密的,也就是明文的,因此使用 HTTP 协议传输隐私信息非常不安全,为了保证这些隐私数据能加密传输,于是网景公司设计了 SSL(Secure Sockets Layer)协议用于对 HTTP 协议传输的数据进行加密,从而就诞生了 HTTPS。简单来说,HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,要比 http 协议安全。
HTTPS 和 HTTP 的区别主要如下:
1、https 协议需要到 ca 申请证书,一般免费证书较少,因而需要一定费用。
2、http 是超文本传输协议,信息是明文传输,https 则是具有安全性的 ssl 加密传输协议。
3、http 和 https 使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443。
4、http 的连接很简单,是无状态的;HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 http 协议安全。
7.12 谈一下 HTTP 协议以及协议头部中表示数据类型的字段?
HTTP 协议是 Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web)服务器传输超文本到本地浏览器的传送协议。
HTTP 是一个基于 TCP/IP 通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)。
HTTP 是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。它于 1990 年提出,经过几年的使用与发展,得到不断地完善和扩展。目前在 WWW 中使用的是 HTTP/1.0 的第六版,HTTP/1.1 的规范化工作正在进行之中,而且 HTTP-NG(NextGeneration of HTTP)的建议已经提出。
HTTP 协议工作于客户端-服务端架构为上。浏览器作为 HTTP 客户端通过 URL 向 HTTP 服务端即 WEB 服务器发送所有请求。Web 服务器根据接收到的请求后,向客户端发送响应信息。
表示数据类型字段: Content-Type
7.13 HTTP 请求方法都有什么?
根据 HTTP 标准,HTTP 请求可以使用多种请求方法。
HTTP1.0 定义了三种请求方法: GET, POST 和 HEAD 方法。
HTTP1.1 新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法。
1、GET 请求指定的页面信息,并返回实体主体。
2、HEAD 类似于 get 请求,只不过返回的响应中没有具体的内容,用于获取报头
3、POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST 请求可能会导致新的资源的建立和/或已有资源的修改。
4、PUT 从客户端向服务器传送的数据取代指定的文档的内容。
5、DELETE请求服务器删除指定的页面。
6、CONNECT HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。
7、OPTIONS 允许客户端查看服务器的性能。
8、TRACE 回显服务器收到的请求,主要用于测试或诊断。
7.14 使用 Socket 套接字需要传入哪些参数 ?
Address Family 和 Type,分别表示套接字应用场景和类型。
family 的值可以是 AF_UNIX(Unix 域,用于同一台机器上的进程间通讯),也可以是 AF_INET(对于 IPV4 协议的TCP 和 UDP),至于 type 参数,SOCK_STREAM(流套接字)或者SOCK_DGRAM(数据报文套接字),SOCK_RAW(raw 套接字)。
7.15HTTP 常见请求头?
Host (主机和端口号)
Connection (链接类型)
Upgrade-Insecure-Requests (升级为 HTTPS 请求)
User-Agent (浏览器名称)
Accept (传输文件类型)
Referer (页面跳转处)
Accept-Encoding(文件编解码格式)
Cookie (Cookie)
x-requested-with :XMLHttpRequest (是 Ajax 异步请求)
7.16 七层模型? IP ,TCP/UDP ,HTTP ,RTSP ,FTP 分别在哪层?
IP: 网络层
TCP/UDP: 传输层
HTTP、RTSP、FTP: 应用层协议
形式: scheme://host[:port#]/path/…/[?query-string][#anchor]
scheme:协议(例如:http, https, ftp)
host:服务器的 IP 地址或者域名7.17 url 的形式?
port:服务器的端口(如果是走协议默认端口,80 or 443)
path:访问资源的路径
query-string:参数,发送给 http 服务器的数据
anchor:锚(跳转到网页的指定锚点位置)
http://localhost:4000/file/part01/1.2.html
标签:__,请求,Python,面试,对象,内存,相关,函数
来源: https://www.cnblogs.com/pankypan/p/11066516.html