刷遍全网Python面试题计划

  • 看完面经和最近的面试我自闭了,想进大厂不是那么容易的,需要扎实的基础
  • 本来以为Python学的不错但是和企业真正的大牛还差的很远,从今天开始刷遍全网Python面试题计划

  1. 迭代器生成器是如何实现迭代的?

首先生成器是特殊的迭代器,迭代器必须实现__iter__和__next__方法,每次通过next()不断循环迭代,生成器通过yield关键字来实现,返回一个生成器,cpu会进行一个挂起操作,调用的时候会执行。如果最后没有元素会抛出一个异常

  1. list的实现

Python中的List是基于数组封装的一种高级数据结构,里面的元素可以是任意类型(泛型),其是一个可变的类型,但是每次初始化会分配固定的内存空间,是因为其中包含了一个指向可变内存区域(堆)的指针,每次数组的扩容会成倍增长,和Go语言大额切片一样,List中的每一个元素也保存了一个指向一块内存区域的引用,list是一个可迭代对象,通过工厂函数创建生成

  1. import包的过程

Python在做大项目必然会解除包和模块的概念,通常将一个py文件成为模块,而带有__init__的文件夹称为包,在import包或文件的过程中会执行该包下的__init__方法来初始化一些事情,可以print东西,可以执行一些函数也可以实例化一些方法通过__init__导入进来等等,根据实际的业务需求。但是通常建议是使用from import的语句来导入,用什么导入,会节省空间。在大型项目通常的做法是在__init__文件夹中将模块的接口暴露出来,模块中通过__all__将接口暴露出来,在from import *的导出过程中_func是不会暴露的。相当于Java中的protect类访问级别,双__是完全私有的,子类也无法访问。

Python会默认从sys.path中寻找包名,没有就会抛错,如果想要导入可以

import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
  1. Python中的装饰器:必问

Python中的装饰器分为函数装饰器和类装饰器,并提供了@的语法糖,装饰器的本质是因为在Python中一切皆为对象,可以通过参数进行传递,就是所谓的函数、类是一等公民

# 基于函数的装饰器
from functools import wraps


def bar(func):
    # 加上这个装饰器函数名不会被改变
    wraps(func)
    # inner函数的参数要和foo函数的参数保持一致

    def inner(*args, **kwargs):
        # 该函数后foo的主逻辑才会执行
        return func(*args, **kwargs)
    return inner

@bar
def foo():
    print("something")

foo()
# 基于类的装饰器
class Foo:
    def __init__(self, func):
        self.func = func

    def __call__(self, param, *args, **kwargs):
        self.func(param, *args, **kwargs)
        print(param)


@Foo
def bar(param: int):
    print("something")


bar(1)
  1. 菱形继承

这是Python多继承的特性,在Java等语言中不支持多继承,因为多继承会带来效率问题,使项目变得复杂不好理解。新式类中默认深度优先,经典类中为广度优先

  1. Python的垃圾回收机制

采用引用基数,因为Python中的所有 = 都可以看做是引用,当一个对象引用为0时会触发GC,通过标记清除和分代回收提升效率并且解决循环引用的问题。标记 清除首先确定跟节点标记为黑色,从跟节点出发,可达的节点标记为灰色,不可达的为白色,最终将灰色全部置为黑色,将白色的清除掉。

Google V8引擎的gc原理:

  1. mysql b+tree

说起索引原理要从msyql的引擎讲起,mysql的架构提供了可插拔的引擎机制,最常用的是innodb和myisam,innodb和myisam的文件组织是不同的,其原理也是不同的,myisam的文件结构为:frm建表语句、myd数据文件、myi索引文件,innodb:frm建表语句、idb:索引加数据文件。innodb称为聚簇索引,myisam称之为非聚簇索引。在innodb中的索引是一颗颗的b+tree,至于为什么使用b+tree稍后进行分解,索引分为主键索引和普通索引(也叫二级索引)主键索引树的结构为根节点存放指针,叶子节点存放数据,但是非主键索引树叶子节点存放的是主键的id,如果查询的索引为普通索引会再到主键索引树插一下称为回表操作。而myisam不同,因为是非聚簇索引,索引树和数据放在不同的文件中,索引树的叶子节点放的是数据的内存地址,拿到内存地址再进行访问,通常这种方式的查询效率较高,故在读写分离中将从表设置为myisam引擎,之所以innodb只在主键索引树的叶子节点存放数据是为了节省空间考虑。

