1、python中is和==的区别
Python中对象包含的三个基本要素,分别是:id(身份标识) 、type(数据类型)和value(值)。
‘==’比较的是value值 值是否相等
‘is’比较的是id 是否为同一个对象
2、简述read、readline、readlines的区别
read([size])方法从文件当前位置起读取size个字节,若无参数size,则表示读 取至文件结束为止,它范围为字符串对象
Readline()从字面意思可以看出,该方法每次读出一行内容,所以,读取时占 用内存小,比较适合大文件,该方法返回一个字符串对象。
readlines()方法读取整个文件所有行,保存在一个列表(list)变量中,每行作为一个元素,但读取大文件会比较占内存
3、*args,**kwargs的作用是分别什么?
*args和**kwargs通常使用在函数定义里,*args允许函数传入不定量个数的非关键字参数,**kwargs允许函数传入不定量个数的关键字参数
4、描述yield作用。
保存当前运行状态(断点),然后暂停执行,即将函数挂起
将yeild关键字后面表达式的值作为返回值返回,此时可以理解为起到了return的作用,当使用next()、inte()函数让函数从断点处继续执行,即唤醒函数
5、什么是装饰器。
装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。
6、python是怎么进行内存管理的?
引用计数:python内部使用引用计数,来保持追踪内存中的对象,Python内部记录了对象有多少个引用,即引用计数,当对象被创建时就创建了一个引用计数,当对象不再需要时,这个对象的引用计数为0时,它被垃圾回收。
7、python中如何拷贝一个对象?(赋值,浅拷贝,深拷贝的区别)
赋值(=),就是创建了对象的一个新的引用,修改其中任意一个变量都会影响到另一个。
浅拷贝:创建一个新的对象,但它包含的是对原始对象中包含项的引用(如果用引用的方式修改其中一个对象,另外一个也会修改改变){1,完全切片方法;2,工厂函数,如list();3,copy模块的copy()函数}
深拷贝:创建一个新的对象,并且递归的复制它所包含的对象(修改其中一个,另外一个不会改变){copy模块的deep.deepcopy()函数}
8、索引和切片
索引:取出数组s中第3个元素:x=s[2]
切片:s[参数1:参数2:参数3] 参数1 起始位置 参数2 终止位置 参数3 步长
9、pyhon 常用内建函数
1、 abs() 函数返回数字的绝对值。
2、 all() 函数用于判断给定的可迭代参数 iterable 中的所有元素是否都为 TRUE,如果是返回 True,否则返回 False。
3、 Ord(“a”) 返回字符串对应的十进制整数。
4、 chr(i) 返回十进制数对应的字符(0~255)
5、 bin(x)将整数转换为二进制字符串
6、 Max(1,2,3) 返回最大值
7、 Min(1,2,3) 返回最小值
10、python内建数据类型有哪些
整型--int 布尔型--bool 字符串--str 列表--list 元组--tuple 字典--dict
11、5个Linux常用命令
ls pwd cd touch rm mkdir tree cp mv cat grep
12、python2和python3区别?列举5个
1、Python3 使用 print 必须要以小括号包裹打印内容,比如 print('hi')
Python2 既可以使用带小括号的方式,也可以使用一个空格来分隔打印内 容,比如 print 'hi'
2、python2 range(1,10)返回列表,python3 range() 函数返回的是一个可迭代对象(类型是对象),而不是列表类型, 所以打印的时候不会打印列表。
3、python2中使用ascii编码,python中使用utf-8编码
4、python2中unicode表示字符串序列,str表示字节序列
python3中str表示字符串序列,byte表示字节序列
5、python2中为正常显示中文,引入coding声明,python3中不需要
6、python2中是raw_input()函数,python3中是input()函数
13、列出5个python标准库
os:提供了不少与操作系统相关联的函数
sys: 通常用于命令行参数
re: 正则匹配
math: 数学运算
datetime:处理日期时间
14、什么是lambda函数?它有什么好处?
lambda表达式,通常是在需要一个函数,但是又不想费神去命名一个函数 的场合下使用,也就是指匿名函数。
Python允许你定义一种单行的小函数。定义lambda函数的形式如下(lambda参数:表达式)lambda函数默认返回表达式的值。你也可以将其赋值 给一个变量。lambda函数可以接受任意个参数,包括可选参数,但是表达 式只有一个。
15、 运算符优先级
运算符 |
描述 |
** |
指数 (最高优先级) |
~ + - |
按位翻转, 一元加号和减号 (最后两个的方法名为 +@ 和 -@) |
* / % // |
乘,除,取模和取整除 |
+ - |
加法减法 |
>> << |
右移,左移运算符 |
& |
位 'AND' |
^ | |
位运算符 |
<= < > >= |
比较运算符 |
<> == != |
等于运算符 |
= %= /= //= -= += *= **= |
赋值运算符 |
is is not |
身份运算符 |
in not in |
成员运算符 |
not and or |
逻辑运算符 |
****记不住用括号,括号优先级最高
16、什么是PEP8?
PEP8是一个编程规范,内容是一些关于如何让你的程序更具可读性的建议。
17、.Python中的pass是什么?
Pass是一个在Python中不会被执行的语句。在复杂语句中,如果一个地方需要暂时被留白,它常常被用于占位符。
18、迭代器和生成器的区别
迭代器是一个更加抽象的概念,任何对象,如果它的类有next方法和iter 方法返回自身。对于string、list、dict、tuple等这类容器对象,使用for循环遍历是很方便的。在后台for语句对容器对象调用iter()函数,iter()是Python的内置函数。iter()会返回一个定义了next()方法的迭代器对象,它在 容器中逐个访问 容器内元素,next()也是python的内置函数。在没有后续元素时,next()会抛出 一个StopIterration的异常。
生成器(Generator)是创建迭代器的简单而强大的工具。它们写起来就 像是正规的函数,只是在返回数据的时候需要使用yield语句。每次next() 被调用时,生成器会返回它脱离的位置(它记忆语句最后一次执行的位置和 所有的数据值)
19、Python里面如何生成随机数?
random模块
随机整数:random.randint(a,b):返回随机整数x,a<=x<=b
random.randrange(start,stop,[,step]):返回一个范围在(start,stop,step) 之间的随机整数,不包括结束值。
随机实数:random.random( ):返回0到1之间的浮点数
random.uniform(a,b):返回指定范围内的浮点数。
20、单引号,双引号,三引号的区别
单引号和双引号是等效的,如果要换行,需要符号(\),三引号则可以直接换行,并且可以包含注释
21、 面向对象中super的作用?
在子类派生出新的方法中重用父类的功能
22、 列举面向对象中特殊成员(带双下划线的特殊方法,如:__init__、等)
# __init__ 负责将类的实例化
# __str__ print打印一个对象时触发
# __repr__ print打印一个对象时而且该实例没有实现__str__触发
# __setattr__ 添加/修改属性会触发它的执行
#__delattr__ 删除属性的时候会触发
# __delete__ 采用del删除属性时,触发
23、 静态方法和类方法区别?
1. 静态方法:相当于不同函数,通过类直接调用,不需要创建对象们不会隐式传递 staticmethod
使用场景
不需要访问实例属性,比如我想定义一个关于时间操作的类,其中有一个获取当前时间的函数。
2. 类方法: 通过类调用,第一个参数默认是类本身 classmethod
使用场景
一般是需要去访问写死的变量,才会用到类方法装饰器
24、通过字符串来操作类与对象的属性,这种操作称为反射
hasattr(obj,某种属性)
测对象自己中是否有指定的函数属性与数据属性,有返回True
setattr(obj,某种属性,属性对应的值)
在对象自己中新增或修改对象中的函数与数据属性
delattr(obj,某种属性,属性对应的值)
#删除对象自己中的属性
getattr(object,某种属性(字符串),[default])
返回对象自己中数据属性的值,与函数属性的内存地址,没有则报错。如果写了默认值没有时则返回默认值
第一阶段面试题
一、Python基础
1. continue和 break有什么区别?
答案:
break和continue都是用来控制循环结构的。
- break:提前终止循环可以使用break来完成。break完全结束一个循环,跳出循环体执行循环后面的语句。
- continue:理解为continue是跳过当次循环中剩下的语句,执行下一次循环。
- 区别:continue只终止本次循环,break则完全终止循环
2.Python 中的作用域?
答案:
Python 中,一个变量的作用域总是由在代码中被赋值的地方所决定的。
当 Python 遇到一个变量的话他会按照这样的顺序进行搜索:
本地作用域(Local)→当前作用域被嵌入的本地作用域(Enclosing locals)
→全局/模块作用域(Global)→内置作用域(Built-in)
- 谈谈对闭包的理解?
答案:
闭包(closure)是函数式编程的重要的语法结构。闭包也是一种组织代码的结构,
它同样提高了代码的可重复使用性。
当一个内嵌函数引用其外部作作用域的变量,我们就会得到一个闭包. 总结一下,
创建一个闭包必须满足以下几点:
必须有一个内嵌函数
内嵌函数必须引用外部函数中的变量
外部函数的返回值必须是内嵌函数
感觉闭包还是有难度的,几句话是说不明白的,还是查查相关资料.
重点是函数运行后并不会被撤销,就像16题的instance字典一样,当函数运行完
后,instance 并不被销毁,而是继续留在内存空间里.这个功能类似类里的类变
量,只不过迁移到了函数上.
闭包就像个空心球一样,你知道外面和里面,但你不知道中间是什么样.
- Python 里的拷贝?理解引用和 copy(),deepcopy()的区别。
答案:
import copy
a = [1, 2, 3, 4, ['a', 'b']] #原始对象
b = a #赋值,传对象的引用
c = copy.copy(a) #对象拷贝,浅拷贝
d = copy.deepcopy(a) #对象拷贝,深拷贝
a.append(5) #修改对象 a
a[4].append('c') #修改对象 a 中的['a', 'b']数组对象
print 'a = ', a
print 'b = ', b
print 'c = ', c
print 'd = ', d
输出结果:
a = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
b = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
c = [1, 2, 3, 4, ['a', 'b', 'c']]
d = [1, 2, 3, 4, ['a', 'b']]
- Python 垃圾回收机制?
答案:
Python GC 主要使用引用计数(reference counting)来跟踪和回收垃圾。在引
用计数的基础上,通过“标记-清除”(mark and sweep)解决容器对象可能产
生的循环引用问题,通过“分代回收”(generation collection)以空间换时
间的方法提高垃圾回
6.什么是 lambda 函数?它有什么好处?
答案:
lambda 表达式,通常是在需要一个函数,但是又不想费神去命名一个函数
的场合下使用,也就是指匿名函数
lambda 函数:首要用途是指点短小的回调函数
lambda [arguments]:expression
>>> a=lambdax,y:x+y
>>> a(3,11)
7.请写出一段 Python 代码实现删除一个list 里面的重复元素?
答案:
1. 使用 set 函数,set(list)
2. 使用字典函数,
>>>a=[1,2,4,2,4,5,6,5,7,8,9,0]
>>> b={}
>>>b=b.fromkeys(a)
>>>c=list(b.keys())
>>> c
8.Python 里面如何拷贝一个对象?(赋值,浅拷贝,深拷贝的区别)
答案:
赋值(=),就是创建了对象的一个新的引用,修改其中任意一个变量都会影响到另一个。
浅拷贝:创建一个新的对象,但它包含的是对原始对象中包含项的引用(如果用
引用的方式修改其中一个对象,另外一个也会修改改变){1,完全切片方法;2,
工厂函数,如 list();3,copy 模块的 copy()函数}
深拷贝:创建一个新的对象,并且递归的复制它所包含的对象(修改其中一个,
另外一个不会改变){copy 模块的 deep.deepcopy()函数}
9.介绍一下 except 的用法和作用?
答案:
try…except…except…[else…][finally…]
执行 try 下的语句,如果引发异常,则执行过程会跳到 except 语句。对每个except 分支顺序尝试执行,如果引发的异常与 except 中的异常组匹配,执行相应的语句。
如果所有的 except 都不匹配,则异常会传递到下一个调用本代码的最高层 try代码中。
try 下的语句正常执行,则执行 else 块代码。如果发生异常,就不会执行
如果存在 finally 语句,最后总是会执行。
10.如何用 Python 来进行查询和替换一个文本字符串?
答案:
可以使用 re 模块中的 sub()函数或者 subn()函数来进行查询和替换,
格式:sub(replacement, string[,count=0])(replacement 是被替换成的文本,
string 是需要被替换的文本,count 是一个可选参数,指最大被替换的数量)
>>> import re
>>>p=re.compile(‘blue|white|red’)
>>>print(p.sub(‘colour’,'blue socks and red shoes’))
colour socks and colourshoes
>>>print(p.sub(‘colour’,'blue socks and red shoes’,count=1))
colour socks and redshoes
subn()方法执行的效果跟 sub()一样,不过它会返回一个二维数组,包括替换后
的新的字符串和总共替换的数量
11.Python 里面 match()和 search()的区别?
答案:
re 模块中 match(pattern,string[,flags]),检查 string 的开头是否与pattern 匹配。
re 模块中 re.search(pattern,string[,flags]),在 string 搜索 pattern 的第一个匹配值。
>>>print(re.match(‘super’, ‘superstition’).span())
(0, 5)
>>>print(re.match(‘super’, ‘insuperable’))
None
>>>print(re.search(‘super’, ‘superstition’).span())
(0, 5)
>>>print(re.search(‘super’, ‘insuperable’).span())
(2, 7)
- Python 里面如何生成随机数?
答案:
random 模块
随机整数:random.randint(a,b):返回随机整数 x,a<=x<=b
random.randrange(start,stop,[,step]):返回一个范围在(start,stop,step)
之间的随机整数,不包括结束值。
随机实数:random.random( ):返回 0 到 1 之间的浮点数
random.uniform(a,b):返回指定范围内的浮点数
- 如何在一个 function 里面设置一个全局的变量?
答案:
解决方法是在 function 的开始插入一个 global 声明:
def f():
global x
- 单引号,双引号,三引号的区别?
答案:
单引号和双引号是等效的,如果要换行,需要符号(\),三引号则可以直接换
行,并且可以包含注释
如果要表示 Let’s go 这个字符串
单引号:s4 = ‘Let\’s go’
双引号:s5 = “Let’s go”
s6 = ‘I realy like“python”!’
这就是单引号和双引号都可以表示字符串的原因
15.Python2 和 3 的区别?
答案:
print 不再是语句,而是函数,比如原来是 print 'abc' 现在是 print('abc')
但是 python2.6+ 可以使用 from __future__ import print_function 来实现相同功能
在 Python 3 中,没有旧式类,只有新式类,也就是说不用再像这样 class
Foobar(object): pass 显式地子类化 object
但是最好还是加上. 主要区别在于 old-style 是 classtype 类型而 new-style 是type 类型
原来 1/2(两个整数相除)结果是 0,现在是 0.5 了
python 2.2+ 以上都可以使用 from __future__ import division 实现改特性, 同时注
意 // 取代了之前的 / 运算
新的字符串格式化方法 format 取代%
错误, 从 python2.6+ 开始已经在 str 和 unicode 中有该方法, 同时 python3 依然支持 % 算符
xrange 重命名为 range
同时更改的还有一系列内置函数及方法, 都返回迭代器对象, 而不是列表或者
元组, 比如 filter, map, dict.items 等
!=取代 < >
python2 也很少有人用 < > 所以不算什么修改
long 重命名为 int
不完全对, python3 彻底废弃了 long+int 双整数实现的方法, 统一为 int , 支持高精度整数运算.
except Exception, e 变成 except (Exception) as e
只有 python2.5 及以下版本不支持该语法. python2.6 是支持的. 不算新东西
exec 变成函数
类似 print() 的变化, 之前是语句.
16.下面代码会输出什么:
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]
17.这两个参数是什么意思:*args,**kwargs?我们为什么要使用它们?
答案:
如果我们不确定要往函数中传入多少个参数,或者我们想往函数中以列表和元组
的形式传参数时,那就使要用*args;
如果我们不知道要往函数中传入多少个关键词参数,或者想传入字典的值作为关
键词参数时,那就要使用**kwargs。
args和kwargs这两个标识符是约定俗成的用法,你当然还可以用*bob和**billy,
但是这样就并不太妥。
下面是具体的示例:
def f(*args,**kwargs): print args, kwargs
l = [1,2,3]
t = (4,5,6)
d = {'a':7,'b':8,'c':9}
f()
f(1,2,3) # (1, 2, 3) {}
f(1,2,3,"groovy") # (1, 2, 3, 'groovy') {}
f(a=1,b=2,c=3) # () {'a': 1, 'c': 3, 'b': 2}
f(a=1,b=2,c=3,zzz="hi") # () {'a': 1, 'c': 3, 'b': 2, 'zzz': 'hi'}
f(1,2,3,a=1,b=2,c=3) # (1, 2, 3) {'a': 1, 'c': 3, 'b': 2}
f(*l,**d) # (1, 2, 3) {'a': 7, 'c': 9, 'b': 8}
f(*t,**d) # (4, 5, 6) {'a': 7, 'c': 9, 'b': 8}
f(1,2,*t) # (1, 2, 4, 5, 6) {}
f(q="winning",**d) # () {'a': 7, 'q': 'winning', 'c': 9, 'b': 8}
f(1,2,*t,q="winning",**d) # (1, 2, 4, 5, 6) {'a': 7, 'q': 'winning', 'c': 9, 'b': 8}
def f2(arg1,arg2,*args,**kwargs): print arg1,arg2, args, kwargs
f2(1,2,3) # 1 2 (3,) {}
f2(1,2,3,"groovy") # 1 2 (3, 'groovy') {}
f2(arg1=1,arg2=2,c=3) # 1 2 () {'c': 3}
f2(arg1=1,arg2=2,c=3,zzz="hi") # 1 2 () {'c': 3, 'zzz': 'hi'}
f2(1,2,3,a=1,b=2,c=3) # 1 2 (3,) {'a': 1, 'c': 3, 'b': 2}
f2(*l,**d) # 1 2 (3,) {'a': 7, 'c': 9, 'b': 8}
f2(*t,**d) # 4 5 (6,) {'a': 7, 'c': 9, 'b': 8}
f2(1,2,*t) # 1 2 (4, 5, 6) {}
f2(1,1,q="winning",**d) # 1 1 () {'a': 7, 'q': 'winning', 'c': 9, 'b': 8}
f2(1,2,*t,q="winning",**d) # 1 2 (4, 5, 6) {'a': 7, 'q': 'winning', 'c': 9, 'b': 8}
19.简要描述 Python 的垃圾回收机制(garbage collection)。
答案:
Python 在内存中存储了每个对象的引用计数(reference count)。如果计数值变成 0,那么相应的对象就会小时,分配给该对象的内存就会释放出来用作他用。偶尔也会出现引用循环(reference cycle)。垃圾回收器会定时寻找这个循环,并将其回收。举个例子,假设有两个对象 o1 和 o2,而且符合 o1.x == o2 和 o2.x == o1 这两个条件。如果 o1 和 o2 没有其他代码引用,那么它们就不应该继续存在。但它们的引用计数都是 1。
Python 中使用了某些启发式算法(heuristics)来加速垃圾回收。例如,越晚创建的对象更有可能被回收。对象被创建之后,垃圾回收器会分配它们所属的代(generation)。每个对象都会被分配一个代,而被分配更年轻代的对象是优先被处理的
20.简述函数式编程
答案:
在函数式编程中,函数是基本单位,变量只是一个名称,而不是一个存储单元。
除了匿名函数外,Python 还使用 fliter(),map(),reduce(),apply()函数来支持函数式编程。
21.什么是匿名函数,匿名函数有什么局限性?
答案:
匿名函数,也就是 lambda 函数,通常用在函数体比较简单的函数上。匿名函数
顾名思义就是函数没有名字,因此不用担心函数名冲突。不过 Python 对匿名函
数的支持有限,只有一些简单的情况下可以使用匿名函数。
22.如何捕获异常,常用的异常机制有哪些?
答案:
如果我们没有对异常进行任何预防,那么在程序执行的过程中发生异常,就会中断程序,调用 python 默认的异常处理器,并在终端输出异常信息。try...except...finally 语句:当 try 语句执行时发生异常,回到 try 语句层,寻找后面是否有 except 语句。找到 except 语句后,会调用这个自定义的异常处理器。except 将异常处理完毕后,程序继续往下执行。finally 语句表示,无论异常发生与否,finally 中的语句都要执行。
assert 语句:判断 assert 后面紧跟的语句是 True 还是 False,如果是 True 则继续执行 print,如果是 False 则中断程序,调用默认的异常处理器,同时输出assert 语句逗号后面的提示信息。
with 语句:如果 with 语句或语句块中发生异常,会调用默认的异常处理器处理,但文件还是会正常关闭。
23.去除列表中的重复元素?
答案:
#用集合
list(set(l))
#用字典
l1 = ['b','c','d','b','c','a','a']
l2 = {}.fromkeys(l1).keys()
print l2
1
2
3
l1 = ['b','c','d','b','c','a','a']
l2 = {}.fromkeys(l1).keys()
print l2
#用字典并保持顺序
l1 = ['b','c','d','b','c','a','a']
l2 = list(set(l1))
l2.sort(key=l1.index)
print l2
#列表推导式
l1 = ['b','c','d','b','c','a','a']
l2 = []
[l2.append(i) for i in l1 if not i in l2]
24.变态台阶问题
一只青蛙一次可以跳上 1 级台阶,也可以跳上 2 级……它也可以跳上 n 级。求该青蛙跳上一个 n 级的台阶总共有多少种跳法
答案:
第一种方法:台阶问题/斐波纳挈
fib = lambda n: n if n <= 2 else fib(n - 1) + fib(n - 2)
第二种记忆方法
def memo(func):
cache = {}
def wrap(*args):
if args not in cache:
cache[args] = func(*args)
return cache[args]
return wrap
@ memo
def fib(i):
if i < 2:
return 1
return fib(i-1) + fib(i-2)
第三种方法
def fib(n):
a, b = 0, 1
for _ in xrange(n):
a, b = b, a + b
return b
25.Python中list和tuples的差别是什么?
答案:
列表里的内容是可以改变的,增删改都可以,tuple则不行;
python中字典的key必须是可哈希的,不可变的所以tuple可以作为字典的键,而list不行;
对于使用场景tuple适合一些只读的数据,如python链接mysql得到的结果就是用tuple,而list则在列表长度不固定或者需要有变动的数据中使用tuple的性能比list好一些,tuple比list更省内存
26.代码举例什么是decorator。
答案:
decorator是一个装饰器函数,作用是用来包装另一个函数。
装饰器函数出入的是一个函数返回的也是一个函数。
def fn(fc):
def f():
print('<a>'+fc()+'</a>')
return f
@fn
def f2():
return '我是一个超链接'
f2() #<a>我是一个超链接</a>
27.单引号,双引号,三引号的区别
答案:
单引号和双引号是等效的,如果要换行,需要符号(\),三引号则可以直接换行,并且可 以包含注释
如果要表示Let’s go 这个字符串
单引号:s4 = ‘Let\’s go’
双引号:s5 = “Let’s go”
s6 = ‘I realylike“python”!’
这就是单引号和双引号都可以表示字符串的原因了
28.请用自己的算法,按升序合并如下两个List , 并去除重复的元素
List1 = [2,3,8,4,9,5,6]
List2 = [5,6,10,17,11,2]
答案:
29.有一个多层嵌套的列表 A = [1,2,[3,4,[‘434’,[…]]]],请写一段代码遍历A中的美个元素并打印出来.
答案:
30.用自己的话说明迭代器和生成器,它们之间的关系?
答案:
迭代器:指的是一个重复的过程,每一次重复称为一次迭代,并且每一次重复的结果是下一次重复的初始值
生成器:只要在函数体内出现yield关键字,那么再执行函数就不会执行函数代码,会得到一个结果,该结果就是生成器
31.Python是如何进行内存管理的?
答案:
python内部使用引用计数,来保持追踪内存中的对象,Python内部记录了对象有多少个引用,即引用计数,当对象被创建时就创建了一个引用计数,当对象不再需要时,
这个对象的引用计数为0时,它被垃圾回收。
32.字符串格式化:% 和 format的区别
答案:
符串的format函数非常灵活,很强大,可以接受的参数不限个数,并且位置可以不按顺序,而且有较为强大的格式限定符(比如:填充,对齐,精度等)
二、OOP
1.新式类和旧式类的区别,如何确保使用的类是新式类?
答案:
为了统一类(class)和类型(type),python 在 2.2 版本引进来新式类。在 2.1 版
本中,类和类型是不同的。
为了确保使用的是新式类,有以下方法:
放在类模块代码的最前面 __metaclass__ = type
从内建类 object 直接或者间接地继承
在 python3 版本中,默认所有的类都是新式类。
- 举例说明Python中的继承类型.
答案:
python中的继承包括单继承和多继承。在单继承中子类无__init__时,会直接继承父类的__init__,多继承时,子类无__init__则从父类列表中逐个判断,是否有__init__直到有时则继承。
class A:
pass
class B:
pass
单继承:
class C(A):
pass
多继承:
class D(A,B):
Pass
- 谈一下类方法、实例方法和静态方法的区别?
答案:
1. 类方法只能访问'类变量'的方法
2. 类方法需要使用@classmethod装饰器定义
3. 类方法的第一个参数是类实例,约定写为cls
说明:
类(实例)和对象(实例)都可以调用类方法
类方法不能访问实例变量
静态方法:@staticmethod
静态方法是普通函数,
静态方法定义在类的内部,只能凭借该类或实例调用
静态方法需要使用@staticmethod装饰器定义
静态方法写普通函数定义相同,不需要传入self和cls 参数
说明:
类和实例都可以调用静态方法
静态方法不能访问类变量和实例变量
- 请阐述__new__ 和 __init__ 的区别?
答案:
1、__new__是一个静态方法,而__init__是一个实例方法.
2、__new__方法会返回一个创建的实例,而__init__什么都不返回.
3、只有在__new__返回一个cls的实例时后面的__init__才能被调用.
4、当创建一个新实例时调用__new__,初始化一个实例时用__init__.
第二阶段面试题
一、网络编程
1. OSI七层模型及其作用?
答案:
应用层:提供用户服务,具体功能由特定的程序而定
表示层:数据的压缩优化,加密
会话层:建立应用级的连接,选择传输服务
传输层:提供不同的传输服务.流量控制
网络层:路由选择,网络互连
链路层:进行数据交换,具体消息的发送,链路连接
物理层:物理硬件,借口设定,网卡路由交换机等
2. 简述一下三次握手四次挥手的过程?
答案:
三次握手:tcp传输在数据传输前建立连接的过程
1 客户端向服务器发送连接请求
2 服务器收到请求后,回复确认消息,表示允许连接
3 客户端收到服务器恢复,进行最终标志发送确认连接
四次挥手:tcp传输在连接断开前进行断开确认的过程
1 主动方发动报文告知被动方要断开连接
2 被动方收到请求后立即返回报文告知已经准备断开
3 被动方准备就绪后再次发送报文告知可以断开
4 主动方发送消息,确认最终断开
3. TCP和UDP的区别?
答案:
1、基于连接与无连接
2、TCP要求系统资源较多,UDP较少;
3、流模式(TCP)与数据报模式(UDP);
4、TCP保证数据正确性,UDP可能丢包
5、TCP保证数据顺序,UDP不保证
4. 什么是水平触发?什么是边缘触发?
答案:
水平触发:如果文件描述符已经就绪可以非阻塞的执行IO操作了,此时会触发通知.允许在任意时刻重复检测IO的状态.select,poll就属于水平触发.
边缘触发:如果文件描述符自上次状态改变后有新的IO活动到来,此时会触发通知.在收到一个IO事件通知后要尽可能多的执行IO操作,因为如果在一次通知中没有执行完IO那么就需要等到下一次新的IO活动到来才能获取到就绪的描述符.
5. 创建TCP连接的流程?
答案:
服务器端:1)创建套接字create;2)绑定端口号bind;3)监听连接listen;4)接受连接请求accept,并返回新的套接字;5)用新返回的套接字recv/send;6)关闭套接字
客户端:1)创建套接字create; 2)发起建立连接请求connect; 3)发送/接收数据send/recv;4)关闭套接字
6. 创建UDP连接流程?
答案:
服务器端: 1)创建套接字create;2)绑定端口号bind;3)接收/发送消息recvfrom/sendto;4)关闭套接字。
客户端: 1)创建套接字create;2)发送/接收消息sendto/recvfrom;3)关闭套接字.
7. 什么是并发和并行?
答案:
并发是指一个处理器同时处理多个任务。
并行是指多个处理器或者是多核的处理器同时处理多个不同的任务。
并发是逻辑上的同时发生(simultaneous),而并行是物理上的同时发生。
8. 生产者与消费者模型的应用场景
答案:
生产者与消费者模式是通过一个容器来解决生产者与消费者的强耦合关系,生产者与消费者之间不直接进行通讯,而是利用阻塞队列来进行通讯,生产者生成数据后直接丢给阻塞队列,消费者需要数据则从阻塞队列获取,实际应用中,生产者与消费者模式则主要解决生产者与消费者生产与消费的速率不一致的问题,达到平衡生产者与消费者的处理能力,而阻塞队列则相当于缓冲区。
9. HTTP常见的几种提交方法?
答案:
GET、HEAD、POST、PUT、DELETE、TRACE、CONNECT
10. GET方法和POST请求的区别?
答案:
GET在浏览器回退时是无害的,而POST会再次提交请求。
GET产生的URL地址可以被加入到书签,而POST不可以。
GET请求会被浏览器主动cache,而POST不会,除非手动设置。
GET请求只能进行url编码,而POST支持多种编码方式。
GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
GET请求在URL中传送的参数是有长度限制的,而POST么有。
对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
GET参数通过URL传递,POST放在Request body中。
大多数浏览器通常都会限制url长度在2K个字节,而大多数服务器最多处理64K大小的url。
二、进程线程
1. 进程、线程、协程的区别是什么?
答案:
1. 进程:进程是资源分配的最小单位,程序运行时系统就会创建一个进程,并为他分配资源(独立的地址空间,建立数据表来维护代码段、堆栈段和数据段)。
2. 线程:程序执行时的最小单位,它是进程的一个执行流,线程是cpu调度的最小单元。
一个进程可以由很多个线程组成,线程间共享进程的所有资源,每个线程有自己的堆栈和局部变量
3. 协程 :又称为轻量级的线程 协程极高的执行效率(子程序切换不是线程切换),不需要多线程的锁机制,一个协程遇到IO操作自动切换到其它协程
2. 进程线程的各有什么优缺点?
答案:
进程:
缺点: 正是因为进程创建时都有自己的独立地址空间,所以创建进程和切换进程消耗资源比较多
优点: 进程间的通信是以ipc通信的方式进行,相对于线程来说,他的健壮性更强,因为线程之间是独立的,一个进程的销毁不会影响另外一个进程。
线程:
缺点: 相对来说健壮性不够强,因为他是进程的执行流,那么一个线程死掉了可能会影响整个进程。而且任何一个线程都可以修改进程中的变量,那么就容易把内容改乱。
优点: 线程间共享进程的资源,那么创建线程和切换线程消耗较小。
3. 什么时候用进程,什么时候用线程?
答案:
linux系统函数fork()可以为当前进程创建一个子进程,那么,在一个进程接收到来自客户端的请求之后,父进程可以创建子进程去处理客户端的请求。父进程只需要监控来自客户端得请求的到来,创建子进程去处理,这样就能实现高并发
对于线程来说,线程是cpu的最小执行单元,一个cpu同时只能执行一个线程,那么在多cpu的环境下就可以允许多个线程同时执行,同样多线程也能实现高并发操作。但是容易造成数据混乱,那么多线程需要同步和互斥。同步和互斥也是编写多线程程序的难点。
4. 多个进程如何占用 CPU?
答案:
** 一个内核同一时间只能运行一个任务
** 多个进程对内核进行争夺,操作系统决定那个进程占有计算机核心。
**占有计算机的核心的进程我们称为该进程占有 CPU 的时间片
5. 怎么查看 进程的状态?进程有那些信息,如何保存 ?
答案:
ps -aux 查看进程的信息
PCB (进程控制块)在内存中开辟的一块空间,里面保存着进程的信息,会随着进程的创建而创建,随着进程的结束而消失
6. 并行和并发的区别
答案:
并发 : 同时处理多个请求,但是内核采用轮询时间片的方式逐个访问,某一时间点实际只处理一个任务。IO多路复用 协程 循环服务器。单线程
并行 : 使用多个内核,同时执行多个任务 多进程 多线程
7. 谈谈你对多线程的理解
答案:
多线程:一个进程可以开启多个线程,每条线程可以并行(同时)执行不同的任务,多线程技术可以提高程序的执行效率,多线程中,所有变量都由所有线程共享,任何一个变量都可被任何一个线程修改。线程之间共享数据的最大危险在于多个线程同时更改一个变量
缺点:
1. 需要用到同步互斥
2. 可能受到GIL的影响,但是网络IO线程并发还是可以的
优点:
资源消耗比较少
原理:同一时间内,CPU 只能处理一条线程,只有一条线程在执行(工作),多线程并发(同时)执行,其实是 CPU 快速的在多线程之间调度(切换)。因为CPU 切换特别快,造成了多线程并发的假象
8. 谈谈你对python全局解释器锁的理解
答案:
python ---》 支持多线程 ---》同步互斥 ---》加锁 ---》 超级锁(全局解释器锁,把解释器锁住) ----》 在同一时刻,解释器只能解释一个线程 -----》大量python库为了省事沿用了这种方法 ---》python 多线程效率低下
GIL 问题 : 由于python的全局解释器锁造成python的多线程执行效率低下
解决方案:
* 不使用线程,使用多进程(Python 执行效率低)
* 不使用c 、c++ 做解释器 C# java
* python线程适合高用时的IO操作,网路IO。不适合cpu密集型程序
9. 线程中,会产生资源争夺的现象,谈谈你对 资源争夺解决的办法
答案:
同步 : 同步是一种合作关系,为完成某个任务多进程或者多线程之间形成一种协调 ,按照条件次序执行,传递告知资源情况。这种协调可能是因为阻塞关系达成的
互斥 :互斥是一种制约关系,但一个进程或线程进入到临界区会进行加锁操作,此时其他进程(线程)在企图操作临界资源就会阻塞。只有当资源被释放才能进行操作。
10. 怎么利用多核CPU呢?
答案:
最简单的方法是多进程加协程,既充分利用多核,有充分发挥协程的高效率,可获得极高的性能
三、MySQL基础
1. MySQL如何优化?
答案:
1.优化索引、SQL语句、分析慢查询;
2.设计表的时候严格按照数据库的设计范式来设计数据库;
3.我们还可以将我们的业务架构进行缓存,静态化和分布式;
4.不用全文索引,使用Xunsearch,ES或者云服务器上的索引;
5.如果效率还是不够好,可以采用主从方式将数据读写分离;
6.可以加上memcached缓存,将经常被访问到但不经常变化的数据放至memcached缓存服务器里面,这样的话能够节约磁盘I/O;
7.还可以优化硬件,在硬件层面,我们可以使用更好的一些硬盘(固态硬盘),使用一些磁盘阵列技术(raid0,raid1,raid5 ) ?
- raid0:最简单的(两块硬件相加100G+100G=200G)?
- raid1:镜像卷,把同样的数据下两份。可以随即从A/B里面读取,效率更高,硬盘坏了一块数据也不会丢失
2. SQL中,drop、delete、truncate有什么区别?
答案:
三者都是删除的意思,但是三者各有些区别
· delete和truncate只删除表的数据不删除表的结构
· 速度 drop > truncate > delete
· 想删除部分数据时, delete 删除时要带上where语句
· 保留表而想删除所有的数据时用truncate
3. 写SQL语句
答案:
1、每门课都大于80分的学生姓名
select name from table1 GROUP BY name having min(fenshu)>80;(推荐)
select DISTINCT name from table1 where name not in (select DISTINCT name from table1 where fenshu<=80);
2、删除除了编号不同,其他都相同的冗余学生信息
delete from table2 where bianhao not in (select min(bianhao) from table2 GROUP BY xuehao,name,kechenghao,kecheng,fenshu);
注意:这么写MySQL会报错,You can't specify target table 'table2' for update in FROM clause。这个错误表示不能在同一表中查询的数据作为同一表的更新数据。
应该这么写:delete from table2 where bianhao not in (select a.bianhao from (select * from table2 GROUP BY xuehao,name,kechenghao,kecheng,fenshu)a)
4. 一个叫team的表,里面只有一个字段name,一共有4条纪录,分别是a,b,c,d,对应四个球队,现在四个球队进行比赛,用一条sql语句显示所有可能的比赛组合。
答案:
select * from team a,team b where a.name>b.name;
5. 索引,主键,外键的区别?
答案:
定义:
主键--唯一标识一条记录,不能有重复的,不允许为空
外键--表的外键是另一表的主键, 外键可以有重复的, 可以是空值
索引--该字段没有重复值,但可以有一个空值
作用:
主键--用来保证数据完整性
外键--用来和其他表建立联系用的
索引--是提高查询排序的速度
个数:
主键--主键只能有一个
外键--一个表可以有多个外键
索引--一个表可以有多个唯一索引
6. 简述在MySQL数据库中MyISAM和InnoDB的区别?
答案:
区别于其他数据库的最重要的特点就是其插件式的表存储引擎。切记:存储引擎是基于表的,而不是数据库。
InnoDB与MyISAM的区别:
InnoDB存储引擎: 主要面向OLTP(Online Transaction Processing,在线事务处理)方面的应用,是第一个完整支持ACID事务的存储引擎(BDB第一个支持事务的存储引擎,已经停止开发)。
特点:
· 行锁设计、支持外键,支持事务,支持并发,锁粒度是支持mvcc得行级锁;
MyISAM存储引擎: 是MySQL官方提供的存储引擎,主要面向OLAP(Online Analytical Processing,在线分析处理)方面的应用。
特点:
不支持事务,锁粒度是支持并发插入得表级锁,支持表所和全文索引。操作速度快,不能读写操作太频繁;
7. 解释MySQL外连接、内连接与自连接的区别?
答案:
先说什么是交叉连接: 交叉连接又叫笛卡尔积,它是指不使用任何条件,直接将一个表的所有记录和另一个表中的所有记录一一匹配。
内连接 则是只有条件的交叉连接,根据某个条件筛选出符合条件的记录,不符合条件的记录不会出现在结果集中,即内连接只连接匹配的行。
外连接 其结果集中不仅包含符合连接条件的行,而且还会包括左表、右表或两个表中的所有数据行,这三种情况依次称之为左外连接,右外连接,和全外连接。
左外连接,也称左连接,左表为主表,左表中的所有记录都会出现在结果集中,对于那些在右表中并没有匹配的记录,仍然要显示,右边对应的那些字段值以NULL来填充。右外连接,也称右连接,右表为主表,右表中的所有记录都会出现在结果集中。左连接和右连接可以互换,MySQL目前还不支持全外连接。
8. 分库分表有没有用到,怎么实现的?
答案:
目前,根据我们的业务量,还没有使用分库分表。但是我有在关注MySQL的分布式方案,以前mysql分布式比较常用的方法是用阿里巴巴的cobar,将一张表水平拆分成多份分别放入不同的库来实现表的水平拆分,或将不同的表放入不同的库,但是后来发现cobar有一个问题一直不能很好的解决。目前,我关注到有很多人用mycat替换了cobar
9. char和varchar的区别?
答案:
是一种固定长度的类型,varchar则是一种可变长度的类型,它们的区别是: char(M)类型的数据列里,每个值都占用M个字节,如果某个长度小于M,MySQL就会在它的右边用空格字符补足.(在检索操作中那些填补出来的空格字符将被去掉)在varchar(M)类型的数据列里,每个值只占用刚好够用的字节再加上一个用来记录其长度的字节(即总长度为L+1字节).
varchar得适用场景:字符串列得最大长度比平均长度大很多 2.字符串很少被更新,容易产生存储碎片 3.使用多字节字符集存储字符串
Char得场景:存储具有近似得长度(md5值,身份证,手机号),长度比较短小得字符串(因为varchar需要额外空间记录字符串长度),更适合经常更新得字符串,更新时不会出现页分裂得情况,避免出现存储碎片,获得更好的io性能
10. 什么是数据库事务?
答案:
1. 单个逻辑单元执行的一系列操作,这些操作要么全做要么全不做,是不可分割的.事务的开始和结束用户是可以控制的,如果没控制则由数据库默认的划分事务.事务具有以下性质:
(1)原子性
指一个事务要么全执行,要么全不执行.也就是说一个事务不可能执行到一半就停止了.比如:你去买东西,钱付掉了,东西没拿.这两步必须同时执行 ,要么都不执行.
(2)一致性
指事务的运行并不改变数据库中的一致性.比如 a+b=10;a改变了,b也应该随之改变.
(3)独立性
两个以上的事务不会出现交替运行的状态,因为这样可能导致数据的不一致
(4)持久性
事务运行成功之后数据库的更新是永久的,不会无缘无故的回滚
四、MongoDB
1. Redis和MongoDB的优缺点?
答案:
MongoDB和Redis都是 NoSQL,采用结构型数据存储。二者在使用场景中,存在一定的区别,这也主要由于二者在内存映射的处理过程,持久化的处理方法不同。MongoDB 建议集群部署,更多的考虑到集群方案,Redis 更偏重于进程顺序写入,虽然支持集群,也仅限于主-从模式.
Redis 优点:
读写性能优异
支持数据持久化,支持AOF和RDB两种持久化方式
支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。
数据结构丰富:除了支持string类型的value外还支持string、hash、set、sortedset、list 等数据结构。
Redis缺点:
Redis不具备自动容错和恢复功能, 主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复。
主机宕机,宕机前有部分数据未能及时同步到从机, 切换 IP后还会引入数据不一致的问题,降低了系统的可用性。Redis的主从复制采用全量复制,复制过程中主机会 fork 出一个子进程对内存做一份快照, 并将子进程的内存快照保存为文件发送给从机,这一过程需要确保主机有足够多的空余内存。若快照文件较大,对集群的服务能力会产生较大的影响,而且复制过程是在从机新加入集群或者从机和主机网络断开重连时都会进行,也就是网络波动都会造成主机和从机间的一次全量的数据复制,这对实际的系统运营造成了不小的麻烦。
Redis 较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。为避免这一问题,运维人员在系统上线时必须确保有足够的空间, 这对资源造成了很大的浪费。
MongoDB优点:
弱一致性(最终一致),更能保证用户的访问速度文档结构的存储方式, 能够更便捷的获取数内置 GridFS,高效存储二进制大对象 (比如照片和视频)
支持复制集、主备、互为主备、自动分片等特性
动态查询
全索引支持,扩展到内部对象和内嵌数组
MongoDB缺点:
不支持事务
MongoDB占用空间过大
维护工具不够成熟
2. 怎么解决数据库高并发的问题?
答案:
解决数据库高并发:
1.分表分库
2.数据库索引
3.redis缓存数据库
4.读写分离
5.负载均衡集群:将大量的并发请求分担到多个处理节点。由于单个处理节点的故障不影响整个服务,负载均衡集群同时也实现了高可用性。
3. 如何执行事物/加锁?
答案:
MongoDB没有使用传统的锁或者复杂的带回滚的事务,因为它设计的宗旨是轻量,快速以及可预计的高性能。可以把它类比成MySQL MylSAM的自动提交模式。通过精简对事务的支持,性能得到了提升,特别是在一个可能会穿过多个服务器的系统里。
4. 如何理解MongoDB中的GridFS机制,MongoDB如何使用GridFS来存 储文件?
答案:
GridFS是一种将大型文件存储在MongoDB中的文件规范。使用GridFS可以将大文件分隔成多个小文档存放,这样我们能够有效的保存大文档,而且解决了BSON对象有限制的问题。
5. MongoDB支持存储过程吗?怎么用?
答案:
MongoDB支持存储过程,它是javascript写的,保存在db.system.js表中。
6. 如果一个分片(Shard)停止或很慢的时候,发起一个查询会怎样?
答案:
如果一个分片停止了,除非查询设置了“Partial”选项,否则查询会返回一个错误。如 果一个分片响应很慢,MongoDB会等待它的响应。
7. 你怎么比较MongoDB、CouchDB及CouchBase?
答案:
MongoDB和CouchDB都是面向文档的数据库。MongoDB和CouchDB都是开源N oSQL数据库的最典型代表。 除了都以文档形式存储外它们没有其他的共同点。Mon goDB和CouchDB在数据模型实现、接口、对象存储以及复制方法等方面有很多不 同。
8. MongoDB成为最好NoSQL数据库的原因是什么?
答案:
以下特点使得MongoDB成为最好的NoSQL数据库:
面向文件
高性能
高可用性
易扩展性
丰富的查询语言
9. 分析器在MongoDB中的作用是什么?
答案:
MongoDB中包括了一个可以显示数据库中每个操作性能特点的数据库分析器。通过这个分析器你可以找到比预期慢的查询(或写操作);利用这一信息,比如,可以确定是否需要添加索引。
10. 名字空间(namespace)是什么?
答案:
MongoDB存储BSON对象在丛集(collection)中。数据库名字和丛集名字以句点连结起来叫做名字空间(namespace)。
五、正则表达式
1. python中用分别用什么字符来匹配字符串的开头和末尾?
答案:
在python中,匹配字符串的开头用^,匹配字符串的末尾用$。
2. 用两种正则的方法表示0-9中的任意一个数字?
答案:
[0-9]和\d
3. python中用正则匹配任意字母和数字的万能式子是什么?
答案:
[a-zA-Z0-9]
4. python中re模块中的match与search的区别?
答案:
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None; 而re.search匹配整个字符串,直到找到一个匹配。
5. findall方法在正则匹配中起到什么样的作用?
答案:
在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。
注意: match 和 search 是匹配一次 findall 匹配所有。
语法格式为:findall(string[,pos[,endpos]])
参数:
string : 待匹配的字符串。
pos : 可选参数,指定字符串的起始位置,默认为 0。
endpos : 可选参数,指定字符串的结束位置,默认为字符串的长度。
六、git
1. 从版本库中删除文件的时候,如果发现删错了可以用什么命令将版本库中的文件进行一键还原?
答案:
git checkout --文件名
2. 如下两条命令的区别在于什么?
①: $ git branch -r
②:$ git branch –a
答案:
第一条命令的命令的意思是列出所有远程分支,第二条命令的意思是列出所有本地分支和远程分支。
3. 请分别指出以下几个名词的译名。
①Workspace
②Index / Stage
③Repository
④ Remote
答案:
①工作区; ②暂存区; ③仓库区(或本地仓库); ④远程仓库
4. 简述以下git的工作流程。
答案:
1、在工作目录中修改某些文件
2、对修改后的文件进行快照,然后保存到暂存区域
3、提交更新,将保存在暂存区域的文件快照永久转储到Git目录中
5. fetch和merge和pull的区别
答案:
pull相当于git fetch 和 git merge,即更新远程仓库的代码到本地仓库,然后将内容合并到当前分支。
git fetch:相当于是从远程获取最新版本到本地,不会自动merge
git merge : 将内容合并到当前分支
git pull:相当于是从远程获取最新版本并merge到本地