Python开发⼯程师⾯试试题(未完待续......)python语法以及其他基础部分
1.可变与不可变类型;
不可变类型(数字、字符串、元组、不可变集合)不可变类型不能被修改。
可变类型(列表、字典、可变集合)
2.浅拷贝与深拷贝的实现⽅式、区别;deepcopy如果你来设计,如何实现;
基本类型 :
基本类型在内存中分别占有固定⼤⼩的空间,他们的值保存在栈空间,我们是通过按值来访问的。
引⽤类型 :
引⽤类型,值⼤⼩不固定,栈内存中存放地址指向堆内存中的对象。是按引⽤访问的。
栈内存中存放的只是该对象的访问地址,在堆内存中为这个值分配空间。由于这种值的⼤⼩不固定,
因此不能把它们保存到栈内存中。但内存地址⼤⼩的固定的,因此可以将内存地址保存在栈内存中。
这样,当查询引⽤类型的变量时,先从栈中读取内存地址,然后再通过地址到堆中的值。对于这种,
我们把它叫做按引⽤访问。
浅拷贝只复制指向某个对象的引⽤地址,⽽不复制对象本⾝,新旧对象还是共享同⼀块内存。
但深拷贝会另外创造⼀个⼀模⼀样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
浅复制只复制⼀层对象的属性,⽽深复制则递归复制了所有层级。
import copy as cp
L=[1,[2,3]]
py(L) #浅拷贝: 只是引⽤,并不会开辟新的内存空间,
L1与L指向同⼀⽚内存空间。L改变,L1也会锁着改变。
L2=cp.deepcopy(L) #深拷贝:会为数据重新开辟⼀⽚内存空间,L的变化不会影响L2。
_new_作⽤于_init_之前。前者可以决定是否调⽤后者,或者说可以决定调⽤哪个类的_init_⽅法。
⾸先要知道在⾯向对象编程中,实例化基本遵循创建实例对象、初始化实例对象、最后返回实例对象这么⼀个过程。
Python 中的 _new_ ⽅法负责创建⼀个实例对象,_init_ ⽅法负责将该实例对象进⾏初始化;
4.你知道⼏种设计模式;
单例模式:保证⼀个类仅有⼀个实例,并提供⼀个访问他的全局访问点,例如框架中的数据库连接
装饰器模式:不修改元类代码和继承的情况下动态扩展类的功能,例如框架中的每个controller⽂件会提供before和after⽅法。迭代器模式:提供⼀个⽅法顺序访问⼀个聚合对象中各个元素,在PHP中将继承 Iterator 类
命令模式: 将”请求”封闭成对象, 以便使⽤不同的请求,队列或者⽇志来参数化其他对象. 命令模式也⽀持可撤销的操作.
5.编码和解码你了解过么;
数据通过编码decode转换成Unicode编码,编码的同时会将数据变成byte类型,通过解码encode转换为utf-8。
6.列表推导list comprehension和⽣成器的优劣;
[expr for iter_var in iterable] 列表推导式是将所有的值⼀次性加载到内存中
(expr for iter_var in iterable)
在⼤数据量处理时,⽣成器表达式的优势就体现出来了,因为它的内存使⽤⽅式更好,
效率更⾼,它并不创建⼀个列表,只是返回⼀个⽣成器。
7.什么是装饰器;如果想在函数之后进⾏装饰,应该怎么做;
装饰器是⼀个函数,这个函数的主要作⽤是包装另⼀个函数或类
包装的⽬的是在不改变原函数名的情况下改变被包装对象的⾏为。
接收⼀个函数,内部对其包装,然后返回⼀个新函数,这样⼦动态的增强函数功能
通过⾼阶函数传递函数参数,新函数添加旧函数的需求,然后执⾏旧函数。
8.⼿写个使⽤装饰器实现的单例模式;
该模式的主要⽬的是确保某⼀个类只有⼀个实例存在。
from functools import warps
def My_decorate(f):
@warps(f)
def fn(*args,**kwargs):
print('decorate called')
return f(*args,**kwargs)
return fn
@My_decorate
def fx():
pring('fx called')
fx()
9.使⽤装饰器的单例和使⽤其他⽅法的单例,在后续使⽤中,有何区别;
使⽤装饰器单例属性不会被覆盖。因为装饰器单例模式是直接返回之前⽣成的对象,
并不会重新初始化对象。像new⽅法构建的单例模式会重新调⽤init⽅法,为实例重新初始化属性。
10.⼿写:正则邮箱地址;
pattern = '[a-zA-Z0-9_.-]+@[a-zA-Z0-9]+\.[a-z]'
匹配⾝份证:
pattern = '(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)'
pattern = '^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$'
11.介绍下垃圾回收:引⽤计数/分代回收/孤⽴引⽤环;
垃圾回收:python解释器对正在使⽤的对象保持计数,当某个对像的引⽤计数降为0时,垃圾收集器就可以释放该对象,获取分配的内存。当分配对象和取消分配对象的差值⾼于阈值时垃圾回收才会启动。
分代回收:python将所有的对象分为0,1,2三代。所有的新建对象都是0代对象。当某⼀代对象经历过垃圾回收,依然存活,那么它就被归⼊下⼀代对象。垃圾回收启动时,⼀定会扫描所有的0代对象。
如果0代经过⼀定次数垃圾回收,那么就启动对0代和1代的扫描清理。当1代也经历了
⼀定次数的垃圾回收后,那么会启动对0,1,2,即对所有对象进⾏扫描。
12.多进程与多线程的区别;CPU密集型适合⽤什么;
多线程:在单个程序中同时运⾏多个线程完成不同的⼯作,称为多线程。
线程共享内存空间;进程的内存是独⽴的,
同⼀个进程的线程之间可以直接交流;两个进程想通信,必须通过⼀个中间代理来实现,
⼀个线程可以控制和操作同⼀进程⾥的其他线程;但是进程只能操作⼦进程
优缺点:1.多进程的优点是稳定性好,⼀个⼦进程崩溃了,不会影响主进程以及其余进程。
但是缺点是创建进程的代价⾮常⼤,因为操作系统要给每个进程分配固定的资源。
2.多线程优点是效率较⾼⼀些,但是致命的缺点是任何⼀个线程崩溃都可能
造成整个进程的崩溃,因为它们共享了进程的内存资源池。
CPU密集型适合⽤多线程开发
13.进程通信的⽅式有⼏种;
进程间通信主要包括管道, 系统IPC(包括消息队列,信号量,共享存储), SOCKET
14.介绍下协程,为何⽐线程还快;
⾼并发+⾼扩展性+低成本:⼀个CPU⽀持上万的协程都不是问题。所以很适合⽤于⾼并发处理
协程能保留上⼀次调⽤时的状态,管是进程还是线程,每次阻塞、切换都需要陷⼊系统调⽤,
使⽤线程时需要⾮常⼩⼼地处理同步问题,⽽协程完全不存在这个问题。
15.range和xrange的区别
xrange和range 的⽤法完全相同,但是返回的是⼀个⽣成器。
算法排序部分
16.⼿写快排;堆排;⼏种常⽤排序的算法复杂度是多少;快排平均复杂度多少,最坏情况如何优化;
17.⼿写:已知⼀个长度n的⽆序列表,元素均是数字,要求把所有间隔为d的组合出来,你写的解法算法复杂度多少;
def func(x, d):
L = []
n = len(x)
if d > n:
return None
L.append(x[0])
a = d + 1
while a < n:
L.append(x[a])
a = a + d + 1
return L
list = [x for x in range(100)]
result = func(list, 10)
print(result)
我写的只考虑到从第⼀个元素开始组合。没有考虑从第⼆个,第三个元素开始......求⼤神提供完全正确⽅法。
18.⼿写:⼀个列表A=[A1,A2,…,An],要求把列表中所有的组合情况打印出来;
19.⼿写:⽤⼀⾏python写出1+2+3+…+10**8 ;
s = sum([x for x in range(1,10**8+1)])
20.⼿写python:⽤递归的⽅式判断字符串是否为回⽂;
def isHuiWen(str):
if(len(str) <2):
return True
if str[0] !=str[-1]:
return False
return isHuiWen(str[1:-1])
str = input("请输⼊⼀个字符串:")
if isHuiWen(str):
print("该字符串为回⽂字符串")
else:
print("该字符串不是回⽂")
21.单向链表长度未知,如何判断其中是否有环;
22.单向链表如何使⽤快速排序算法进⾏排序;
23.⼿写:⼀个长度n的⽆序数字元素列表,如何求中位数,如何尽快的估算中位数,
你的算法复杂度是多少;
def func(list):
if len(list) <= 1:
return list
L = sorted(list)
n = len(list) % 2
m = len(list) // 2
if n == 0:
s = (L[m] + L[m-1]) / 2
return s
s = L[m]
return s
l = [1,2,6,84,12,62,100]
print(func(l))
24.如何遍历⼀个内部未知的⽂件夹(两种树的优先遍历⽅式)
⽹络基础部分
25.TCP/IP分别在模型的哪⼀层;
TCP 在传输层,
IP在⽹络层
26.socket长连接是什么意思;
在⼀个TCP连接上可以连续发送多个数据包,在TCP连接保持期间,如果没有数据包发送,
需要双⽅发检测包以维持此链接,⼀般需要⾃⼰做在线维持。
长连接指建⽴SOCKET连接后不管是否使⽤都保持连接,但安全性较差
数据库的连接⽤长连接。如果⽤短连接频繁的通信会造成socket错误,
⽽且频繁的socket创建也是对资源的浪费
27.select和epoll你了解么,区别在哪;
28.TCP UDP区别;三次握⼿四次挥⼿讲⼀下;
TCP协议: (在传输之前先建⽴连接)⾯向连接(的通信服务):可靠地数据传输,失序,⽆差错,⽆丢失,⽆
重复⽤途:适⽤于传输内容⽐较⼤,⽹络情况⽐较好,需要提供准确的情况.⽐如:聊天信息,⽂字传输,邮件传输。 udp 协议:⾯向⽆连接的服务,不可靠,发送时由发送端⾃主进⾏,不考虑接收端。
⽤途:适⽤于⽹络较差,对传输准确性要求低,⼴播组播.⽐如:视频会议,⼴播数据。
三次握⼿:
1.客户端向服务器发起链接请求(问是否可以连接)
2.服务器接受到请求后进⾏确认(允许连接)返回报⽂
3.客户端收到许可,建⽴连接
四次挥⼿:
1.主动⽅发送报⽂告知被动⽅要断开连接
2.被动发返回报⽂没告知收到请求,准备断开
3.被动发发送报⽂给主动⽅告知准备就绪可以断开
4.主动⽅发送报⽂确定断开
get是从服务器上获取数据,post是向服务器传送数据。在客户端, get⽅式在通过URL提交数据,
数据在URL中可以看到;post⽅式,数据放置在HTML HEADER内提交。
对于get⽅式,服务器端⽤Request.QueryString获取变量的值,
对于post⽅式,服务器端⽤Request.Form获取提交的数据。
Get ⽅式提交数据,会带来安全问题,⽐如⼀个登陆页⾯,通过 Get ⽅式提交数据时,快速排序python实现
⽤户名和密码将出现在 URL 上,如果页⾯可以被缓存或者其他⼈可以访问客户这台机器,
就可以从历史记录获得该⽤户的帐号和密码,所以表单提交建议使⽤ Post ⽅法。
33.状态码你知道多少,⽐如200/403/404/504等等;
200:操作成功。
403:访问受限,授权过期(错误提⽰)
404:资源,服务器未到
504:⽹关超时,服务器作为⽹关或代理,但是没有及时从上游服务器收到请求。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论