再来说说这么多数据结构为什么采用b+tree,既然是索引需要很高的查询性能,首先想到的是hashTable,虽然hashTable有着O(1)的查询效率,但是存在hash冲突问题(解决方法为拉出来一个链表),其次无法很好的进行范围查询,仅仅是等值查询效率高,所以pass了;那么二叉搜索树行不行呢?毕竟本身有序,查询的时间复杂度为O(logn),看似可以但是在极端的情况下,顺序插入数据会退化成链表,所以也pass了;接下来是红黑树:增加了自旋的操作保持平衡,但是在顺序插入的情况下高度还是太高,不太理想;接下来是AVL树登场,解决了红黑树的问题不过树高还是比较高,会多次的进行磁盘io,不行;综上所属最合适的结构是B树,树高4,将1 2层都放在内存中只需要2次的磁盘io就可以查到数据,效果理想,不过B树的节点存放数据太占空间,故改进成B+Tree,节点只存放指针,大大节省了空间!

  1. wsgi

web server网关接口可以看做是一种规范和约定,类似于前后端分离约定的接口,大家都按照这个接口实现,通过采用uwsgi和gunicorn来部署生产级别的项目,伴随着异步的兴起,出现了新的更高效的接口规范ASGI,Django3.0也开始支持,生态也出现了很多异步的框架FastAPI Sanic等,成熟的服务器为uvicorn,也是部署首选。

9.Python的 异步和协程

协程又称为轻量级线程在操作系统的用户态有用户调度,线程则在内核态由操作系统调度,协程占用的系统资源比较少,一台机器可以起上w个协程,通常采用协程+时间循环的方式编程,在Python的3.5版本将aysncio加入到了标准库,之前由吉多亲自操刀贡献了代码。当然有更快的方式uvloop。

  1. 归并、快排、堆排序

pass

  1. BIO、NIO、select、poll、epoll

BIO又称阻塞IO通常用多线程方式来解决阻塞的效率问题,但是多线程上下文在内核态的切换开销太大故出现了NIO模型,通常采用单线程+实现循环的方式,select、poll、epoll是一个逐渐升级的过程,在linux操作系统中一切皆为文件,文件有描述符,三种方式只是优化寻找文件描述符的不同,最终的epoll对资源的利用率更少性能更优,在redis、nginx中都应用了epoll,可以通过trace命令来查看启动的执行过程,但是两者还略有不同,nginx会阻塞住监听,redis会轮训,导致文件逐渐增大因为redis是单线程模型

  1. mysql联合索引、覆盖索引、索引下推

联合索引支持最左前缀原则和mysql5.7引入的虚拟字段意思是比如将人名的性和年龄创建联合索引可以增加性的虚拟字段,由姓名字段自动生成,可以优化性能。覆盖索引和索引下推

  1. Python中的eval

虽然是个神器但是不能乱用,有安全性问题

  1. 虚拟内存

虚拟内存是对主存的一个抽象,通过虚拟寻址的方式间接引用主存

  1. TCP和UDP的区别

TCP是面向连接的,UDP是面向非连接的,TCP是可靠的,UDP是不可靠的。TCP有拥塞控制,UDP支持1对1,1对多,多对多

  1. TCP断开的过程,连接过程,syn攻击,拥塞控制和流量控制

四次挥手:fin ack fin ack报文但是不要这么回答。fin_wait,close_wait,fin_wait,last_ack(等待客户端最后一个ack),time_wait,closed,为什么time_wait之后不关闭,等2TTLS,因为要确保服务端收到的ack,如果没收到会重新发送fin。
三次握手:syn ,ack+syn,ack。也不要这么回答,首先客户端发送syn报文测试服务端的接受能力,服务端收到后又发送syn报文测试客户端的接受能力,都没问题最后ack进入established状态。
在syn队列满了之后会发送一个syn cookie有就处理连接,限制syn并发次数。
拥塞控制:因为发送数据的一方需要等待接受方的ack响应,但是有可能网络传输比较拥堵,故有拥塞控制,通常采用慢启动的方式,慢慢增加发送数据包的量,先指数增大,到达一个值线性增加,如果到达阈值则置为一半。快重传:当12 (3丢失)456,当发送方连续收到3个重复的确认(456的确认)则认为3丢失,就立刻重传3,不用等到重传计时器时间到期。快恢复:因为能收到3个连续的确认证明没有网络拥塞,则将把ssthresh设为max的一半成为新阈值
流量控制:解决发送方和接收方速率不一致的问题,产生了发送窗口和接受窗口的概念,在现在的TCP协议中窗口大小会动态调整,接受窗口会告诉发送端自己的窗口大小,如果丢失会定时重传机制,通常接受窗口>=发送窗口

  1. Python中的GIL锁

