Python 面试题大全系列(三)

简介: Python 面试题大全系列(三)

今天继续分享 Python 相关的面试题,你准备好了嘛!

综合篇(一),网络编程

1. 简述 OSI 七层协议

是网络传输协议,人为的把网络传输的不同阶段划分成不同的层次。

七层划分为:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层。

五层划分为:应用层、传输层、网络层、数据链路层、物理层。

物理层:网线,电缆等物理设备

数据链路层:Mac 地址

网络层:IP 地址

传输层:TCP,UDP 协议

应用层:FTP 协议,Email,WWW 等

2. 三次握手、四次挥手的流程

都发生在传输层

三次握手:

TCP 协议是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接。

TCP 标志位(位码),有6种标示:SYN(synchronous建立联机) ACK(acknowledgement 确认) PSH(push传送) FIN(finish结束) RST(reset重置) URG(urgent紧急)

Sequence number(顺序号码) Acknowledge number(确认号码)

第一次握手:主机 A 发送位码为 syn=1,随机产生 seq number=1234567 的数据包到服务器,并进入 SYN_SEND 状态,主机 B 由 SYN=1 知道,A 要求建立联机;

第二次握手:主机 B 收到请求后要确认联机信息,向 A 发送 ack number=(主机 A 的 seq+1),syn=1,ack=1,随机产生 seq=7654321 的包,并进入 SYN_RECV 状态;

第三次握手:主机 A 收到后检查 ack number 是否正确,即第一次发送的 seq number+1,以及位码 ack 是否为 1,若正确,主机 A 会再发送 ack number=(主机 B 的 seq+1),ack=1,主机 B 收到后确认 seq 值与 ack=1 则连接建立成功,两个主机均进入 ESTABLISHED 状态。

以上完成三次握手,主机 A 与主机 B 开始传送数据。

四次挥手:

因为 TCP 连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个 FIN 来终止这个方向的连接。收到一个 FIN 只意味着这一方向上没有数据流动,一个 TCP 连接在收到一个 FIN 后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。

  1. 服务器 A 发送一个 FIN,用来关闭 A 到服务器 B 的数据传送。
  2. 服务器 B 收到这个 FIN,它发回一个 ACK,确认序号为收到的序号加1。和 SYN 一样,一个 FIN 将占用一个序号。
  3. 服务器 B 关闭与服务器 A 的连接,发送一个 FIN 给服务器 A。
  4. 服务器 A 发回 ACK 报文确认,并将确认序号设置为收到序号加1。

3. 什么是 C/S 和 B/S 架构

B/S 又称为浏览器/服务器模式。比如各种网站,jupyter notebook 等。

优点:零安装,维护简单,共享性好。

缺点:安全性较差,个性化不足。

C/S 又称为客户端/服务器模式。比如微信客户端,Oracle 客户端等。

优点:安全性好,数据传输较快,稳定。

缺点:对 PC 机操作系统等有要求,当客户端较多时,服务器端负载较大。

4. TCP 和 UDP 的区别

TCP 和 UDP 都是 OSI 模型中运输层的协议。TCP 提供可靠的通信传输,而 UDP 则常被用于广播和细节控制交给应用的通信传输。

UDP 不提供复杂的控制机制,利用 IP 提供面向无连接的通信服务。

TCP 充分实现了数据传输时各种控制功能,可以进行丢包的重发控制,还可以对次序乱掉的分包进行顺序控制。

TCP 应用:FTP 传输,点对点短信等。

UDP 应用:媒体流等。

5. 局域网和广域网

广域网(WAN,Wide Area Network)也称远程网(long haul network )。通常跨接很大的物理范围,所覆盖的范围从几十公里到几千公里,它能连接多个城市或国家,或横跨几个洲并能提供远距离通信,形成国际性的远程网络。

域网(Local Area Network,LAN)是指在某一区域内由多台计算机互联成的计算机组。一般是方圆几千米以内。局域网可以实现文件管理、应用软件共享、打印机共享、工作组内的日程安排、电子邮件和传真通信服务等功能。局域网是封闭型的,可以由办公室内的两台计算机组成,也可以由一个公司内的上千台计算机组成。

6. arp 协议

ARP(Address Resolution Protocol)即地址解析协议, 用于实现从 IP 地址到 MAC 地址的映射,即询问目标 IP 对应的 MAC 地址。

