Java有八股文,但是Python面试好像这方面的资料比较少,所以打算自己整理一些写出来,给要找工作的小伙伴个参考crt语句生成器,如果大家有一些好的面试题也可以私聊我
下面是某软国际的面试题,感觉整体考察的是基础部分
1.请说一下你对迭代器和生成器的区别?
大家回家这个题的时候,也可以提一下可迭代对象(iterable),可迭代对象是一种可以逐一返回其成员元素的对象crt语句生成器,它可以在每次的迭代过程中产生一个成员元素
迭代器是一种可以被遍历的对象,并且能作用于next()函数。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。 迭代器只能往后遍历不能回溯,不像列表,你随时可以取后面的数据,也可以返回头取前面的数据。
迭代器通常要实现两个基本的方法:iter() 和 next()
下面举个例子
lis=[1,2,3,4]
it = iter(lis) # 使用Python内置的iter()方法创建迭代器对象
next(it) # 使用next()方法获取迭代器的下一个元素
1
next(it)
2
next(it)
3
next(it)
4
next(it) # 当后面没有元素可以next的时候,弹出错误
复制代码
我们也可以用迭代器实现一个for循环
d_iter = iter(range(5))
while True:
try:
print(next(d_iter))
except StopIteration:
break
复制代码
上面我们自己写的代码等价于
for i in range(5):
print(i)
复制代码
接下来我们聊下生成器
有时候,序列或集合内的元素的个数非常巨大,如果全制造出来并放入内存,对计算机的压力是非常大的。
如果元素可以按照某种算法推算出来,需要就计算到哪个,就可以在循环的过程中不断推算出后续的元素,而不必创建完整的元素集合,从而节省大量的空间。
在Python中,这种一边循环一边计算出元素的机制,称为生成器:generator。
生成器在 Python 的写法是用小括号括起来,g = (x * x for x in range(1, 4)),即初始化了一个生成器。
可以通过next()函数获得generator的下一个返回值,这点和迭代器非常相似
next(g)
1
next(g)
4
next(g)
9
next(g)
复制代码
除了使用生成器推导式,我们还可以使用yield关键字。
def createNums():
print("----func start------")
a,b = 0,1
for i in range(5):
# print(b)
print("--1--")
yield b
print("--2--")
a,b = b,a+b # a,b = 1, 1 a,b = 1,2
print("--3--")
print("----func end------")
g= createNums()
复制代码
在 Python中,使用yield返回的函数会变成一个生成器(generator)。 在调用生成器的过程中,每次遇到yield时函数会暂停并保存当前所有的运行信息,返回yield的值。并在下一次执行next()方法时从当前位置继续运行。
2.什么是线程安全?
线程安全,就要提到Python中的线程共享全局变量导致资源竞争,如果两个线程同时对一个变量进行写操作,我们看下会发生什么
import threading
import time
num = 0
def task1(nums):
global num
for i in range(nums):
num += 1
print("task1----num=%d" % num)
def task2(nums):
global num
for i in range(nums):
num += 1
print("task2----num=%d" % num)
def main():
t1 = threading.Thread(target=task1, args=(1000000,))
t2 = threading.Thread(target=task2, args=(1000000,))
t1.start()
t2.start()
time.sleep(5)
print("main-----num=%d" % num)
if __name__ == "__main__":
main()
复制代码
打印结果
task1----num=1000000
task2----num=1193380
main-----num=1193380
复制代码
因为这是多线程的, 所以cpu在处理两个线程的时候, 是采用雨露均沾的方式, 可能在线程一刚刚将num值+1还没来得及将新值赋给num时, 就开始处理线程二了, 因此当线程二执行完全部的num+=1的操作后, 可能又会开始对线程一的未完成的操作, 而此时的操作停留在了完成运算未赋值的那一步, 因此在完成对num的赋值后, 就会覆盖掉之前线程二对num的+1操作
那我们如何解决呢?
可以通过加锁,或者采用队列的方式来解决资源竞争的问题,这里我就不展开说了
3.Python中数组有哪些类型?
List Tuple Dictionary
复制代码
4.python 中 yield 的用法?
yield 简单说来就是一个生成器,这样函数它记住上次返 回时在函数体中的位置。对生成器第 二次(或n 次)调用跳转至该函 次)调用跳转至该函数。
5. Python中pass语句的作用是什么?
pass语句什么也不做,一般作为占位符或者创建占位程序,pass语句不会执行任何操作。
6.谈谈你对GIL锁对python多线程的影响?
GIL全局解释器锁,这是一段官网对GIL的说明
In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple
native threads from executing Python bytecodes at once. This lock is necessary mainly
because CPython’s memory management is not thread-safe. (However, since the GIL
exists, other features have grown to depend on the guarantees that it enforces.)
复制代码
Python解释器有很多,CPython、JPython、iPython,在CPython解释器中GIL是一把互斥锁,用来阻止同一个进程下的多个线程同时执行
每个CPU在同一时间只能执行一个线程(在单核CPU下的多线程其实都只是并发,不是并行,并发和并行从宏观上来讲都是同时处理多路请求的概念。但并发和并行又有区别,并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔内发生。)
重点:
7. Python里面如何拷贝一个对象?
浅拷贝:创建一个新的对象,但它包含的是对原始对象中包含项的引用(如果用引用的方式修改其中一个对象,另外一个也会修改改变)
深拷贝:创建一个新的对象,并且递归的复制它所包含的对象(修改其中一个,另外一个不会改变)
下面给大家举个例子
from copy import deepcopy
a = [11,22]
b = a
print(id(a))
print(id(b))
import copy
c = deepcopy(a)
a.append(33)
# [11, 22, 33]
print(a)
# [11, 22] c是深拷贝 相当于创建了新的对象 不受影响
print(c)
复制代码
8. 递归函数停止的条件
递归的终止条件一般定义在递归函数内部,在递归调用前要做一个条件判断,根据判断的结果选择是继续调用自身,还是return;返回终止递归。
终止的条件:
举个例子
def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n-1)
复制代码
9. 什么是闭包?
在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。
给大家举个例子
def outer_function(x):
def inner_function(y):
return x + y
return inner_function
closure = outer_function(10)
result = closure(5)
print(result) # Output: 15
复制代码
10. linux下管道符的作用?
一个命令的输出结果可以通过管道做为另一个命令的输入,就是管道符的作用.
这个命令就是查看Linux系统中是否运行了Redis服务
ps -aux | grep redis
复制代码