面试八股文-python
解释型语言与编译性语言面向对象和面向过程Python优点Python缺点装饰器python 装饰器@staticmethod和@classmethod区别和使用写一个装饰器深拷贝、浅拷贝和等号赋值在python中如何实现多线程GILPython如何内存管理Python垃圾回收机制*args和**kwargs的含义常用方法模块和包闭包python运算符(7)多进制数字Python标准数据类型(6)tuple (元组)set(集合) PYTHONPATH变量是什么生成器generator和迭代器iterator生成器迭代器生成器和函数: 参数传递机制Python对象基本要素(3),id,type和value__new__和__init__的区别列出5个python标准库字典根据键从小到大排序
因为最近面试需要,就随手整理了一些八股文,参考了很多
解释型语言与编译性语言
编译型语言要求使用编译器一次性将所有源代码编译为一个可执行程序,一次编译可重复执行。代表语言有C、C++、Golang、汇编等。
解释型语言是使用解释器一边执行一边转换,用到些源代码就转换哪些,不会生成可执行程序。代表语言有JavaScript、Python、PHP、Shell等。
面向对象和面向过程
面向过程:指的是把问题分解成为一个一个步骤,每个步骤用函数实现,依次调用即可。
面向对象:把构成问题的事务分解成各个对象,建立对象来描述某个事务在解决问题的步骤中的行为; 面向对象的特点:封装、继承、多态
Python优点
解释型,语法简单易懂,可读性强有很多库可以用,可以让我们站在巨人的肩膀上简单的实现想要的功能可扩展,和其他编程语言或其他软件有可连接的接口免费开源、可移植自动内存管理,让程序员可以专注于代码的实现Python缺点
他的可解释特征使其运行速度变慢动态语言的特点可能会增加运行时错误。装饰器
装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,它接受一个函数作为参数,并返回一个函数,利用python的@语法来放置
功能:1.引入日志;2.函数执行时间统计;3.执行函数前预备处理;4.执行函数后清理功能;5.权限校验;6.缓存
python 装饰器@staticmethod和@classmethod区别和使用
使用原因:使用@staticmethod或@classmethod,就可以不需要实例化,直接类名.方法名()来调用。这有利于组织代码,把某些应该属于某个类的函数给放到那个类里去,同时有利于命名空间的整洁。
@staticmethod或@classmethod的区别
类的普通方法,第一个参数需要self参数表示自身。
@staticmethod不需要表示自身对象的self和自身类的cls参数,就跟使用函数一样。
@classmethod也不需要self参数,但第一个参数需要是表示自身类的cls参数。
class Test(object): """docstring for Test""" def __init__(self, arg=None): super(Test, self).__init__() self.arg = arg def say_hi(self): print 'hello wrold' @staticmethod def say_bad(): print 'say bad' @classmethod def say_good(cls): print 'say good'def main(): test = Test() test.say_hi() Test.say_bad() //直接类名.方法名()来调用 Test.say_good() //直接类名.方法名()来调用if __name__ == '__main__': main()
写一个装饰器
import timedef calc_time(func): def inner(): t1 = time.time() func() t2 = time.time() print('cost time: {}s'.format(t2-t1)) return inner@calc_timedef test(x): for i in range(1000): print(x,end='') print('\n') return xtest(1)
深拷贝、浅拷贝和等号赋值
深拷贝:新建一个对象,把原来对象的内存完全复制过来,改变复制后的对象,不会改动原来内存的内容。(两个对象在复制之后是完全独立的对象)
等号赋值:相当于为原来的对象打一个新的标签,两个引用指向同一个对象,修改其中的一个,另一个也会产生变化
浅拷贝:两种情况,1. 浅拷贝的值是不可变对象(数值、字符、元组)时,和等于赋值一样,对象的id值和浅拷贝原来的值相同;2. 如果是可变对象(列表、字典等),a. 一个简单的没有嵌套的对象,复制前后的对象相互之间不会影响,b. 对象中有复杂子对象,如列表嵌套,如果改变原来的对象中复杂子对象的值,浅拷贝的值也会受影响,因为在浅拷贝时只复制了子对象的引用(只拷贝父对象)。
在python中如何实现多线程
Thread,新建线程,然后可以用GIL实现线程通信
GIL
GIL(全局解释锁)能确保一次执行一个线程,线程轮流保存GIL并且在把他传给下一个线程之前执行一些操作,以达到多个进程在CPU上轮流运行,但是这个转换速度很快,让我们觉得他是并行的。
Python如何内存管理
引用计数:python内部使用引用计数,来保持追踪内存中的对象,Python内部记录了对象有多少个引用,即引用计数,当对象被创建时就创建了一个引用计数,当对象不再需要时,这个对象的引用计数为0时,它被垃圾回收。
垃圾回收:python会检查引用计数为0的对象,清除其在内存占的空间;循环引用对象则用一个循环垃圾回收器来回收
内存池机制:在Python中,许多时候申请的内存都是小块的内存,这些小块内存在申请后,很快又会被释放,由于这些内存的申请并不是为了创建对象,所以并没有对象一级的内存池机制。这就意味着Python在运行期间会大量地执行malloc和free的操作,频繁地在用户态和核心态之间进行切换,这将严重影响Python的执行效率。为了加速Python的执行效率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放。
a) Python提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。
b) Python中所有小于256个字节的对象都使用pymalloc实现的分配器,而大的对象则使用系统的 malloc。另外Python对象,如整数,浮点数和List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配又释放了大量的整数,用于缓存这些整数的内存就不能再分配给浮点数。
Python垃圾回收机制
(自动处理分配回收内存的问题,没用了内存泄漏的隐患),以引用计数机制为主,标记-清楚和分代收集两种机制为辅
计数机制就是python中的每一个对象都有一个引用计数的值,当有引用的时候,这个值会增加,引用他的对象被删除时,这个值减小,引用计数的值为0时,该对象生命结束,python会把这段内存自动回收。(缺点,循环引用,如果l1和l2相互引用,没用其他的对象引用他们,这两段内存永远无法被回收)
*args和**kwargs的含义
用来处理可变参数,接收参数后,args会变成一个tuple,kwargs会变成一个dict
可变参数指的是,不知道参数数量
同时使用*args和kwargs时,*args参数必须要列在kwargs前,否则会报错。
def test(a,*args,**kwargs): print(a) print(args) print(kwargs)test(1,3,5,7,c='2',d=4)输出为:1(3, 5, 7){‘c’: ‘2’, ‘d’: 4}
常用方法
join()和split()
join(),把指定的字符串添加到字符串中,也可以把join后面带的一个含字符串的列表用指定的字符串连接起来
split(),把字符串用指定字符分割,结果是一个列表
strip(), lstrip(), rstrip()
移除字符串两边的空格
is家族 检查字符串……
islower(), isupper(), istitle()…
isalnum(), isdigit(), isnumeric(), isdecimal()…
pass
比如函数没想好怎么写的时候可以用来在函数中占位,保证语法正确
continue直接跳到下一个循环,pass则是占位,虽然什么都不会发生,但是如果后面语句的话这些语句会继续运行
yield
保存当前运行状态(断点),然后暂停执行,即将函数挂起
将yeild关键字后面表达式的值作为返回值返回,此时可以理解为起到了return的作用,当使用next()、send()函数让函数从断点处继续执行,即唤醒函数。
match()和search()
match()检测RE是不是在字符串开始位置匹配,只有在0匹配成功才返回True,search()会扫描整个字符串查找有无匹配
模块和包
模块:python中包含并有组织的代码片段,xxx.py的xxx就是模块名
包:模块之上的有层次的目录结构,定义了由很多模块或很多子包组成的应用程序执行环境。包是一个包含__init__.py文件和若干模块文件的文件夹。
库:具有相关功能模块的集合,python有很多标准库、第三方库…
闭包
闭包使得局部变量在函数外被访问成为可能。
python运算符(7)
算术、关系、赋值、逻辑、位、成员、身份运算符
多进制数字
0b二进制(bin),0o八进制,0x十六进制
Python标准数据类型(6)
不可变数据:1.number (数字类型)
2.string (字符串类型)
3.tuple (元组类型)
可变数据: 1.set (集合类型)
2.dictionary (字典类型)(key、walue)
3.list (列表类型)
tuple (元组)
tuple1=("hello",2,True)
tuple 是使用 ( ) 小括号包含各个数据项
tuple 与 list 的唯一区别是 tuple 的元素是不能修改,而 list 的元素可以修改
set(集合)
set1={1,2,3,"nihao","hello",1,2}set2=set("hello word")
set 是一个无序不重复元素的序列
使用大括号 { } 或者 set() 函数创建集合
用 set() 创建一个空集合
使用 set 可以去重
PYTHONPATH变量是什么
Python中的环境变量,用于在导入模块的时候搜索路径。因此它必须包含Python源库目录以及含有Python源代码的目录。
生成器generator和迭代器iterator
参考
生成器
生成器是一种特殊迭代器。生成一系列的值用于迭代,在for循环的过程中不断计算出下一个元素并在恰当的条件结束循环
使用了yield的函数,返回迭代器
迭代器
迭代器是访问集合元素的一种方式,他的对象从集合的第一个元素开始访问,直到所有元素被访问完结束,用iter()创建迭代器,调用next()函数获取对象(迭代只能往前不能后退)。
两者区别:
创建/生成,生成器创建一个函数,用关键字yield生成/返回对象;迭代器用内置函数iter()和next()
生成器中yield语句的数目可以自己在使用时定义,迭代器不能超过对象数目
生成器yield暂停循环时,生成器会保存本地变量的状态;迭代器不会使用局部变量,更节省内存
生成器和函数:
生成器和函数的主要区别在于函数 return a value,生成器 yield a value同时标记或记忆 point of the yield 以便于在下次调用时从标记点恢复执行。 yield 使函数转换成生成器,而生成器反过来又返回迭代器。
参数传递机制
如果实际参数的数据类型是可变对象(列表、字典),则函数参数的传递方式将采用引用传递方式。如果是不可变的,比如字符串、数值、元组,他们就是按值传递。
Python对象基本要素(3),id,type和value
==比较value,即值,is比较id
__new__和__init__的区别
new:创建对象时调用,会返回当前对象的一个实例
init:创建完对象后调用,对当前对象的一些实例初始化,无返回值
调用顺序:先调用__new__生成一个实例再调用__init__方法对实例进行初始化,比如添加属性。
列出5个python标准库
os:提供了不少与操作系统相关联的函数
sys: 通常用于命令行参数
re: 正则匹配
math: 数学运算
datetime:处理日期时间
字典根据键从小到大排序
y = {1:3, 2:2, 3:1}by_key = sorted(y.items(),key = lambda item:item[0])by_value = sorted(y.items(),key = lambda item:item[1])print (by_key) #结果为[(1, 3), (2, 2), (3, 1)],即按照键名排列print (by_value) #结果为[(3, 1), (2, 2), (1, 3)],即按照键值排列