7. 什么是 socket?简述基于 TCP 协议的套接字通信流程。

socket 是对 TCP/IP 协议的封装,它的出现只是使得程序员更方便地使用 TCP/IP 协议栈而已。socket 本身并不是协议,它是应用层与 TCP/IP 协议族通信的中间软件抽象层,是一组调用接口(TCP/IP网络的API函数)。

“TCP/IP 只是一个协议栈,就像操作系统的运行机制一样,必须要具体实现,同时还要提供对外的操作接口。

这个就像操作系统会提供标准的编程接口,比如win32编程接口一样。TCP/IP 也要提供可供程序员做网络开发所用的接口,这就是 Socket 编程接口。”

Server:

1import socket
 2import threading
 3def tcplink(sock, addr):
 4    print('Accept new connection from %s:%s...' % addr)
 5    sock.send(b'Welcome!')
 6    while True:
 7        data = sock.recv(1024)
 8        time.sleep(1)
 9        if not data or data.decode('utf-8') == 'exit':
10            break
11        sock.send(('Hello, %s!' % data.decode('utf-8')).encode('utf-8'))
12    sock.close()
13    print('Connection from %s:%s closed.' % addr)
14
15s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
16# 监听端口:
17s.bind(('127.0.0.1', 9999))
18s.listen(5)
19print('Waiting for connection...')
20while True:
21    # 接受一个新连接:
22    sock, addr = s.accept()
23    # 创建新线程来处理TCP连接:
24    t = threading.Thread(target=tcplink, args=(sock, addr))
25    t.start()

Client:

1import socket
 2s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 3# 建立连接:
 4s.connect(('127.0.0.1', 9999))
 5# 接收欢迎消息:
 6print(s.recv(1024).decode('utf-8'))
 7for data in [b'Michael', b'Tracy', b'Sarah']:
 8    # 发送数据:
 9    s.send(data)
10    print(s.recv(1024).decode('utf-8'))
11s.send(b'exit')
12s.close()

例子来源于廖雪峰的官网

8. 简述 进程、线程、协程的区别以及应用场景

进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。每个进程都有自己的独立内存空间,不同进程通过进程间通信来通信。

线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。

协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。

多进程:密集 CPU 任务,需要充分使用多核 CPU 资源(服务器,大量的并行计算)的时候,用多进程。

缺陷:多个进程之间通信成本高,切换开销大。

多线程:密集 I/O 任务(网络 I/O,磁盘 I/O,数据库 I/O)使用多线程合适。

缺陷:同一个时间切片只能运行一个线程,不能做到高并行,但是可以做到高并发。

协程:又称微线程,在单线程上执行多个任务,用函数切换,开销极小。不通过操作系统调度,没有进程、线程的切换开销。

缺陷:单线程执行,处理密集 CPU 和本地磁盘 IO 的时候,性能较低。处理网络 I/O 性能还是比较高。

多线程请求返回是无序的,哪个线程有数据返回就处理哪个线程,而协程返回的数据是有序的。

9. 如何使用线程池和进程池

池的功能是限制启动的进程数或线程数。当并发的任务数远远超过了计算机的承受能力时,即无法一次性开启过多的进程数或线程数时,就应该用池的概念将开启的进程数或线程数限制在计算机可承受的范围内。

多进程

1from multiprocessing import Pool
 2import os
 3import time
 4import random
 5
 6
 7def long_time_task(name):
 8    print('Run task %s (%s)...' % (name, os.getpid()))
 9    start = time.time()
10    time.sleep(random.random() * 3)
11    end = time.time()
12    print('Task %s runs %0.2f seconds.' % (name, (end - start)))
13
14
15def test_pool():
16    print('Parent process %s.' % os.getpid())
17    p = Pool(4)
18    for i in range(5):
19        p.apply_async(long_time_task, args=(i,))
20    print('Waiting for all subprocesses done...')
21    p.close()
22    p.join()
23    print('All subprocesses done.')
24
25
26if __name__ == '__main__':
27    test_pool()

output

1Parent process 32432.
 2Waiting for all subprocesses done...
 3Run task 0 (15588)...
 4Run task 1 (32372)...
 5Run task 2 (12440)...
 6Run task 3 (18956)...
 7Task 2 runs 0.72 seconds.
 8Run task 4 (12440)...
 9Task 3 runs 0.82 seconds.
