1、用一条SQL语句查询出每门课都大于80分的学生姓名。
select name, min(fenshu) from stu;
select name, min(fenshu) from stu group by kecheng;
select name, min(fenshu) from stu group by kecheng having min(fenshu)>80
select name from(select name, min(fenshu) from stu group by kecheng having min(fenshu)>80) stu;
2、表中有A、B、C三列,用SQL语句实现;当A列大于B列时选择A列,否则选择B列
当B列大于C列时选择B列否则选择C列。
select (case when a>b then a else b end), (case when b>c then b else c end) from table1
3、数据表如下:按name分组取val最大的值所在行的数据
select name, max(val), memo from table1 group by name;
4、用生成器生成100以内的偶数
for i in range(100):
if i % 2 == 0:
print(i)
gs = (i for i in range(100) if i % 2 == 0)
for g in gs:
print(g)
5、写一个列表去重的方法
a = [1, 1, 2, 4, "a", "b", "a"]
b = set(a)
print(b)
# {'b', 1, 2, 4, 'a'}
6、如何给到2s和5s之间的随机值?
import random
a = random.randint(2, 5)
print(a)
7、写出在网络爬虫爬取数据的过程中,遇到的反爬虫问题的解决方案。
1、遇到基于请求头的反爬构造合理的HTTP请求头(User-Agent/Referer/Cookie)
2、设置Cookie(模拟登录获取cookie)
3、降低访问频率
4、动态页面的爬虫(通过ajax请求数据,或者通过javascript生成)使用selenium和phantomjs模拟浏览器爬取数据
5、使用IP,网站反爬比较严格的时候,一般会根据用户请求网页的频率来限制IP,所以必要的时候可以使用IP代理池
6、出现验证码使用打码平台来识别验证码
8、写出下列代码的运行结果
seq = [1, 2, 3, 4]
print(seq[:2])
[1, 2]
print(seq[-2:])
[3, 4]
print(seq[:-2])
[1, 2]
print(seq[::2])
[1, 3]
print(seq[:])
[1, 2, 3, 4]
9、写出运行结果
def funcArgsTest(a, b, c=100, *args, **kwargs):
sum = a + b + c
for d in args:
sum += d
for v in kwargs.values():
sum += v
return sum
print(funcArgsTest(100, 200, aa=700, bb=900, cc=1000))
print(funcArgsTest(100, 200, 300, 500, 600, aa=700, bb=900, cc=1000))
3000 4300
10、Python中__new__和__init__方法的区别
(1)__new__是静态方法,而__init__是实例方法
(2)__new__方法会返回一个创建的实例,而__init__什么都不返回
(3)只有在__new__返回一个cls的实例时,后面的__init__才能被调用
(4)当创建一个新实例时调用__new__,初始化一个实例时调用__init__
11、写一个python中的单例模式(某一个类只有一个实例存在)
方法一:使用装饰器
装饰器维护一个字典对象instances,缓存了所有单例类,只要单例不存在则创建,已经存在则返回该实例对象。
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):
_instance = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instance:
cls._instance[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instance[cls]
class Foo(metaclass=Singleton):
pass
foo1 = Foo()
foo2 = Foo()
print(foo1 is foo2)
True
12、git常见命令及作用
“”"
git clone 路径名:复制文件
git stats:查看当前状态
git config --global user.name fuhaozhen:配置身份信息
git add 文件名:将文件提交到缓存区
git commit -m 备注:将缓存区文件提交到本地仓库
git reset --hard 版本号:从仓库回退到缓存区
git checkout -文件名:撤销缓存区的修改
git pull:从远程仓库更新文件
git push:将本地仓库的文件推送到远程仓库
“”"
13、解释python中的三元表达式
条件为真时的结果 if 判断条件 else 条件为假时的结果
14、谈下python的GIL
多线程并不能真正的让多核CPU实现并行,这是因为cpython解释器中存在一个GIL(全局解释器锁),
作用是保证同一时刻只有一个线程可以执行代码,每个线程在执行的过程中都需要先获取GIL
15、python2和python3的range(100)的区别
python2返回列表,python3返回迭代器,节约内存
16、一句话解释什么样的语言能够使用装饰器
函数可以作为参数传递的语言
17、列表[1,2,3,4,5],请使用map()函数输出[1,4,9,16,25],并用
列表推导式提取大于10的数,最终输出[16,25]
list1 = [1, 2, 3, 4, 5]
list2 = list(map(lambda x: x * x, list1))
print(list2)
list3 = [x for x in list2 if x > 10]
print(list3)
18、python中生成随机整数、随机小数、0-1之间小数方法
random.randint(a.b), numpy.random.randn(5),random.random()
19、
,用正则表达式匹配出标签中的内容(“中国”),
其中class的类名是不确定的
import re
str1 = "中国"
res = re.findall(r"(.*?)", str1)
print(res)
20、数据表student有id,name,score,city字段,其中name中的名字可有重复,
需要消除重复行,请写sql语句
select distinct name from student
21、字典根据键从小到大顺序dict={“name”:“zs”,“age”:18,“city”:“深圳”,“tel”:“1362626627”}
dict1 = {"name": "zs", "age": 18, "city": "深圳", "tel": "1362626627"}
list1 = sorted(dict1)
# 字典的键排序
print(list1)
new_dict = {}
for key in list1:
new_dict[key] = dict1[key]
print(new_dict)
22、利用collections库的Counter方法统计字符串每个单词出现的次数
"kjalfj;ldsjafl;hdsllfdhg;lahfbl;jl;ahlf;h"
from collections import Counter
str1 = "kjalfj;ldsjafl;hdsllfdhg;lahfbl;jl;ahlf;h"
res = Counter(str1)
print(res)
Counter({'l': 9, ';': 6, 'f': 5, 'h': 5, 'j': 4, 'a': 4, 'd': 3, 's': 2, 'k': 1, 'g': 1, 'b': 1})
23、数据库优化查询方法
(1)选取最适用的字段属性
(2)使用连接来代替子查询
(3)使用联合来代替手动创建的临时表
(4)事务(要么语句块中每条语句都操作成功,要么都失败,就是可以保证数据库中数据的一致性和完整性)
(5)锁定表
(6)使用外键
(7)使用索引
(8)优化的查询语句
24、请列出你会的任意一种统计图(条形图、折线图等)绘制的开源库
pychart matplotlib
25、a=“张明 98分”,用re.sub将98替换成100
a = "张明 98分"
import re
str1 = re.sub("98", "100", a)
print(str1)
张明 100分
26、提高Python运行效率的方法
(1)关键代码使用外部功能包
(2)在排序时使用键
(3)针对循环的优化
(4)使用较新的Python版本
(5)尝试多种编码方法
(6)交叉编译你的应用
27、list=[2,3,5,4,9,6],从小到大排序,不许用sort,输出[2,3,4,5,6,9]
list1 = [2, 3, 5, 4, 9, 6]
list2 = []
while len(list1) > 0:
a = min(list1)
list1.remove(a)
list2.append(a)
print(list2)
28、IOError、AttributeError、ImportError、IndentationError、IndexError、
KeyError、SyntaxError、NameError分别代表什么异常
IOError:输入输出异常,基本是无法打开文件
AttributeError:属性异常,试图访问一个对象没有的属性
ImportError:导入异常,无法引入模块或包
IndentationError:缩进异常,代码没有对齐
IndexError:索引异常,下标索引超出序列边界
KeyError:键异常,试图访问字典中不存在的键
SyntaxError:语法异常,代码写错了
NameError:变量异常,尝试访问一个没有声明的变量
29、列表嵌套列表排序,年龄数字相同怎么办?
首先按年龄对列表排序,如果年龄相同,则按名字排序
30、a = “info:xiaoZhang 33 shandong”,用正则切分字符串中输出[“info”,“xiaoZhang”,“33”,“shandong”]
import re
a = "info:xiaoZhang 33 shandong"
str1 = re.split(r":| ", a)
print(str1)
['info', 'xiaoZhang', '33', 'shandong']
31、正则表达式匹配第一个URL
re.findall()结果无需加group(),re.search()结果需要加group()提取
32、python传参数是传值还是传址
python 中函数参数是引用传递,对于不可变类型,因为不能修改,所以运算不会影响到变量自身
而对于可变类型来说,函数体运算可能会更改传入的参数变量
33、同源策略
协议相同、域名相同、端口相同
34、简述cookie和session的区别
cookie在客户端,session在服务器端,安全性比cookie强,cookie存储数量有限
35、简述多线程、多进程
“”"
进程:操作系统分配资源和调度的基本单位,各个进程间相互独立,不产生影响,稳定性好,如果一个进程崩溃,不会影响到其他进程。但是进程消耗资源较大,开启的进程数量有限。
线程:是CPU进行资源分配和调度的基本单位,线程是进程的一部分,是比进程更小的能独立运行的基本单位,一个进程下的多个线程共享资源,如果IO操作密集,可以使用多线程运行效率高,缺点是如果一个线程崩溃,进程也就不能运行了
所以IO密集的用多线程,可以提高效率,在用户进入休眠的时候,可以切换到其他线程
CPU密集的可以使用多进程,因为线程间共享一个GIL锁,当前运行的线程会霸占GIL,就不能发挥多核CPU的优势。
“”"
36、简述any()和all()方法
a = ["a", "1", False]
# any():只要迭代器中有一个元素为真就为真
print(any(a))
# all():迭代器中所有的元素都为真才为真,否则为假
print(all(a))
True
False
37、常见的网络传输协议
UDP:用户数据报协议,将网络数据压缩成数据包的形式
TCP:传输控制协议,把数据流分割成适当长度的报文段
FTP:文本传输协议
HTTP:超文本传输协议
SMTP:简单邮件传输协议
38、HTTP请求中get和post区别
get请求是通过url直接请求数据,数据信息在url中可以看到,比如浏览器访问,而Post请求是放在请求头中的,我们无法直接看到;get数据有大小的限制,一般不超过1024个字节,post请求一般没有限制。
39、
print(int("1.4"))
ValueError: invalid literal for int() with base 10: ‘1.4’
print(int(1.4))
1
40、Linus命令重定向>和>>
> 表示输出,会覆盖文件原有的内容
>> 表示追加,会将内容追加到已有文件的末尾
41、生成0-100之间的随机数
import random
# 随机小数
print(100 * random.random())
# 随机整数
print(random.randint(0, 100))
42、python回收机制
python垃圾回收主要是引用计数为主,标记清除和分代回收为辅的机制,其中标记清除和分代回收主要是为了处理循环引用的难题。
引用计数是当有一个变量保存了对象的引用时,此对象的引用计数就会加1,当使用del删除变量指向的对象时,对象的引用计数减1,当为0时把对象删除。
43、在python中,字符串、元组和整型是不可更改对象,而列表和字典是可以修改的对象
a = 1
def fun(a):
a = 2
fun(a)
print(a)
a = []
def fun(a):
a.append(1)
fun(a)
print(a)
1
[1]
44、python中的元类(metaclass)
元类就是用来创建类的东西。
45、@staticmethod和@classmethod
class A(object):
def foo(self, x):
print("executing foo(%s,%s)" % (self, x))
@classmethod
def class_foo(cls, x):
print("executing class_foo(%s,%s)" % (cls, x))
@staticmethod
def static_foo(x):
# 静态方法和普通的方法一样,不需要对谁绑定
print("executing static_foo(%s)" % x)
# 实例方法的调用离不开实例,我们需要把实例自己传给函数
46、类变量和实例变量
class Person:
# 类变量
name = "a"
p1 = Person()
print(p1.name) # a
#实例变量
p1.name = "b"
print(p1.name) # b
name一开始指向的是类变量,但在实例的作用域里把类变量的
引用改变了,就变成了一个实例变量
47、python自省
自省就是面向对象的语言所写的程序在运行时,就能知道对象的类型,
如type()、dir()、getattr()、hasattr()、insinstance()
48、字典推导式
dict1 = {"a": 10, "b": 20}
dict2 = {key: value for (key, value) in dict1.items()}
print(dict2)
49、python中单划线和双下划线
单下划线是一种约定,用来约定变量私有。
双下滑线是私有属性,外部不可访问。
前后双下划线是python内部的名字,用来区别其他用户自定义的命名方法
50、字符串格式化:%和.format
%无法同时传递一个变量和元组
51、迭代器和生成器
在Python中 ,这种一边循环一边计算的机制,称为生成器:generator。
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator
52、面向切面编程AOP和装饰器
AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。
装饰器本质上是一个可调用的对象,它可以让其他函数在不需要做任何代码的变动的前提下增加额外的功能。装饰器的返回值也是一个函数的对象,它经常用于有切面需求的场景。比如:插入日志,性能测试,事务处理,缓存,权限的校验等场景,有了装饰器就可以抽离出大量的与函数功能无关的雷同代码并发并继续使用。
53、鸭子类型
当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。我们并不关心对象是什么类型,到底是不是鸭子,只关心行为。
如list.extend()方法中,我们并不关心它的参数是不是List,只要它是可迭代的,所以它的参数可以是list/tuple/dict/string/generator等。
54、python中重载
函数重载主要是为了解决两个问题:可变参数类型、可变参数个数。
设计原则是,仅仅当两个函数除了参数类型和参数个数不同以外,其他功能是完全相同的,此时才使用函数重载。
55、新式类和旧式类
新式类是广度优先,旧式类是深度优先
56、import方法
import方法作为Python的模块是天然的单例模式
mysingleton.py
class My_singleton(object):
def foo(self):
pass
my_singleton = My_singleton()
text1.py
from mysingleton import my_singleton
my_singleton.foo()
57、python中的作用域
在python中,创建、改变、查找变量名时,都是在一个保存变量名的空间中进行的,我们称之为命名空间,也称之为作用域。变量名被赋值的位置决定了该变量能被访问的范围,LEGB
当python遇到一个变量的会按照这样的顺序搜索:
本地作用域(local)——>嵌套作用域(enclosing local)——>全局作用域(global)——>内置作用域(bulit-in)
58、协程
协程是进程和线程的升级版,进程和线程都面临着内核态和用户态的切换问题而耗费许多切换时间,而协程就是用户自己控制切换的时机,不再需要陷入系统的内核态。
python中最常见的yield就是协程的思想
59、闭包
闭包是函数式编程的重要语法结构。提高了代码的可重复使用性。
当一个内嵌函数引用其外部作用域的变量,我们就会得到一个闭包。
创建一个闭包必须满足以下几点:
(1)必须有一个内嵌函数
(2)内嵌函数必须引用外部函数中的变量
(3)外部函数的返回值必须是内嵌函数
60、lambda函数
匿名函数,有输入和输出,一般功能简单。
61、python函数式编程
(1)filter函数的功能相当于过滤器。调用一个布尔函数bool_func来迭代遍历每个seq中的元素;返回一个使bool_sql返回值为true的元素的序列
a = [1, 2, 3, 4, 5, 6, 7]
b = filter(lambda x:x>5, a)
print(b)
[6, 7]
(2)map函数是对一个序列的每个项依次执行函数
a = map(lambda x: x*2, [1, 3, 2])
print(list(a))
[2, 6, 4]
(3)reduce函数式对一个序列的每个项迭代调用函数
from _functools import reduce
# 求3的阶乘
result = reduce(lambda x, y: x*y, range(1, 4))
print(result)
6
62、Python里的拷贝
import copy
a = [1, 2, 3, ["a", "b"]]
# 赋值
b = a
# 浅拷贝
c = copy.copy(a)
# 深拷贝
d = copy.deepcopy(a)
# 修改对象a
a.append(5)
a[3].append("c")
print(a)
print(b)
print(c)
print(d)
[1, 2, 3, [‘a’, ‘b’, ‘c’], 5]
[1, 2, 3, [‘a’, ‘b’, ‘c’], 5]
[1, 2, 3, [‘a’, ‘b’, ‘c’]]
[1, 2, 3, [‘a’, ‘b’]]
63、python中的is和==
is 是比较内存地址,而==是比较值
64、read、readline、readlines
read:读取整个文件
readline:读取下一行,使用生成器方法
readlines:读取整个文件到一个迭代器以供我们遍历
65、什么是python
(1)python是一种解释型的语言,这就是说,与c语言和c的衍生语言不同,python代码在运行之前不需要编译,其他解释型的语言还包括PHP和Ruby。
(2)python是动态类型的语言,指的是你在声明变量的时候,不需要说明变量的类型。
(3)python非常适合面向对象编程(OOP)
(4)python代码编写快,但是运行速度比编译语言要慢
(5)python用途非常广泛——网络应用,自动化,科学建模,大数据应用等,它通常被用作“胶水语言”,帮助其他语言和组件改善运行状况
66、阅读下面的代码,写出A0,A1到An的最终值。
A0 = dict(zip(("a", "b", "c", "d", "e"), (1, 2, 3, 4, 5)))
A1 = list(range(10))
A2 = [i for i in A1 if i in A0]
A3 = [A0[s] for s in A0]
A4 = [i for i in A1 if i in A3]
A5 = {i: i*i for i in A1}
A6 = [[i, i*i] for i in A1]
print(A0)
print(A1)
print(A2)
print(A3)
print(A4)
print(A5)
print(A6)
{‘a’: 1, ‘b’: 2, ‘c’: 3, ‘d’: 4, ‘e’: 5}
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[]
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
[[0, 0], [1, 1], [2, 4], [3, 9], [4, 16], [5, 25], [6, 36], [7, 49], [8, 64], [9, 81]]
67、下面代码会输出什么
def f(x,l=[]):
for i in range(x):
l.append(i*i)
print(l)
f(2)
f(3, [3, 2, 1])
f(3)
[0, 1]
[3, 2, 1, 0, 1, 4]
[0, 1, 0, 1, 4]
68、你如何管理不同版本的代码?
使用git进行版本控制,版本控制能够帮你追踪谁对代码库做了什么操作;发现新引入了什么bug;管理你的软件的不同版本和发行版;在团队成员中分享源代码;部署及其他自动化处理,还能让你回滚到出现问题之前的版本。
69、“猴子补丁”指的是什么?这种做法好吗
在函数或对象已经定义之后,再去改变他们的行为,大部分情况下,这是种很不好的做法,因为函数在代码库中的行为最好是都保持一致。打猴子补丁的原因可能是为了测试。
70、介绍一下except的用法和作用?
执行try下的语句,如果引发异常,则执行过程中会调用到except语句。对每个except分支顺序尝试执行,如果引发的异常与except中的异常相匹配,则执行相应的语句,如果所有的except都不匹配,则异常会传递到下一个调用本代码的最高层try代码中。
try下的语句正常执行,则执行else块代码,如果发生异常就执行except语句下的代码,如果存在finally语句,最后总是会执行。
71、Python中的pass语句的作用是什么
pass语句不会执行任何操作,一般作为占位符或者创建占位程序。
72、介绍一下python下range()函数的用法
for in range(10):
print(i)
0 1 2 3 4 5 6 7 8 9
73、如何用Python来进行查询和替换一个字符串
import re
p = re.compile("blue")
print(p.sub("red", "blue clothes"))
red clothes
74、python中match()和search()的区别?
print(re.match("super", "supersition").span())
print(re.match("super", "insupersition"))
print(re.search("super", "supersition").span())
print(re.search("super", "insupersition"))
# match检查string的开头是否匹配
# search搜索pattern中的第一个匹配值
(0, 5)
None
(0, 5)
75、用Python匹配HTML tag的时候,<.>和<.?>有何区别
贪婪匹配,从头到尾匹配和非贪婪匹配,只匹配到第一个
76、python中如何生成随机数?
random模块
随机整数:random.randint(a, b)
返回0-1之间的浮点数:random.random()
返回指定范围内的浮点数:random.uniform(a, b)
77、有没有一个工具可以帮助查找python的bug和进行静态的代码分析?
pychecker是一个Python代码的静态分析工具,它可以帮助查找python代码的bug,会对代码的复杂度和格式提出警告。
pylint是另外一个工具可以进行codingstandard检查。
78、如何在一个function里面设置一个全局的变量?
def fun():
global x
79、在python中的re模块中match、search、findall、finditer的区别
match:匹配string开头,成功返回Match object,失败返回None,只匹配一个。
search:在string中进行搜索,成功返回Match object,失败返回None,只匹配一个。
findall:在string中查找所有匹配成功的组,即用括号括起来的部分,返回对象,每个list item是由每个匹配的所有组组成的List。
finditer:在string中查找所有匹配成功的字符串,返回iterator,每个item是一个Match object。
——————操作系统——————
80、调度算法
(1)先来先服务
(2)短作业优先
(3)最高优先权调度
(4)时间片轮转
(5)多级反馈队列调度
实时调度算法:
(1)最早截止事件优先 EDF
(2)最低松弛度优先 LLF
81、死锁
原因:
(1)竞争资源
(2)程序推进顺序不当
必要条件:
(1)互斥条件:资源不能共享,只能被一个进程使用。
(2)请求和保持条件:进程已经获得一些资源,但因请求其他资源被阻塞,对已获得的资源保持不放。
(3)不剥夺条件:有些系统资源是不可抢占的,当某个进程已获得这种资源后,系统不能强行收回,只能由进程使用完时自己释放。
(4)环路等待条件:若干个进程形成环形链,每个都占用对方申请的下一个资源。
处理死锁基本方法:
(1)预防死锁
(2)避免死锁(银行家算法)
(3)检测死锁(资源分配图)
(4)解除死锁(剥夺资源、撤销进程)
82、程序编译与链接
(1)预处理
主要处理那些以"#"开始的预编译指令
(2)编译
编译过程就是把预处理完的文件进行一系列的词法分析、语法分析、语义分析及优化后生成相应的汇编代码文件。这个过程是整个程序构建的核心部分。
(3)汇编
汇编器是将汇编代码转化成机器可以执行的指令,每一条汇编语句几乎都是一条机器指令。经过编译、链接、汇编输出的文件成为目标文件。
(4)链接
链接的主要内容就是把各个模块之间相互引用的部分处理好,使各个模块可以正确的拼接。
83、静态链接和动态链接
静态链接方法:静态链接的时候,载入代码就会把程序会用到的动态代码或动态代码的地址确定下来。
静态库的链接可以使用静态链接,动态链接库也可以使用这种方法链接导入库。
动态链接方法:使用这种方式的程序并不在一开始就完成动态链接,而是直到真正调用动态库代码时,载入程序才计算动态代码的逻辑地址,然后等到某个时候,程序又需要调用另外某块动态代码时,载入程序又去计算这部分代码的逻辑地址,所以,这种方式使程序初始化时间较短,但运行期间的性能比不上静态链接的程序。
84、虚拟内存技术
虚拟存储器是指具有请求调入功能和置换功能,能从逻辑上对内存容量加以扩充的一种存储系统。
85、分页和分段
分页:用户程序的地址空间被划分成若干固定大小的区域,称为“页”,相应地,内存空间分成若干个物理块,页和块的大小相等。可将用户程序的任一页放在内存的任一块中,实现了离散分配。
分段:将用户程序地址空间分成若干个大小不等的段,每段可以定义一组相对完整的逻辑信息。存储分配时,以段为单位,段与段在内存中可以不相邻接,也实现了离散分配。
分页与分段的主要区别
(1)页是信息的物理单位,分页是为了实现非连续分配,以便解决内存碎片问题,或者说分页是由于系统管理的需要。段是信息的逻辑单位,它含有一组意义相对完整的信息,分段的目的是为了更好的实现共享,满足用户的需要。
(2)页的大小是固定的,由系统确定,将逻辑地址划分为页号和页内地址是由机器硬件实现的,而段的长度却不固定,决定于用户所编写的程序,通常由编译程序在对源程序进行编译时根据信息的性质来划分。
86、页面置换算法
(1)最佳置换算法OPT:不可能实现
(2)先进先出FIFO
(3)最近最久未使用算法LRU
(4)clock算法
87、边沿触发和水平触发
边缘触发是指每当状态变化时发生一个io事件
水平触发就是只要满足条件就发生一个io事件
——————数据库——————
88、事务
数据库事务,是指作为单个逻辑工作单元执行的一系列操作,要么完全的执行,要么完全的不执行。
89、数据库索引
索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息。
90、redis原理
redis是一个开源的key-value存储系统。与memcached类型,redis将大部分数据存储在内存中,支持的数据类型包括:字符串、哈希表、列表、集合、有序集合以及基于这些数据类型的相关操作。
redis使用c语言开发,指定的端口号是6379。
91、乐观锁和悲观锁
悲观锁:假定一定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。
乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反了数据完整性。
92、MVCC
是一种并发控制的方法,一般在数据库管理系统中,实现对数据的并发访问;在编程语言中实现事务内存。
93、MyISAM和InnoDB
MyISAM适合于一些需要大量查询的应用,但其对于大量写操作并不是很好。甚至你只是需要update一个字段,整个表都会被锁起来,而别的进程,就算是读进程都无法操作直到读操作完成。另外,MyISAM对于SELECT COUNT(*) 这类的计算是超快无比的。
InnoDB的趋势会是一个非常复杂的存储引擎,对于一些小的应用,他会比MyISAM还慢。支持“行锁”,于是在写操作比较多的时候,会更优秀,并且支持事务。
——————网络——————
94、三次握手
(1)客户端发送syn(建立连接)到服务端发起握手,并进入syn_send状态
(2)服务端收到syn包,必须确认客户的syn,同时自己也发送一个syn包,即ack+syn包,此时服务器进入syn_recv状态
(3)客户端收到syn+ack后,向服务器发送ack包进行确认,此包发送完毕,客户端和服务器进入established状态,完成三次握手。
握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接前,TCP连接都将被一直保持下去。
95、四次挥手
(1)客户端发送一个FIN(关闭连接),用来关闭客户端到服务器的数据传送
(2)服务端收到FIN后,发送一个ACK给客户端,服务端进入等待状态
(3)服务端发送一个FIN,用来关闭服务端到客户端的数据传送
(4)客户端收到FIN后,发送一个ACK给服务器端确认,完成四次挥手
为什么建立连接的时候是三次握手,关闭的时候却是四次挥手呢?
这是因为服务端收到客户端发送的syn连接请求之后,可以直接发送syn+ack报文,其中syn是用来同步的,ack是用来应答的。但是关闭连接时,当服务端收到fin报文时,很可能不会立即关闭socket,所以只能先回复一个ack报文,等到服务端的所有报文都发送完了,才发送FIN报文,因此需要四次。
为什么需要等待2MSL才能返回到close状态?
虽然按道理,四个报文发送完毕,我们可以直接进入close状态了,但是我们必须假设网络是不可靠的,有可能最后一个ACK会丢失。所以time_wait就是用来重发可能丢失的ack报文。如果服务端没有收到ack,将不断重复发送fin报文段,客户端在发送完ack之后,进入等待状态,如果这时间内再次收到了fin报文,说明服务端没有收到它发送的ack报文,此时客户端需要重发ack并再次等待。所谓的2MSL就是一个发送和一个回复所需的最大时间,如果在这个时间内都没有收到服务端发来的fin,证明客户端之前发送的ack已经被收到,此时可以结束TCP的连接。
如果已经建立了连接,客户端突然出现故障了怎么办?
TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等待下去,白白浪费资源,服务器每收到一次客户端的请求之后都会复位这个计时器,时间通常是2小时,若2小时后还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔76秒钟就发送一次。若一连发送10个探测报文段仍然没有反应,则服务器就认为客户端出了故障,接着就关闭连接。
96、ARP协议
地址解析协议(Address Resolution Protocol):根据IP地址获取物理地址的一个TCP/IP协议。
97、urllib和urllib2的区别
(1)urllib提供urlencode方法用来GET查询字符串的产生,而urllib2没有
(2)urllib2可以接受一个Request类的实例来设置url请求的headers,urllib仅可以接受URL。这意味着你不可以伪装你的User-Agent字符串等。
98、Post和Get区别
GET刷新按钮没有变化,POST数据会被重新提交(浏览器应该告知用户数据会被重新提交)。
GET书签可收藏,POST书签不可收藏。
GET能被缓存,POST不能缓存。
GET参数保留在浏览器历史中,POST参数不会保存在浏览器历史中。
GET对数据长度有限制,当发送数据时,GET方法向URL添加数据,URL的长度是受限制的,最大长度是2048个字符,POST无限制。
GET只允许ASCII字符,POST没有限制,也允许二进制数据。
GET安全性较差,因为所发送的数据是URL的一部分,POST更安全,因为参数不会被保存在浏览器历史或web服务器日志中。
99、Cookie和Session
cookie存储在客户端,session存储在服务器端。
cookie用来跟踪会话,也可以保存用户偏好位置或者保存用户名密码等,session用来跟踪会话。
cookie不安全,session比较安全。
100、apache和nginx的区别
nginx相对apache的优点:
(1)轻量级,比apache占用更少的内存及资源。
(2)抗并发,niinx处理请求是异步非阻塞的,支持更多的并发连接,而apache则是阻塞型的,在高并发下nginx能保持低资源消耗高性能。
(3)高度模块化的设计,编写模块相对简单
(4)社区活跃
apache相对nginx的优点:
(1)rewrite,比nginx的rewrite强大
(2)模块超多,基本想到的都可以找到
(3)少bug,nginx的bug相对较多
(4)超稳定
101、网站用户密码保存
(1)明文保存
(2)明文hash后保存,如md5
(3)MD5+SALT方式,这个salt可以随机
(4)知乎使用了Bcrypy加密
102、HTTP和HTTPS
HTTP:超文本传输协议,是一种详细规定了浏览器和万维网服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议。
HTTPS:是以安全为目标的HTTP通道,是HTTP的安全版,即HTTP加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。
103、CSRF和XSS
CSRF:跨站请求伪造,重点在请求
XSS:跨站脚本攻击,重点在脚本
104、SOAP
简单对象访问协议(simple object access protocol),是交换数据的一种协议规范,使用在计算机网络web服务中,交换带结构信息。SOAP为了简化网页服务器从XML数据库中提取数据时,节省去格式化页面时间,以及不同应用程序之前按照HTTP通信协议,遵从XML格式执行资料互换,使其抽象于语言实现、平台和硬件。
105、RPC
远程过程调用协议(remote procedure call protocol),是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据,在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。
106、CGI和WSGI
CGI是通用网关接口,是连接web服务器和应用程序的接口,用户通过CGI来获取动态数据或文件等。
CGI程序是一个独立的程序,它可以用几乎所有语言来写,包括perl,c,lua,python等。
WSGI,Web Server Gateway Interface,是python应用程序或框架和web服务器之间的一种接口,WSGI的其中一个目的就是让用户可以用统一的语言编写前后端。
107、中间人攻击
中间人攻击是指攻击者与通讯的两端分别创建独立的联系,并交换其所收到的数据,使通讯的两端认为他们正在通过一个私密的连接与对方直接对话,但事实上整个会话都会被攻击者完全攻击。
108、c10k问题
指的是服务器同时支持成千上万个客户端
109、socket
网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一段称为一个socket。建立网络通信连接至少要一对端口号。
socket = ip address + TCP/UDP + port
110、浏览器缓存
浏览器缓存机制,其实主要就是HTTP协议定义的缓存机制。
Expires策略:是Web服务器响应消息头字段,在响应http请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存存取数据,而无需再次请求。
Cache-control策略:与Expires的作用一致,都是指明当前资源的有效期,控制浏览器是否直接从浏览器 存取数据还是重新请求到服务器存取数据。只不过Cache-Control的选择更多,设置更细致,如果同时设置的话,其优先级高于Expires。
111、HTTP1.0和HTTP1.1
(1)请求头host字段,一个服务器多个网站
(2)长链接
(3)文件断点续传
(4)身份认证,状态管理,Cache缓存
112、Ajax
异步的JavaScript和XML,是在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页的技术。
——————数据结构——————
113、红黑树
红黑树与AVL的比较:AVL是严格平衡树,因此在增加或者删除节点的时候,根据不同情况,旋转的次数比红黑树要多;
红黑是用非严格的平衡来换取增删节点时候旋转次数的降低;
所以简单说,如果你的应用中,搜索的次数远远大于插入和删除,那么选择AVL,如果搜索,插入删除次数几乎差不多,应该选择RB。
114、台阶问题/斐波那契
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上1个n级台阶总共有多少种跳法。
fib = lambda n: n if n < 2 else fib(n-1) + fib(n-2)
print(fib(5))
5
115、变态台阶问题
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶…也可以跳上n级台阶。求该青蛙跳上一个n级台阶总共有多少种跳法。
fib = lambda n: n if n < 2 else fib(n-1) * 2
print(fib(3))
4
116、矩形覆盖
我们可以用21的小矩形横着或者 竖着去覆盖更大的矩形,请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法
f = lambda n: 1 if n < 2 else f(n-1) + f(n-2)
print(f(3))
3
117、去除列表中的重复元素
(1)使用集合
l = [1, 2, 3, 2, 1, 2, 1]
print(list(set(l)))
[1, 2, 3]
(2)使用字典
l1 = ["b", "c", "d", "b", "c", "a", "a"]
l2 = {}.fromkeys(l1).keys()
print(list(l2))
[‘b’, ‘c’, ‘d’, ‘a’]
(3)先排序然后删除
l1 = ["b", "c", "d", "b", "c", "a", "a"]
l2 = []
[l2.append(i) for i in l1 if not i in l2]
print(l2)
[‘b’, ‘c’, ‘d’, ‘a’]
118、创建字典的方法
(1)直接创建
dict = {"name": "earth", "port":80}
(2)工厂方法
items = [("name", "earth"), ("port", 80)]
dict2 = dict(items)
print(dict2)
{‘name’: ‘earth’, ‘port’: 80}
(3)fromkeys()方法
dict1 = {}.fromkeys(("x", "y"), -1)
print(dict1)
{‘x’: -1, ‘y’: -1}
——————web相关——————
119、解释一下WSGI和FastCGI的关系?
CGI全称是“公共网关接口”,HTTP服务器与你的或其他机器上的程序进行“交谈”的一种工具,其程序必须运行在网络服务器上。CGI可以用任何一种语言编写,只要这种语言具有标准输入、输出和环境变量。如php,perl,tcl等。
FastCGI是语言无关的、可伸缩架构的CGI开放扩展,其主要行为是将CGI解释器进程保持在内存在并因此获得较高的性能。
WSGI的全称是Python web服务器网关接口,它是Python应用程序和WEB服务器之间的一种接口,目的是建立一个简单的普遍适用的服务器与WEB框架之间的接口。
120、解释一下Django和Tornado的关系、差别
Django是一个大而全的web应用框架,使用MVT开发模式,M表示model,负责与数据库进行交互,V表示views,是核心,负责接收请求、获取数据、返回结果,T表示template,负责呈现内容到浏览器。
Tornado是 FriendFeed使用的可扩展的非阻塞式 web 服务器及其相关工具的开源版本。这个 Web 框架看起来有些像 web.py 或者 Google 的 webapp,不过为了能有效利用非阻塞式服务器环境,这个 Web 框架还包含了一些相关的有用工具和优化。
Tornado 和现在的主流 Web 服务器框架(包括大多数Python 的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快。得利于其 非阻塞的方式和对epoll的运用,Tornado 每秒可以处理数以千计的连接,这意味着对于实时 Web服务来说,Tornado 是一个理想的 Web 框架。我们开发这个 Web 服务器的主要目的就是为了处理 FriendFeed 的实时功能 ——在 FriendFeed 的应用里每一个活动用户都会保持着一个服务器连接。(关于如何扩容 服务器,以处理数以千计的客户端的连接的问题。
121、如何进行Django单元测试
django的单元测试使用python的unittest模块,这个模块使用基于类的方法来定义测试。类名为django.test.TestCase,继承于python的unittest.TestCase。
122、解释HTTP协议
HTTP是一个属于应用层的面向对象的协议,由于其简洁、快速的方式,适用于分布式超媒体信息系统。
(1)支持客户/服务器模式
(2)简单快速:客户向服务器请求服务时,只需要传送请求方法和路径。请求方法常用的有GET\HEAD\POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
(3)灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。
(4)无连接:限制每次连接只处理一个请求。服务器处理完客户的请求,并受到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
(5)无状态:指协议对于事务处理没有记忆能力。缺少状态意味着如果后续需要处理前面的信息,则必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
123、解释下http请求头和常见的响应状态码
Accept:指浏览器或其他客户可以接受的MIME文件格式。可以根据它判断并返回适当的文件格式。
Accept-Charset:指出浏览器可以接受的字符编码。默认是ISO-8859-1。
Accept-Language:指出浏览器可以接受的语言种类。
Accept-Encoding:指出浏览器可以接受的编码方式。
Cookie:浏览器用这个属性向服务器发送Cookie,Cookie是在浏览器中寄存的小型数据体,它可以记载和服务器相关的用户信息,也可以用来实现会话功能。
状态码由3位数字组成,第一个数字定义了响应的类别,且有5种可能取值:
1xx:指示信息——表示请求已接收,继续处理
2xx:成功——表示请求已被成功接收、理解、接受
3xx:重定向——要完成请求必须进行更进一步的操作
4xx:客户端错误——请求有语法错误或请求无法实现
5xx:服务器端错误——服务器未能实现合法的请求
200 OK //客户端请求成功
400 Bad Request //客户端请求有语法错误,不能被服务器所理解
401 Unauthorized //请求未经授权
403 Forbidden //服务器收到请求,但是拒绝提供服务
404 Not Found //请求资源不存在
500 Internal Server Error //服务器发生不可预期的错误
503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后可能恢复正常
124、哪些操作会导致Python内存溢出,怎么处理?
(1)内存中加载的数据量过于庞大,如一次从数据库中取出过多数据
(2)集合类中有对对象的引用,使用完后未清空,产生了堆积,使得JVM不能回收
(3)代码中存在死循环或循环产生过多重复的对象实体
(4)使用的第三方软件中的BUG
(5)启动参数内存值设定的过小
解决方案:
(1)修改JVM启动参数,直到增加内存
(2)检查错误日志
(3)对代码进行走查和分析,找出可能发生内存溢出的位置
125、Mysql怎样限制ip访问的
grant all privileges on . to "数据库中用户名“ @"ip地址" identified by "数据库密码";
126、什么是lambda函数,写一个函数求两个数的和
lambda函数是匿名函数,可以接受任意参数并且返回单个表达式值的函数。
lambda函数比较轻便,一般给filter,map这样的函数式编程使用。
res = lambda x, y: x+y
print(res(1, 2))
3
127、TCP和UDP的区别
(1)TCP面向连接;UDP是无连接的,即发送数据之前不需要建立连接
(2)TCP提供可靠的服务,也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
(3)TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的,没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低
(4)每一条 TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
(5)TCP首部开销20字节;UDP的首部开销小,只有8字节
129、HTTP请求方法
GET:请求指定的页面信息,并返回实体主体。
HEAD:类似于GET请求,只不过返回的响应中没有具体的内容,用于获取报头。
POST:向指定资源提交数据进行处理请求。数据请求可能会导致新的资源的建立或已有资源的修改。
PUT:从客户端向服务器传送的数据取代指定的文档的内容。
DELETE:请求服务器删除指定的页面。
CONNECT:预留给能够将连接改为管道方式的代理服务器。
OPTIONS:允许客户端查看服务器的性能。
TRACE:回显服务器收到的请求,主要用于测试或诊断。
130、使用socket套接字需要传入哪些参数
IP和端口号
131、七层模型
应用层
表示层
会话层
传输层
网络层
数据链路层
物理层
132、url的形式
url参数字符串中使用key=value键值对这样的形式来传参,键值对之间以&符号分隔,url的编码格式采用的是ASCII码,而不是unicode。
133、Flask和Django路由映射的区别?
在django中,路由是浏览器访问服务器时,先访问项目中的url,再由项目中的url找到应用中的url,这些url是放在一个列表中的,遵循从前往后匹配的规则。
在flask中,路由是通过装饰器给每个视图函数提供的,而且根据请求方式的不同可以一个url用于不同的作用。
134、对设计模式的理解,简述你了解的设计模式
设计模式是经过总结,优化的,对我们经常会碰到的一些编程问题的可重用解决方案。一个设计模式并不想一个类和一个库一样能够直接作用于我们的代码,反之,设计模式更为高级,它是一种必须在特定情形下实现的一种方法模板。常见的模式有工厂模式和单例模式。
135、单例模式的应用场景有哪些
单例模式的应用场景一般发生在以下条件下:资源共享的情况下,避免由于资源操作时导致的性能或损耗等,如日志文件,应用配置。控制资源的情况下,方便资源之间的互相通信。如线程池等,网站的计数器,应用配置,多线程池,数据库配置,数据库连接池,引用程序的日志应用。
136、爬虫与反爬虫
反爬虫手段
(1)检测User-Agent
(2)检测非人行为,封禁ip
(3)动态页面
(4)要求登录
(5)验证码
绕过反爬虫的措施
(1)设置User-Agent
(2)设置随机延迟时间,随机的更换代理ip
(3)selenium+浏览器,模拟ajax请求
(4)模拟登录:
a、用登录过之后的cookie模拟登录;
b、模拟发送登录表单;
c、selenium模拟登录
(5)验证码处理:
a、Tessractor识别图片中的文本(OCR)
b、打码平台;
c、滑动验证码的识别,使用selenium模拟拖动
137、数据库设计的三大范式
(1)第一范式:确保每列保持完整性
(2)第二范式:确保表中的每列都和主键相关
(3)第三范式:确保每列都和主键列直接相关,而不是间接相关
138、事务的基本要素
(1)原子性:事务开始后的所有操作,要么全部做完,要么全部不做,不可滞留在中间环节
(2)一致性:事务开始前和结束后,数据库的完整性约束没有被破坏
(3)隔离性:同一时间,只允许一个事务请求同意数据,不同事务之间彼此没有任何干扰
(4)持久性:事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚
139、MVC框架
核心思想是解耦,降低各功能模块之间的耦合性,方便变更,更容易重构代码,最大程度上实现代码的重用。
m表示model,主要用于对数据库层的封装
v表示view,用于向用户展示结果
c表示contrller,是核心,用于处理请求,获取数据,返回结果
140、MVT框架
m表示model,负责与数据库交互
v表示view,是核心,负责接受请求,获取数据,返回结构
t表示template,负责呈现内容到浏览器
141、ORM
对象关系映射,主要实现程序对象到关系数据库数据的映射。
类——>数据表
对象——>数据行
属性——>字段
142、scrapy流程
首先爬虫spider将需要发送请求的url经引擎发送给调度器,Scheduler处理之后经引擎发送给Downloader,Downloader向网路服务器发送服务器请求进行下载,得到响应后将下载的数据经引擎交给Spider,Spider会对网页进行分析,分析出来的结果有两种,一种是需要进一步抓取的链接,这些链接会被传回Scheduler,另一种是需要保存的数据,它们则被送到Item Pipeline,Item会定义数据格式,最后由Pipeline对数据进行清洗、去重等处理后存储到文件或数据库。
143、什么是面向对象
OOP:是一种编程的思想,把对象当成一个程序的基本单元,一个对象包含了数据和操作数据的函数。面向对象的出现极大的提高了编程的效率,使其编程的重用性增大。
封装:把需要重用的函数或者功能封装,方便其他程序直接调用
继承:子类可以继承父类的某些功能
多态:一个函数有多重表现形式,调用一个方法有多种形式,但是表现出来的方法是不一样的
144、nginx的作用
实现构架:客户端请求nginx,再由nginx请求uwsgi,运行django框架下的代码
(1)负载均衡:多台服务器轮流处理请求
(2)反射代理:隐藏真实服务器
115、HTTP请求过程
当我们在web浏览器的地址栏中输入:www.baidu.com,然后回车,到底发生了什么。
(1)对www.baidu.com这个网址进行DNS域名解析,得到对应的IP地址
(2)根据这个IP,找到对应的服务器,发起TCP的三次握手
(3)建立TCP连接后发起HTTP请求
(4)服务器响应HTTP请求,浏览器得到html代码
(5)浏览器解析html代码,并请求html代码中的资源,如js,css图片等
(6)浏览器对页面进行渲染呈现给用户
116、HTTPS如何实现加密机制
使用SSL协议进行加密传输,让客户端拿到服务器的公钥,然后客户端随机生成一个对称加密的秘钥,使用公钥加密,传输给服务端,后续的所有信息都通过该对称秘钥进行加密解密,完成整个HTTPS的流程。
117、AJAX请求流程
(1)创建一个XMLHttpRequest对象
(2)创建一个新的HTTP请求,并指定该请求的方法,url及验证信息
(3)设置响应HTTP请求状态变化的函数
(4)发送HTTP请求
(5)获取异步调用返回的数据
(6)使用js和DOM实现局部刷新
118、socket编程
socket简称套接字,是进程间通信的一种, 与其他进程间通信间通信的一个不同是,它能实现不同主机上的进程间通信,我们网络上各种各样的服务大多是基于socket来完成通信的。
在程序中,如果要完成一个tcp服务器的功能,需要的流程如下:
(1)socket绑定一个套接字
(2)bind绑定id和port
(3)listen使套接字变为可以被动连接
(4)accept等待客户端的连接
(5)recv/send接收发送数据
119、numpy
(1)提供了一个在python中做科学计算的基础库,重在数值计算,主要用于多维数组(矩阵)处理的库。
(2)高性能科学计算和数据分析的基础包,用来存储和处理大型矩阵,比python 中自身的嵌套列表结构要高效的多。
(3)本身是由c语言开发,核心是ndarray对象
120、pandas
pandas是一个强大的分析结构化数据的工具集,基于Numpy构建,提供了高级数据结构和数据操作工具,应用于数据挖掘和数据分析,提供数据清洗功能。
121、项目部署流程
将项目上传到服务器的一个文件目录下,安装并创建虚拟环境,在虚拟环境下安装所有需要的包,安装并配置uwsgi服务器,安装配置nginx,收集静态文件