在同一时间内Python解释器只允许一个进程中的一个线程占有CPU资源

  1. 中断和系统调用

我们不能直接操作内核态的东西这样很不安全,故产生了系统调用,开放某些接口,中断分为软中断和硬中断

  1. Python中的全局变量和局部变量都保存在哪

v8引擎是有个全局执行上下文概念和局部执行上下文概念

  1. LRU算法

采用hashTable+DoubleLinkedList

from collections import OrderedDict

class LRUCache:
    def __init__(self, cap):
        self.dic = OrderedDict()
        self.cap = cap
    
    def get(self, key):
        if key not in self.dict:
            return - 1
        v = self.dic.pop(key)
        self.key = v
        return v
    def put(self, key, value):
        if key in self.dic:
            self.dic.pop(key)
        else:
            if self.cap > 0:
                self.cap += 1
            else:
                self.dic.popitem(last=False)
        self.dic[key] = value
  1. rpc

pass

  1. http在传输一个二进制文件的所有过程

先到数据链路层封装城以太网帧,到网络层ip协议,到传输层tcp封装tcp报文,再到应用层http封装报文格式通过网卡发送出去,解包反之

  1. Python2和Python3的区别

字符的编码不同,3默认都是unicode,2中st是ascii,range和xrange一个返回数组,一个返回迭代器,print也不同,class也不同

  1. Python中元组和列表的区别

通常元组存放静态数据比如经纬度,列表存放可变数据,但是初始化会是相同的内存,因为其中维护了一个指向可变区域的指针,通常set比list效率略高一点

  1. Python中的深浅拷贝

深拷贝会递归的进行拷贝,浅拷贝如果遇到列表套列表、元组、字典就不行了,深拷贝会重新创建数据

  1. Python的多态

默认就支持多态的语言,不同的对象实现了相同的接口,duck type

  1. read、readline、readlines

read读取整个文件,可以指定一个size,readlines逐行读取返回一个列表,readline一般不用

  1. Python的内存管理机制

Python中的大内存和小内存,以256k为界限,小内存使用内存池来分配,调优手段:手动回收大力,调高垃圾回收阈值

  1. map,reduce,filter的使用

map:对可迭代对象中的每一个对象进行操作
reduce:两两操作
filter:过滤条件

  1. Python中的反射

getattr,setattr用法

  1. 正则匹配汉字

[\u4E00-\u9FA5]
\d:匹配数字,\D匹配非数字
\w:匹配单词字符
+:一次或多次
?:0次或一次
*:0词或多次

import re

target = "崔贺然 1213232"
res = re.findall("[\u4E00-\u9FA5]", target)
print(res)
  1. Python中的super

只在新式类中有,解决多重继承的问题

  1. TCP断开什么时候进入time_wait阶段?

主动断开的一端进入time_wait的状态,被动额一方进入closed状态,fin关闭关闭,ack收到,客户端进入time_wait状态,服务端进入closed状态,如果2MSL没有对端响应超时变成closed状态

  1. Mysql死锁

互斥条件、请求保持条件、不可剥夺条件、环路等待条件

  1. MySQL的MVCC

MySQL中有非常多的锁,在最早的数据库中只有读读之间是可以并发的,其他都不行。采用了多版本并发控制大大提高了innodb的并发度

  1. Python中的TLS

Threading Local Storage技术,threading.local()中实现,在多线程中全局变量保证不冲突的技术,TLS为每个线程维护一个与该线程绑定的副本而不是传参,但是并不意味着不需要加锁了,缺点是如果线程不退出副本不能被gc回收

  1. Python中的queue是什么东西

queue模块是用于多线程编程的先进先出FIFO数据结构,因为他是线程安全的,多个线程可以轻松访问一个实例

发布了140 篇原创文章 · 获赞 53 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_44291044/article/details/105101252