10Task 1 runs 1.21 seconds.
11Task 0 runs 3.00 seconds.
12Task 4 runs 2.95 seconds.
13All subprocesses done.

apply_async(func[, args[, kwds]]) :使用非阻塞方式调用 func(并行执行,堵塞方式必须等待上一个进程退出才能执行下一个进程),args 为传递给 func 的参数列表,kwds 为传递给 func 的关键字参数列表;

close():关闭 Pool,使其不再接受新的任务;

terminate():不管任务是否完成,立即终止;

join():主进程阻塞,等待子进程的退出, 必须在 close 或 terminate 之后使用;

也可以使用 concurrent.futures 模块提供的功能来实现

1def test_future_process():
 2    print('Parent process %s.' % os.getpid())
 3    p = ProcessPoolExecutor(4)
 4    for i in range(5):
 5        p.submit(long_time_task, i)
 6    p.shutdown(wait=True)
 7    print('Finish')
 8
 9
10if __name__ == '__main__':
11    # test_pool()
12    test_future_process()

output

1Parent process 29368.
 2Run task 0 (32148)...
 3Run task 1 (31552)...
 4Run task 2 (24012)...
 5Run task 3 (29408)...
 6Task 2 runs 0.52 seconds.
 7Run task 4 (24012)...
 8Task 3 runs 0.86 seconds.
 9Task 1 runs 1.81 seconds.
10Task 0 runs 1.83 seconds.
11Task 4 runs 1.69 seconds.
12Finish

多线程

1def sayhello(a):
 2    print("hello: " + a)
 3    start = time.time()
 4    time.sleep(random.random() * 3)
 5    end = time.time()
 6    print('Task %s runs %0.2f seconds.' % (a, (end - start)))
 7
 8
 9def test_future_thread():
10    seed = ["a", "b", "c", "d"]
11    start = time.time()
12    with ThreadPoolExecutor(3) as executor:
13        for i in seed:
14            executor.submit(sayhello, i)
15    end = time.time()
16    print("Thread Run Time: " + str(end - start))

output

1hello: a
2hello: b
3hello: c
4Task a runs 0.40 seconds.
5hello: d
6Task b runs 0.56 seconds.
7Task d runs 1.70 seconds.
8Task c runs 2.92 seconds.
9Thread Run Time: 2.9195945262908936

可以看出,由于是创建了限制为3的线程池,所以只有三个任务在同时执行。

10. 进程之间如何进行通信

1def write(q):
 2    print("write(%s), 父进程为(%s)" % (os.getpid(), os.getppid()))
 3    for i in "Python":
 4        print("Put %s to Queue" % i)
 5        q.put(i)
 6
 7
 8def read(q):
 9    print("read(%s), 父进程为(%s)" % (os.getpid(), os.getppid()))
10    for i in range(q.qsize()):
11        print("read 从 Queue 获取到消息: %s" % q.get(True))
12
13
14def test_commun():
15    print("(%s) start" % os.getpid())
16    q = Manager().Queue()
17    pw = Process(target=write, args=(q, ))
18    pr = Process(target=read, args=(q, ))
19    pw.start()
20    pr.start()
21    pw.join()
22    pr.terminate()

output

1(23544) start
 2write(29856), 父进程为(23544)
 3Put P to Queue
 4Put y to Queue
 5Put t to Queue
 6Put h to Queue
 7Put o to Queue
 8Put n to Queue
 9read(25016), 父进程为(23544)
10read 从 Queue 获取到消息: P
11read 从 Queue 获取到消息: y
12read 从 Queue 获取到消息: t
13read 从 Queue 获取到消息: h
14read 从 Queue 获取到消息: o
15read 从 Queue 获取到消息: n

Python 的 multiprocessing 模块包装了底层的机制,提供了 Queue、Pipes 等多种方式来交换数据。

11. 进程锁和线程锁

进程锁:是为了控制同一操作系统中多个进程访问一个共享资源,只是因为程序的独立性,各个进程是无法控制其他进程对资源的访问的,但是可以使用本地系统的信号量控制。

信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。

线程锁:当多个线程几乎同时修改一个共享数据的时候,需要进行同步控制,线程同步能够保证多个线程安全的访问竞争资源(全局内容),最简单的同步机制就是使用互斥锁。

某个线程要更改共享数据时,先将其锁定,此时资源的状态为锁定状态,其他线程就能更改,直到该线程将资源状态改为非锁定状态,也就是释放资源,其他的线程才能再次锁定资源。互斥锁保证了每一次只有一个线程进入写入操作。从而保证了多线程下数据的安全性。

