一、Python基础
1、什么是python,使用python有什么好处
什么是python:
Python是一种跨平台的计算机程序设计语言。
Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言
是一种面向对象的动态类型语言
python语法简洁,支持动态输入,是解释性语言
使用python的好处:
免费开源,可移植性
可扩展性,可嵌入性
丰富的标准和扩展库
2、如何在一个function里面对一个全局变量赋值
使用关键字 global
x = 0 def fun(): global x x = 1 print(x)
3、写出一段代码实现删除list里面的重复元素
使用set函数
l = [2, 3, 5, 8, 6, 1, 2, 5, 8, 10, 88, 62] s = set(l) l = list(s)
4、列表和元组的区别
最大的区别就是
列表是可变的,元组不可变
列表是动态数组,内部数据可修改且可以改变长度
元组是静态数组,其内部数据一旦创建便无法改变
5、深拷贝与浅拷贝的区别
我的理解
深拷贝copy.deepcopy() 跟与原对象无任何关系,不随原对象的变化而变化,拷贝后完全开辟新的内存地址来保存之前的对象
浅拷贝copy.copy() 与原对象任由联系,随原对象变化而变化
其他说法
复制不可变数据类型,不管copy还是deepcopy,都是同一个地址当浅复制的值是不可变对象(数值,字符串,元组)时和=“赋值”的情况一样,对象的id值与浅复制原来的值相同。
复制的值是可变对象(列表和字典)
浅拷贝copy有两种情况:
第一种情况:复制的 对象中无 复杂 子对象,原来值的改变并不会影响浅复制的值,同时浅复制的值改变也并不会影响原来的值。原来值的id值与浅复制原来的值不同。
第二种情况:复制的对象中有 复杂 子对象 (例如列表中的一个子元素是一个列表), 改变原来的值 中的复杂子对象的值 ,会影响浅复制的值。
深拷贝deepcopy:完全复制独立,包括内层列表和字典
import copy
orign = [1, [21, 3], 4, [1, 2]]
qcopy= copy.copy(orign)
scopy = copy.deepcopy(orign)
orign.append("66")
orign[1].append(6)
print(orign)
print(qcopy)
print(scopy)
结果
[1, [21, 3, 6], 4, [1, 2], '66']
[1, [21, 3, 6], 4, [1, 2]]
[1, [21, 3], 4, [1, 2]]
结论:
表层对象修改时,浅拷贝的对象不会变化,但是内部深一层的对象变化时,浅拷贝的对象也会随之变化
另外三个对象内部各元素的id是相同的,但是对于深拷贝中元素为可变类型对象时,id同前两者时不同的
6、列举几个python标准库
自带的库:
os:提供操作系统相关联的函数
sys:常用语命令行参数
math:数学运算
time random datetime
第三方库
re:正则匹配
django
flask
requests
scrapy
7、字典删除键、合并字典
删除 del
合并 update()
dic1 = { "a":1,"b":2,"d":5 } dic2 = { "b":3,"c":4,"e":6 } del dic2["b"] dic1.update(dic2) print(dic1) print(dic2)
结果
{'a': 1, 'b': 2, 'd': 5, 'c': 4, 'e': 6}
{'c': 4, 'e': 6}
8、简述GIL
GIL(全局解释器锁)
python GIL简述
GIL 全称 Global Interpreter Lock(全局解释器锁),任何 Python 线程执行前,必须先获得 GIL 锁,然后,每执行100条字节码,解释器就自动释放GIL锁,让别的线程有机会执行。要避免这种“现象”利用操作系统的多核优势可以有下面几种方法:
- 使用 C 语言编写扩展,创建原生线程,摆脱 GIL,但是即使是扩展,在 Python 代码内,任意一条Python 代码还是会有 GIL 限制
- 使用多进程代替多线程,使用多进程时,每个进程都有自己的 GIL。故不存在进程与进程之间的 GIL 限制。但是多进程不能共享内存。
每个线程在执行的过程都需要先获取GIL,保证同一时刻只有一个线程可以执行代码。
线程释放GIL锁的情况:在IO操作等可能会引起阻塞的systemcall之前,可以暂时释放GIL,但在执行完毕后,必须重新获取GIL
Python3.x使用计时器(执行时间达到阈值后,当前线程释放GIL)
(1)在处理像科学计算这类需要持续使用cpu的任务的时候单线程会比多线程快
(2)在处理像IO操作等可能引起阻塞的这类任务的时候多线程会比单线程
9、如何提高python的运行效率
使用生成器可节省内存
核心模块使用外部功能包 cpython,pypy等
循环代码优化
交叉编译
10、实现单例模式
单例模式:一个类有且仅有一个实例
通过重写 __new__(cls)方法去实现类只创建一个实例
class DL(object):
# 当前实例的判断
instance = None
def __new__(cls):
if cls.instance == None:
cls.instance = object.__new__(cls)
return cls.instance
else:
# 返回上一个对象的引用
return cls.instance
11、fun(*args,**kwargs)中的*args,**kwargs什么意思?
12、简述装饰器
他们是修改其他函数的功能的函数,有助于让我们的代码更简短
装饰器可以把与业务逻辑无关的代码抽离出来,让代码保持干净清爽,而且装饰器还能被多个地方重复利用
from functools import wraps
def a_new_decorator(a_func):
@wraps(a_func)
def wrapTheFunction():
print("I am doing some boring work before executing a_func()")
a_func()
print("I am doing some boring work after executing a_func()")
return wrapTheFunction
@a_new_decorator
def a_function_requiring_decoration():
"""Hey yo! Decorate me!"""
print("I am the function which needs some decoration to "
"remove my foul smell")
类装饰器
相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器主要依靠类的__call__方法
class Foo(object):
def __init__(self, func):
self._func = funcdef __call__(self):
print ('class decorator runing')
self._func()
print ('class decorator ending')@Foo
def bar():
print ('bar')
bar()
13、python内建数据类型有哪些
整型--int
布尔型--bool
字符串--str
列表--list
元组--tuple
字典--dict
14、简述面向对象中__new__和__init__区别
__init__是初始化方法,创建对象后,就立刻被默认调用了,可接收参数
__new__至少要有一个参数cls,代表当前类,此参数在实例化时由Python解释器自动识别
__new__必须要有返回值,返回实例化出来的实例
__init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值
如果__new__创建的是当前类的实例,会自动调用__init__函数,通过return语句里面调用的__new__函数的第一个参数是cls来保证是当前类实例,如果是其他类的类名,;那么实际创建返回的就是其他类的实例,其实就不会调用当前类的__init__函数,也不会调用其他类的__init__函数
__init__
只是单纯的对实例进行某些属性的初始化,以及执行一些需要在新建对象时的必要自定义操作,无返回值。而 __new__
返回的是用户创建的实例,这个才是真正用来创建实例的,所以 __new__
是在 __init__
之前执行的,先创建再初始化
15、简述with方法
16、python中生成随机整数、随机小数、0--1之间小数方法
随机整数:random.randint(a,b),生成区间内的整数
随机小数:numpy库,np.random.randn(n)生成n个随机小数
0-1随机小数:random.random(),括号中不传参
17、避免转义给字符串加哪个字母表示原始字符串?
r'str'
18、python中断言方法举例
assert()方法,断言成功,则程序继续执行,断言失败,则程序报错
19、列出python中可变数据类型和不可变数据类型,并简述原理
不可变数据类型:整型int、浮点型float、字符串型string和元组tuple
不允许变量的值发生变化,如果改变了变量的值,相当于是新建了一个对象,而对于相同的值的对象,在内存中则只有一个对象,内部会有一个引用计数来记录有多少个变量引用这个对象
可变数据类型:list dict
允许变量的值发生变化,即如果对变量进行变化的操作后,只是改变了变量的值,而不会新建一个对象,变量引用的对象的地址也不会变化
20、利用collections库的Counter方法统计字符串每个单词出现的次数
from collections import Counter strings = "dewfefdbshdcbeyfgejsycgdhzcyevdsjbc" print(Counter(strings))
结果
Counter({'d': 5, 'e': 5, 'c': 4, 'f': 3, 'b': 3, 's': 3, 'y': 3, 'h': 2, 'g': 2, 'j': 2, 'w': 1, 'z': 1, 'v': 1})
21、filter方法 求出列表所有奇数并构造新列表,a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
22、正则re.complie作用
re.compile是将正则表达式编译成一个对象,加快速度,并重复使用
23、a=(1,)b=(1),c=("1") 分别是什么类型的数据?
元组 整型 字符串
24、请用datetime模块打印如下格式的时间 “2019-09-12 15:10:51”
import datetime print(datetime.datetime.now().strftime('%Y-%m-%d:%H:%M:%S'))
其中的%Y可以改成小写的y将显示两位的年份
%m改成%h可以显示英文的月份(截取的月份单词的前三位)
25、自定义异常代码
a = 9 try: for i in range(a): if i == 5: raise Exception("到此为止") except Exception as e: print(e)
26、正则表达式匹配中,(.*)和(.*?)匹配区别?
(.*)是贪婪匹配,会把满足正则的尽可能多的往后匹配
(.*?)是非贪婪匹配,会把满足正则的尽可能少匹配
27、[[1,2],[3,4],[5,6]]一行代码展开该列表,得出[1,2,3,4,5,6]
将列表转成numpy矩阵,通过numpy的flatten()方法 或者列表推导式
print(np.array([[1,2],[3,4],[5,6]]).flatten().tolist())
28、x="A",y="def",z=["d","e","f"],分别求出x.join(y)和x.join(z)返回的结果
dAeAf
dAeAf
import os basePath = r"F:\a\b" print("os.path.join()") print(os.path.join(basePath,"c"))
29、zip()函数用法
zip()函数在运算时,会以一个或多个序列(可迭代对象)做为参数,返回一个元组的列表。同时将这些序列中并排的元素配对
zip()参数可以接受任何类型的序列,同时也可以有两个以上的参数;当传入参数的长度不同时,zip能自动以最短序列长度为准进行截取,获得元组。
zip_a = ["a", "b", "c"] zip_b = [1, 2, 3, 4, 5] print(list(zip(zip_a,zip_b)))
30、a="张飞 98分",用re.sub,将98替换为100
grade = "张飞 98分" print(re.sub(r'\d+', '100',grade))
31、a="hello"和b="你好"编码成bytes类型
a=b"hello" b="你好".encode() print(a) print(b)
32、list=[2,3,5,4,9,6],从小到大排序,不许用sort,输出[2,3,4,5,6,9]
使用min()
求三个方法打印结果33、对于函数fn(k,v,dic={})
fn("one",1)直接将键值对传给字典;
fn("two",2)因为字典在内存中是可变数据类型,所以指向同一个地址,传了新的额参数后,会相当于给字典增加键值对
fn("three",3,{})因为传了一个新字典,所以不再是原先默认参数的字典
此处其实就是函数参数中传入了一个默认的字典参数参数
由于字典是可变类型,在不传入第三个字典参数的情况下,当多次调用该函数时,默认的字典一直在添加添加键值对
如果像第三次调用传入了指定的字典参数,那么会生成新的字典,在新的字典中赋予键值对
33、简述多线程、多进程
进程:
1、操作系统进行资源分配和调度的基本单位,多个进程之间相互独立
2、稳定性好,如果一个进程崩溃,不影响其他进程,但是进程消耗资源大,开启的进程数量有限制
线程:
1、CPU进行资源分配和调度的基本单位,线程是进程的一部分,是比进程更小的能独立运行的基本单位,一个进程下的多个线程可以共享该进程的所有资源
2、如果IO操作密集,则可以多线程运行效率高,缺点是如果一个线程崩溃,都会造成进程的崩溃
应用:
IO密集的用多线程,在用户输入,sleep 时候,可以切换到其他线程执行,减少等待的时间
CPU密集的用多进程,因为假如IO操作少,用多线程的话,因为线程共享一个全局解释器锁,当前运行的线程会霸占GIL,其他线程没有GIL,就不能充分利用多核CPU的优势
34、简述any()和all()方法
python中为假的元素:0,空字符串,空列表、空字典、空元组、None, False
- any():只要迭代器中有一个元素为真就为真
- all():迭代器中所有的判断项返回都是真,结果才为真
35、各种异常
- IOError:输入输出异常
- AttributeError:试图访问一个对象没有的属性
- ImportError:无法引入模块或包,基本是路径问题
- IndentationError:语法错误,代码没有正确的对齐
- IndexError:下标索引超出序列边界
- KeyError:试图访问你字典里不存在的键
- SyntaxError:Python代码逻辑语法出错,不能执行
- NameError:使用一个还未赋予对象的变量
36、列出几种魔法方法并简要介绍用途
- __init__:对象初始化方法
- __new__:创建对象时候执行的方法,单列模式会用到
- __str__:当使用print输出对象的时候,只要自己定义了__str__(self)方法,那么就会打印从在这个方法中return的数据
- __del__:删除对象执行的方法
37、C:Users y-wu.junyaDesktop>python 1.py 22 33命令行启动程序并传参,print(sys.argv)会输出什么数据
文件名和参数构成的列表
38、a = " hehheh ",去除首尾空格
strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列
39、使用lambda函数对list排序foo = [-5,8,0,4,9,-4,-20,-2,8,2,-4],输出结果为[0,2,4,8,8,9,-2,-4,-4,-5,-20],正数从小到大,负数从大到小
(传两个条件,x<0和abs(x))
foo = [-5,8,0,4,9,-4,-20,-2,8,2,-4] print(sorted(foo,key=lambda x:(x<0,abs(x))))
40、元组,列表,字典的嵌套排序
- 列表嵌套字典的排序,分别根据年龄和姓名排序
foo = [{"name":"zs","age":19},{"name":"ll","age":54},{"name":"wa","age":17},{"name":"df","age":23}]
foo.sort(key=lambda x:x['age'])
foo.sort(key=lambda x:x['name'])
- 列表嵌套元组,分别按字母和数字排序
- 列表嵌套列表排序,年龄数字相同怎么办?
foo = [["lucifer",16],["loveless",16],["reforget",18]] foo.sort(key=lambda x:(x[0],x[1]))
- 根据键对字典排序(方法一,zip函数)
其实就是将字典转换成列表进行排序
dic = { 'name':'loveless', 'age':16, 'love':'her' } f = list(zip(dic.keys(),dic.values()))
- 根据键对字典排序(方法二,不用zip)
使用dic.items()默认就是个列表嵌套元组的对象,可以直接使用sort函数
41、python字典和json字符串相互转化方法
json.dumps()字典转json字符串,json.loads()json转字典
42、用两种方法去空格
split 以及replace
43、简述python引用计数机制
python垃圾回收主要以引用计数为主,标记-清除和分代清除为辅的机制,其中标记-清除和分代回收主要是为了处理循环引用的难题。
引用计数算法
当有1个变量保存了对象的引用时,此对象的引用计数就会加1
当使用del删除变量指向的对象时,如果对象的引用计数不为1,比如3,那么此时只会让这个引用计数减1,即变为2,当再次调用del时,变为1,如果再调用1次del,此时会真的把对象进行删除
44、简述乐观锁和悲观锁
- 悲观锁, 就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
- 乐观锁,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制,乐观锁适用于多读的应用类型,这样可以提高吞吐量
45、正则表达式匹配出<html><h1>www.itcast.cn</h1></html>
前面的<>和后面的<>是对应的,可以用此方法
hlist = ['<html><h1>www.itcast.cn</h1></html>','<html><h1>www.itcast.cn</h2></html>']
for each in hlist:
ret = re.match(r'<(\w*)><(\w*)>.*?</\2></\1>',each)
if ret:
print(ret.group())
46、python传参数是传值还是传址
Python中函数参数是引用传递(注意不是值传递)。对于不可变类型(数值型、字符串、元组),因变量不能修改,所以运算不会影
响到变量自身;而对于可变类型(列表字典)来说,函数体运算可能会更改传入的参数变量。
47、求两个列表的交集、差集、并集
l1 = [1, 2, 3, 5]
l2 = [9, 5, 3, 7]
# 交集
print([i for i in l1 if i in l2])
print(list(set(l1).intersection(set(l2))))
# 并集
print(list(set(l1).union(set(l2))))
# 差集
print(list(set(l1).difference(set(l2))))
48、lambda匿名函数好处
- lambda函数比较轻便,即用即仍,很适合需要完成一项功能,但是此功能只在此一处使用,连名字都很随意的情况下;
- 匿名函数,一般用来给filter,map这样的函数式编程服务
- 作为回调函数,传递给某些应用,比如消息处理
49、python垃圾回收机制
python垃圾回收主要以引用计数为主,标记-清除和分代清除为辅的机制,其中标记-清除和分代回收主要是为了处理循环引用的难题。
引用计数算法
当有1个变量保存了对象的引用时,此对象的引用计数就会加1
当使用del删除变量指向的对象时,如果对象的引用计数不为1,比如3,那么此时只会让这个引用计数减1,即变为2,当再次调用del时,变为1,如果再调用1次del,此时会真的把对象进行删除
50、python正则中search和match
match()函数只检测字符串开头位置是否匹配,匹配成功才会返回结果,否则返回None
search()函数会在整个字符串内查找模式匹配,直到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。
51、字符串格式化:%和.format的区别
字符串的format函数非常灵活,很强大,可以接受的参数不限个数,并且位置可以不按顺序,
而且有较为强大的格式限定符(比如:填充,对齐,精度等)
52、以下的代码的输出将是什么? 说出你的答案并解释
class
Parent(
object
):
x
=
1
class
Child1(Parent):
pass
class
Child2(Parent):
pass
Parent.x, Child1.x, Child2.x
Child1.x
=
2
Parent.x, Child1.x, Child2.x
Parent.x
=
3
Parent.x, Child1.x, Child2.x
>>
1
1
1
1
2
1
3
2
3
在 Python中,类变量在内部是作为字典处理的,如果一个变量的名字没有在当前类的字典中发现,将搜索祖先类(比如父类)直到被引用的变量名被找到
如果任何它的子类重写了该值(例如,我们执行语句 Child1.x
=
2
)该值仅仅在子类中被改变
最后,如果该值在父类中被改变(例如,我们执行语句 Parent.x
=
3
),这个改变会影响
到任何未重写该值的子类当中的值
53、模块是什么
Python 模块(Module),是一个 Python 文件,以 .py 结尾,包含了 Python 对象定义和Python语句。
模块让你能够有逻辑地组织你的 Python 代码段。
把相关的代码分配到一个模块里能让你的代码更好用,更易懂。
模块能定义函数,类和变量,模块里也能包含可执行的代码。
54、dir()是什么指令
dir
(module)是一个非常有用的指令,可以通过它查看任何模块中所包含的工具。
55、python中 if __name__ == '__main__': 的作用是什么呢
在执行之前会根据当前运行的模块是否为主程序而定义变量__name__的值为__main__还是模块名
56、==
和 is
区别
- is 比较的是两个实例对象是不是完全相同,它们是不是同一个对象,占用的内存地址是否相同。莱布尼茨说过:“世界上没有两片完全相同的叶子”,这个is正是这样的比较,比较是不是同一片叶子(即比较的id是否相同,这id类似于人的身份证标识)
- == 比较的是两个对象的内容是否相等,即内存地址可以不一样,内容一样就可以了。这里比较的并非是同一片叶子,可能叶子的种类或者脉络相同就可以了。默认会调用对象的 __eq__()方法
57、连接字符串都有哪些方式
- 格式化字符连接(
%s
) - format
- join
- +
58、Python 里面怎么实现协程
可以用 yield 关键字实现
从句法上看,协程与生成器类似,都是定义体中包含 yield 关键字的函数。可是,在协程中, yield 通常出现在表达式的右边(例如, datum = yield),可以产出值,也可以不产出 —— 如果 yield 关键字后面没有表达式,那么生成器产出 None
def simple_coroutine():
print('-> start')
x = yield
print('-> recived', x)sc = simple_coroutine()
next(sc)
sc.send('zhexiao')
解释:
1. 协程使用生成器函数定义:定义体中有 yield 关键字。
2. yield 在表达式中使用;如果协程只需从客户那里接收数据,那么产出的值是 None —— 这个值是隐式指定的,因为 yield 关键字右边没有表达式。
3. 首先要调用 next(…) 函数,因为生成器还没启动,没在 yield 语句处暂停,所以一开始无法发送数据。
4. 调用send方法,把值传给 yield 的变量,然后协程恢复,继续执行下面的代码,直到运行到下一个 yield 表达式,或者终止。
注:send方法只有当协程处于 GEN_SUSPENDED 状态下时才会运作,所以我们使用 next() 方法激活协程到 yield 表达式处停止,或者我们也可以使用 sc.send(None),效果与 next(sc) 一样
协程的四个状态
协程可以身处四个状态中的一个。当前状态可以使用inspect.getgeneratorstate(…) 函数确定,该函数会返回下述字符串中的一个:
1. GEN_CREATED:等待开始执行
2. GEN_RUNNING:解释器正在执行
3. GEN_SUSPENED:在yield表达式处暂停
4. GEN_CLOSED:执行结束
59、谈谈python的装饰器,迭代器,yield?
- 装饰器
也就是在不改变原来函数的代码及调用方式的前提下对原函数进行功能上的完善。其核心原理其实是利用闭包
- 迭代器 (Iterator)
是一种 对象,它能够用来 遍历 容器中的元素,每个迭代器对象代表容器中的确定的地址。 可以被next()
函数调用并不断返回下一个值的对象称为迭代器。
- 迭代器与列表比较,迭代器是惰性计算,省内存。
- 不如 list索引 取值灵活,不可逆序。
迭代器的特点:访问者不需要关心迭代器内部的结构,仅需通过next()方法不断去取下一个内容,不能随机访问集合中的某个值,只能从头到尾依次访 问,访问到一半不能往后退,便于循环比较大的数据集合,节省内存
迭代器有两种类型:
1.集合数据类型:列表,字典,元组,集合,字符串
2.generator:包括生成器和带有yield的生成函数
- 生成器(yield)
包含 yield 的函数。
yield 与 return 相比,能 多次 返回 值。
定义生成器的方式:
(1)列表生成式的[]改为()
使用for循环进行调用即可
(2)定义yield关键字
如果一个函数定义中包含yield关键字,则这个函数为一个生成器
注意:yield的原理是,在每次进行迭代调用next()时执行,遇到yield语句返回,下次执行时从上次返回的yield语句处继续执行。
- Python的装饰器是一个以函数作为参数并返回一个替换函数的可执行函数。它其实是一种闭包的应用
- Python的迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束
- 在python中,使用了yield 的函数被称为生成器(generator)
60、较为高级一点的面试题
61、后端开发
62、什么是闭包
“闭包”的本质就是函数的嵌套定义,即在函数内部再定义函数
“闭包”有两种不同的方式,第一种是在函数内部就“直接调用了”;第二种是“返回一个函数名称”。
二、数据库
1、MYSQL或SQL SERVER中inner join和left join的区别
MYSQL inner join(等值连接)获取两个表中字段匹配关系的记录
MYSQL left join 会读取左边数据表的全部数据,即便右边表无对应数据
MYSQL right join 会读取右边数据表的全部数据,即便左边边表无对应数据
当主表为大数据量时,使用left join 会比较慢,可考虑inner join ,它在执行的时候会选择最小的表做基础表,效率高
2、MYSQL与Redis的区别
MYSQL:关系型数据库,数据存储于磁盘,检索时有IO操作,访问速度较慢
Redis:非关系型数据库(缓存数据库),数据存于内存中,访问速度快,可用于存储使用频繁的数据
3、常见数据库引擎
- InnoDB
支持事务处理,支持外键,支持崩溃修复能力和并发控制。如果需要对事务的完整性要求比较高(比如银行),要求实现并发控制(比如售票),那选择InnoDB有很大的优势。如果需要频繁的更新、删除操作的数据库,也可以选择InnoDB,因为支持事务的提交(commit)和回滚(rollback)
- MyISAM
插入数据快,空间和内存使用比较低。如果表主要是用于插入新记录和读出记录,那么选择MyISAM能实现处理高效率。如果应用的完整性、并发性要求比 较低,也可以使用。
- Memory
所有的数据都在内存中,数据的处理速度快,但是安全性不高。如果需要很快的读写速度,对数据的安全性要求较低,可以选择MEMOEY。它对表的大小有要求,不能建立太大的表。所以,这类数据库只使用在相对较小的数据库表
4、什么是SQL注入及解决办法
所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令
sql注入是一种将sql代码添加到输入参数中,传递到sql服务器解析并执行的一种攻击手法,
所以sql注入攻击就是输入参数未经过滤,直接拼接到sql语句中,解析执行,达到预想之外的行为。
解决:
- 严格检查输入变量的类型和格式:对数字类型的参数id的强校验;对字符串类型的参数的校验 (正则校验)
- 过滤和转义特殊字符
- 利用预编译机制(mysqli 和 pdo)
5、InnoDB与MyISAM的区别
- InnoDB 支持事务,MyISAM 不支持,这一点是非常之重要。事务是一种高
级的处理方式,如在一些列增删改中只要哪个出错还可以回滚还原,而 MyISAM
就不可以了; - MyISAM 适合查询以及插入为主的应用,InnoDB 适合频繁修改以及涉及到
安全性较高的应用; - InnoDB 支持外键,MyISAM 不支持;
- 对于自增长的字段,InnoDB 中必须包含只有该字段的索引,但是在 MyISAM
表中可以和其他字段一起建立联合索引; - 清空整个表时,InnoDB 是一行一行的删除,效率非常慢。MyISAM 则会重
建表;
6、数据表student有id,name,score,city字段,其中name中的名字可有重复,需要消除重复行,请写sql语句
select distinct name from student
7、数据库优化查询方法
外键、索引、联合查询、选择特定字段等等
8、存储过程和函数的区别
存储过程是用户定义的一系列sql语句的集合,涉及特定表或其它对象的任务,用户可以调用存储过程,而函数通常是数据库已定义的方法,它接收参数并返回某种类型的值并且不涉及特定用户表。
另外,存储过程和函数还有以下几个区别:
- 存储过程一般是作为一个独立的部分来执行的,而函数可以作为查询语句的一个部分来调用。由于函数可以返回一个对象,因此它可以在查询语句中位于From关键字的后面。
- 一般而言,存储过程实现的功能较为复杂,而函数实现的功能针对性较强。
- 函数需要用括号包住输入的参数,且只能返回一个值或表对象,而存储过程可以返回多个参数。
- 函数可以嵌入在SQL中使用,可以在SELECT中调用,存储过程不行。
- 函数不能直接操作实体表,只能操作内建表。
- 存储过程在创建时即在服务器上进行了编译,其执行速度比函数快
9、事务是什么?
事务是作为一个逻辑单元执行的一系列操作,一个逻辑工作单元必须有四个属性,称为 ACID(原子性、一致性、隔离性和持久性)属性,只有这样才能成为一个事务:
- 原子性 事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。
- 一致性 事务在完成时,必须使所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。事务结束时,所有的内部数据结构(如 B树索引或双向链表)都必须是正确的。
- 隔离性 由并发事务所作的修改必须与任何其它并发事务所作的修改隔离。事务查看数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。这称为可串行性,因为它能够重新装载起始数据,并且重播一系列事务,以使数据结束时的状态与原始事务执行的状态相同
- 持久性 事务完成之后,它对于系统的影响是永久性的。该修改即使出现系统故障也将一直保持。
10、 游标的作用?如何知道游标已经到了最后?
游标用于定位结果集的行,通过判断全局变量@@FETCH_STATUS可以判断是否到了最后,通常此变量不等于0表示出错或到了最后。
(关系数据库中的操作会对整个行集起作用。由 SELECT 语句返回的行集包括满足该语句的 WHERE 子句中条件的所有行。这种由语句返回的完整行集称为结果集。应用程序,特别是交互式联机应用程序,并不总能将整个结果集作为一个单元来有效地处理。这些应用程序需要一种机制以便每次处理一行或一部分行。游标就是提供这种机制的对结果集的一种扩展。
游标的特点是:
- 允许定位在结果集的特定行。
- 从结果集的当前位置检索一行或一部分行。
- 支持对结果集中当前位置的行进行数据修改。
- 为由其他用户对显示在结果集中的数据库数据所做的更改提供不同级别的可见性支持。
- 提供脚本、存储过程和触发器中用于访问结果集中的数据的 Transact-SQL 语句
- 在从游标中提取信息后,可以通过判断@@FETCH_STATUS 的值来判断是否到了最后。当@@FETCH_STATUS为0的时候,说明提取是成功的,否则就可以认为到了最后。)
11、 触发器分为事前触发和事后触发,这两种触发有和区别。语句级触发和行级触发有何区别
事前触发器运行于触发事件发生之前,而事后触发器运行于触发事件发生之后。通常事前触发器可以获取事件之前和新的字段值。
语句级触发器可以在语句执行前或后执行,而行级触发在触发器所影响的每一行触发一次。
12、Mysql面试知识点总结(基础篇)
13、mysql数据库基础知识总结
14、MySQL基础知识
三、计算机网络
1、列举网络中的四层或七层协议模型
- TCP/IP四层协议模型:网络接口层 网络层 传输层 应用层
- OSI七层:物理层 数据链路层 网络层 传输层 会话层 表示层 应用层
2、常见的网络传输协议
UDP、TCP、FTP、HTTP、SMTP等等
3、
四、爬虫
1、列举网络爬虫所用到的网络数据包,解析包
- 网络数据包: urllib、urllib2、requests
- 解析包: re、xpath、beautiful soup、lxml
五、WEB框架--Django/SSH/Flask
1、Http请求中GET请求和POST请求的区别
- GET在回退时无害,POST会再次提交一次请求
- GET只有url编码,而POST支持多种编码
- GET请求的参数会显示在url中,而POST放在了request body中,无法直接看见,所以POST的安全性比GET好
2、WEB项目的性能优化(从前端、后端、数据库方面解析)
- 前端优化:减少http的请求;html与css的代码放在JavaScript代码的前面
- 后端优化:缓存高优先级以及变化少的数据;异步方式处理耗时操作;代码优化
- 数据库:可考虑存储在redis数据库;简历索引,外键等
3、常见网络状态码
- 200 OK 请求正常处理完毕
- 400 Bad Request 请求报文语法错误或参数错误
- 403 Forbidden 请求资源被拒绝
- 404 NOT FOUND 无法找到请求资源(服务器无理由拒绝)
- 500 Intent Server Error 服务器故障或Web应用故障
- 503 Service Unavailable 服务器超负载或停机维护
4、同源策略
- 协议相同
- 域名相同
- 端口相同
- http:www.test.com与https:www.test.com 不同源——协议不同
- http:www.test.com与http:www.admin.com 不同源——域名不同
- http:www.test.com与http:www.test.com:8081 不同源——端口不同
只要不满足其中任意一个要求,就不符合同源策略,就会出现“跨域”
5、简述Django的orm
ORM(Object-Relation Mapping)意为对象-关系映射
MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库
- 根据对象的类型生成表结构
- 将对象、列表的操作,转换为sql语句
- 将sql查询到的结果转换为对象、列表
ORM操作
# 增
models.UserInfo.object.create(name=new_name)
# 删
models.UserInfo.object.get(id=xxx,None)
models.delete()
# 改
obj = models.UserInfo.object.get(id=xx,None)
obj = new_xxx
obj.save()
# 查
querylist=models.Entry.objects.all()
print([e.title for e in querylist])
print([e.title for e in querylist])
entry = models.Entry.objects.get(id=?)
6、简述cookie和session的区别
1,session 在服务器端,cookie 在客户端(浏览器)
2、session 的运行依赖 session id,而 session id 是存在 cookie 中的,也就是说,如果浏览器禁用了 cookie ,同时 session 也会失效,存储Session时,键与Cookie中的sessionid相同,值是开发人员设置的键值对信息,进行了base64编码,过期时间由开发人员设置
3、cookie安全性比session差
7、requests
包新建一个 session
再 get
和普通的 requests.get
有什么区别
维持一个会话,** 建立一个tcp长连接** ,cookie 自动保存,下次请求还是一个会话
8、Flask 的 Route 是怎么实现的? 你认为 Flask 框架有什么优缺点?
- 实际上在 Flask 类里面,route 可以简单理解为不过是把对应的路由规则作为键,装饰的视图函数作为值,存到 werkzeug.routing.Map 对象(可以看成是和字典类似的数据结构)里。这里是 源码,好理解些。这是之前写的一篇 笔记
- Flask 优点是轻量,灵活,可高度定制,插件化。缺点也是过于轻量,功能必须通过第三方插件实现,插件质量参差不齐,也不能完全保证后期维护
9、Django 的认识
10、SpringMVC常见面试题总结
六、Linux
1、10个Linux常用命令
ls pwd cd touch rm mkdir tree cp mv cat more grep echo
2、python删除文件和用linux命令删除文件方法
python:os.remove(文件名)
linux: rm 文件名
3、Linux命令重定向 > 和 >>
Linux 允许将命令执行结果 重定向到一个 文件
将本应显示在终端上的内容 输出/追加 到指定文件中
- > 表示输出,会覆盖文件原有的内容
- >> 表示追加,会将内容追加到已有文件的末尾
4、linux自启动的几种方式
5、Linux设置程序开机自启动
七、数据结构
1、中间部分包含了数据结构和算法
2、代码面试需要知道的8种数据结构