12. 什么是并发和并行

并行:多个 CPU 核心,不同的程序就分配给不同的 CPU 来运行。可以让多个程序同时执行。

并发:单个 CPU 核心,在一个时间切片里一次只能运行一个程序,如果需要运行多个程序,则串行执行。

13. threading.local 的作用

ThreadLocal 叫做线程本地变量,ThreadLocal 在每一个变量中都会创建一个副本,每个线程都可以访问自己内部的副本变量,对其他线程时不可见的,修改之后也不会影响到其他线程。

14. 什么是域名解析

域名解析是指将域名解析为 IP 地址。也有反向的“逆解析”,将 IP 通过 DNS 服务器查找到对应的域名地址。

DNS 是域名系统 (Domain Name System),域名系统为因特网上的主机分配域名地址和 IP 地址。用户使用域名地址,该系统就会自动把域名地址转为 IP 地址。

15. LVS 是什么及作用

LVS 是 Linux Virtual Server 的简写,意即 Linux 虚拟服务器,是一个虚拟的服务器集群系统,即负载均衡服务器。

LVS 工作模式分为 NAT 模式、TUN 模式、以及 DR 模式。

16. Nginx 的作用

Nginx 主要功能:1、反向代理 2、负载均衡 3、HTTP 服务器(包含动静分离) 4、正向代理

正向代理:某些情况下,代理用户去访问服务器,需要手动设置代理服务器的 IP 和端口号。

反向代理:是用来代理服务器的,代理要访问的目标服务器。代理服务器接受请求,然后将请求转发给内部网络的服务器(集群化),并将从服务器上得到的结果返回给客户端,此时代理服务器对外就表现为一个服务器。

负载均衡服务器类似于 LVS

HTTP 服务器类似于 Tomcat 等。

17. keepalived 及 HAProxy

HAProxy 提供高可用性、负载均衡,以及基于 TCP 和 HTTP 的应用程序代理。

keepalived 是集群管理中保证集群高可用的一个服务软件,其功能类似于 heartbeat,用来防止单点故障。

18. 什么是 rpc

RPC 是指远程过程调用,也就是说两台服务器 A,B,一个应用部署在 A 服务器上,想要调用 B 服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。

19. 从浏览器输入一个网址到展示网址页面的过程

  1. 浏览器通过 DNS 服务器查找到域名对应的 IP 地址
  2. 浏览器给 IP 对应的 web 服务器发送 HTTP 请求
  3. web 服务器接收到 HTTP 请求后,返回响应给浏览器
  4. 浏览器接收到响应后渲染页面

20. 什么是cdn

CDN 的全称是 Content Delivery Network,即内容分发网络。CDN 是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。CDN 的关键技术主要有内容存储和分发技术。

相关文章
|
7天前
|
API 数据库 数据安全/隐私保护
Flask框架在Python面试中的应用与实战
【4月更文挑战第18天】Django REST framework (DRF) 是用于构建Web API的强力工具,尤其适合Django应用。本文深入讨论DRF面试常见问题,包括视图、序列化、路由、权限控制、分页过滤排序及错误处理。同时,强调了易错点如序列化器验证、权限认证配置、API版本管理、性能优化和响应格式统一,并提供实战代码示例。了解这些知识点有助于在Python面试中展现优秀的Web服务开发能力。
22 1
|
6天前
|
前端开发 测试技术 C++
Python自动化测试面试:unittest、pytest与Selenium详解
【4月更文挑战第19天】本文聚焦Python自动化测试面试,重点讨论unittest、pytest和Selenium三大框架。unittest涉及断言、TestSuite和覆盖率报告;易错点包括测试代码冗余和异常处理。pytest涵盖fixtures、参数化测试和插件系统,要注意避免过度依赖unittest特性。Selenium的核心是WebDriver操作、等待策略和测试报告生成,强调智能等待和元素定位策略。掌握这些关键点将有助于提升面试表现。
20 0
|
6天前
|
数据采集 存储 JSON
Python爬虫面试:requests、BeautifulSoup与Scrapy详解
【4月更文挑战第19天】本文聚焦于Python爬虫面试中的核心库——requests、BeautifulSoup和Scrapy。讲解了它们的常见问题、易错点及应对策略。对于requests,强调了异常处理、代理设置和请求重试;BeautifulSoup部分提到选择器使用、动态内容处理和解析效率优化;而Scrapy则关注项目架构、数据存储和分布式爬虫。通过实例代码,帮助读者深化理解并提升面试表现。
13 0
|
7天前
|
SQL 中间件 API
Flask框架在Python面试中的应用与实战
【4月更文挑战第18天】**Flask是Python的轻量级Web框架,以其简洁API和强大扩展性受欢迎。本文深入探讨了面试中关于Flask的常见问题,包括路由、Jinja2模板、数据库操作、中间件和错误处理。同时,提到了易错点,如路由冲突、模板安全、SQL注入,以及请求上下文管理。通过实例代码展示了如何创建和管理数据库、使用表单以及处理请求。掌握这些知识将有助于在面试中展现Flask技能。**
13 1
Flask框架在Python面试中的应用与实战
|
8天前
|
数据可视化 Python
Python模型评估与选择:面试必备知识点
【4月更文挑战第17天】本文深入探讨了Python模型评估与选择在面试中的关键点,包括性能度量、过拟合与欠拟合识别、模型比较与选择、模型融合和偏差-方差权衡。强调了避免混淆评估指标、忽视模型验证和盲目追求高复杂度模型的常见错误,并提供相关代码示例,如交叉验证、网格搜索和超参数调优。通过理解这些概念和技巧,可在面试中展示出色的数据科学能力。
31 12
|
8天前
|
机器学习/深度学习 搜索推荐 Python
Python特征工程面试:从理论到实践
【4月更文挑战第17天】本文探讨了Python在数据科学面试中的特征工程,涵盖基础概念如特征选择和提取,实战技能如缺失值和异常值处理,以及特定场景应用。强调避免过度依赖单一方法,忽视数据分布和相关性,以及保持特征工程的可解释性。提供代码示例展示了处理缺失值、标准化、特征选择和异常值检测的基本操作。建议结合业务理解,灵活运用多种方法并注重模型解释性。
23 9
|
8天前
|
数据采集 机器学习/深度学习 数据挖掘
Python数据清洗与预处理面试题解析
【4月更文挑战第17天】本文介绍了Python数据清洗与预处理在面试中的常见问题,包括Pandas基础操作、异常值处理和特征工程。通过示例代码展示了数据读取、筛选、合并、分组统计、离群点检测、缺失值和重复值处理、特征缩放、编码、转换和降维。强调了易错点,如忽视数据质量检查、盲目处理数据、数据隐私保护、过度简化特征关系和忽视模型输入要求。掌握这些技能和策略将有助于在面试中脱颖而出。
24 8
|
8天前
|
缓存 自然语言处理 数据处理
Python自然语言处理面试:NLTK、SpaCy与Hugging Face库详解
【4月更文挑战第16天】本文介绍了Python NLP面试中NLTK、SpaCy和Hugging Face库的常见问题和易错点。通过示例代码展示了如何进行分词、词性标注、命名实体识别、相似度计算、依存关系分析、文本分类及预训练模型调用等任务。重点强调了理解库功能、预处理、模型选择、性能优化和模型解释性的重要性,帮助面试者提升NLP技术展示。
28 5
|
8天前
|
NoSQL MongoDB Redis
Python与NoSQL数据库(MongoDB、Redis等)面试问答
【4月更文挑战第16天】本文探讨了Python与NoSQL数据库(如MongoDB、Redis)在面试中的常见问题,包括连接与操作数据库、错误处理、高级特性和缓存策略。重点介绍了使用`pymongo`和`redis`库进行CRUD操作、异常捕获以及数据一致性管理。通过理解这些问题、易错点及避免策略,并结合代码示例,开发者能在面试中展现其技术实力和实践经验。
133 8
Python与NoSQL数据库(MongoDB、Redis等)面试问答
|
8天前
|
SQL 关系型数据库 MySQL
Python与MySQL数据库交互:面试实战
【4月更文挑战第16天】本文介绍了Python与MySQL交互的面试重点,包括使用`mysql-connector-python`或`pymysql`连接数据库、执行SQL查询、异常处理、防止SQL注入、事务管理和ORM框架。易错点包括忘记关闭连接、忽视异常处理、硬编码SQL、忽略事务及过度依赖低效查询。通过理解这些问题和提供策略,可提升面试表现。
29 6