Bootstrap

Python基础常见面试题总结

在这里插入图片描述


1.深拷贝与浅拷贝

  • 浅拷贝是对地址的拷贝,只拷贝第一层,第一层改变的时候不会改变,内层改变才会改变。
  • 深拷贝是对值的拷贝,不会随着原数据的变化而变化
import copy
list = [[1, 2], 'feng', 66]
a = copy.copy(list)
b = copy.deepcopy(list)


# list[1]=4

# print(a)
# print(b)
#输出结果
# [[1, 2], 'feng', 66]
# [[1, 2], 'feng', 66]

list[0][0] = 8
print(a)
print(b)
#输出结果
# [[8, 2], 'feng', 66]
# [[1, 2], 'feng', 66]


import copy
list = ['feng',[1,2], 66]
a = copy.copy(list)
b = copy.deepcopy(list)

print(id(list[0]))
print(id(a[0]))
print(id(b[0]))
print(id(list[1]))
print(id(a[1]))
print(id(b[1]))
#输出结果
# 4306918640
# 4306918640
# 4306918640
# 4307415552
# 4307415552
# 4307500992

2.迭代器

    迭代器是一个可以记住遍历位置的对象,因此不会像列表那样一次性全部生成,而是可以等到用的时候才生成,因此节省了大量的内存资源。迭代器对象从集合中的第一个元素开始访问,直到所有的元素被访问完。迭代器有两个方法:iter()next()方法。

迭代器的优点: 省内存.它是一种通过延时创建的方式生成一个序列,只有在需要的时候才被创建。

__iter____next__执行流程:

  1. 先调用__iter()__,得到可迭代对象的迭代器
  2. 调用__next()__,将上一步得到的迭代器 进行取值
  3. 将上一步取出来的值赋值给变量
  4. 重复执行,所有数据都获取完毕后,会在下一次调用__next__的时候产生Stopiteration异常。只不过 for循环中自带了异常处理,当它遇到Stopiteration异常的时候,会自动结束for循环

示例代码:

# 自定义一个迭代器,求斐波那契序列

from itertools import islice
from collections import Iterator,Iterable

class Fib(object):
    def __init__(self):
        self.prev = 0
        self.curr = 1

    def __iter__(self):
        return self

    def __next__(self):
        value = self.curr
        self.curr += self.prev
        self.prev = value
        return value

# 迭代器对象
f = Fib()
print(isinstance(f,Iterator)) # true
L = list(islice(f,0,10)) # islice对可迭代对象进行切片
print(L)
# [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

3.生成器

    在Python中,一边循环一边计算的机制,称为生成器:generator。使用了 yield 的函数被称为生成器(generator)。

生成器仅仅保存了一套生成数值的算法,并且没有让这个算法现在就开始执行,而是什么时候调它,它什么时候开始计算一个新的值,并返回。生成器是一种特殊的迭代器,能够在遍历时暂停和继续执行,使用yield定义的函数不会执行,返回一个生成器对象。迭代时遇到yield会暂停并返回yield后面的值,保存当前的状态,下次迭代从上次暂停的地方继续执行,直到再次遇到yield,优势是内存占用少,节约资源。应用场景是遍历文件或网络数据流、CPU密集型计算、图像处理等。生成器可以逐个读取大文件,并且不必将整个文件加载到内存中,避免了内存消耗和IO操作的额外开销。

当我们创建一个生成器时,第一次调用只能用next() 或者 send(None) 来启动生成器实际上next()send() 在一定意义上作用是相似的,区别是 send() 可以传递yield表达式的值进去,而next() 不能传递特定的值,只能传递None进去。因此,我们可以看做c.next()c.send(None) 作用是一样的。nextsend都是调用yield生成值的函数,next是直接调用,send是先覆盖上一个yield返回值后再调用下一个yield生成值。


4.装饰器

    装饰器是在函数原有功能不变的基础上加上新的功能。底层采用闭包理念实现。内外函数嵌套,外层函数返回内层函数,内层函数引用外部函数的变量。

    装饰器分为有参装饰器和无参装饰器。当func被多个装饰器修饰时,装饰器会按照从下到上的顺序对func进行装饰,也就是最靠近函数的装饰器最先应用装饰,执行的时候从上往下执行

应用场景:权限验证,日志记录,接口执行时间统计,接口过滤

  • 权限验证:比如在后台管理系统中,在装饰器中检查用户权限,按照权限判断用户是否可以访问此接口;
  • 日志记录:在函数执行前后添加日志记录,用于监控函数的调用情况

代码示例:

# 多个装饰器装饰一个原函数

# 装饰器1:在调用原函数前输出 "装饰器1的开始";在调用原函数结束输出  "装饰器1的结束"
def outer1(f):
    def inner():
        print("装饰器1的开始")
        f()
        print("装饰器1的结束")
    return inner


# 装饰器2:在调用原函数前输出 "装饰器2的开始";在调用原函数结束输出  "装饰器2的结束"
def outer2(f):
    def inner():
        print("装饰器2的开始")
        f()
        print("装饰器2的结束")
    return inner


# 原函数 输出“我是原函数”
@outer2
@outer1
def func():
    print("我是原函数")
func()


# 总结:
# 装饰器的调用顺序:从下往上
# 装饰器的执行顺序:从上往下  -->执行结果

更多请点击:Python进阶:深入剖析闭包与装饰器的应用与技巧

5.进程、线程、协程

    进程是操作系统进行分配资源的基本单位,每个进程都有自己的内存空间和系统资源,进程之间不能共享内存,需要通过IPC(进程间通信:管道、队列、数据库)的方式进行通信。适合CPU密集型场景。

比如:并行计算、网络编程、爬虫、任务调度(定时任务、异步任务)、分布式计算。


    线程是程序执行的最小单元,一个进程可以有多个线程,同一个进程中的多个线程共享该进程中的全部资源,进程和线程都有五种状态:初始态、就绪态、执行态、阻塞态、终止态。适合IO密集型场景。
比如:多线程爬虫,多线程处理订单


    协程(Coroutine,又称微线程)是一种比线程更加轻量级的存在,协程不是被操作系统内核所管理,而完全是由程序所控制。

协程可以比作子程序,但执行过程中,子程序内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行。协程之间的切换不需要涉及任何系统调用或任何阻塞调用。

协程只在一个线程中执行,是子程序之间的切换,发生在用户态上。而且,线程的阻塞状态是由操作系统内核来完成,发生在内核态上,因此协程相比线程节省线程创建和切换的开销。

6.高阶函数

    高阶函数,它指的是一个函数可以接收另一个函数作为参数,或者将函数作为结果返回。

1.map(func, list):
	将func 应用于list中的每一个元素,返回一个迭代器

2.reduce(func, list):
  计算结果与下一个数据做累积计算,必须有两个参数
  from functools import reduce	

3.filter(func, list):
  过滤掉不符合条件的元素,返回一个filter对象,可用list()转换
  
4.sorted(iterable[,cmp][,key][,reverse])  
​    从iterable的项目中返回一个新的排序后的列表。可选的参数和列表方法与sort中的相同

list_sort = sorted(d,key=lambda x:x['a'],reverse=True)

7.魔法方法

    Python 的魔法方法(Magic Methods),也称为特殊方法或双下划线方法,用于定义类的行为和特性。这些方法在特定的情况下会被自动调用。

魔法方法的分类:

初始化与析构:如__init____new____del__等,控制对象的创建和销毁。
属性访问:如__getattr____getattribute____setattr____delattr__等,控制属性的访问和修改。
容器方法:如__len____getitem____setitem____delitem__等,支持容器类型的操作。
数值方法:如__add____sub____mul__等,支持数学运算。
字符串与序列表示:如__str____repr____format__等,提供对象的字符串表示。
上下文管理:如__enter____exit__等,支持with语句的上下文管理。
比较操作符:如__eq____ne____lt____le____gt____ge__等,支持对象比较。
其他:如__call____hash__等,提供额外的功能

以下是一些常用的 Python 魔法方法详解:

  • __new__: 用于创建对象实例时调用。它在对象实例化之前被调用,并且必须返回一个新的对象实例,在使用普通的类实例化对象时,默认会先调用 __new__ 方法来创建对象实例,然后再调用 __init__ 方法进行初始化。但是,我们可以重写 __new__ 方法以自定义对象的创建过程。
  • __init__(self, [...]): 构造函数,在创建对象时调用,用于初始化对象的属性。
  • __del__(self): 析构函数,在对象被销毁时调用,用于清理资源。
  • __str__(self): 字符串表示方法,在使用 str() 函数或 print() 函数打印对象时调用。
  • __repr__(self): 表示方法,返回对象的完整、可读性较好的字符串表示形式,在交互模式下会自动调用。
  • __len__(self): 长度方法,在使用 len() 函数获取对象长度时调用。
  • __getitem__(self, key): 索引访问方法,在通过索引访问对象时调用。
  • __setitem__(self, key, value): 索引赋值方法,在通过索引设置对象值时调用。
  • __iter__(self): 迭代器方法,返回一个对象的迭代器,在使用 for 循环遍历对象时调用。
  • __next__(self): 迭代器中的下一个元素方法,在迭代器中调用以获取下一个元素。
  • __eq__(self, other): 相等比较方法,判断对象是否相等时调用。
  • __lt__(self, other): 小于比较方法,判断对象是否小于另一个对象时调用。
  • __gt__(self, other): 大于比较方法,判断对象是否大于另一个对象时调用。

此外,还有很多其他的魔法方法可以用于自定义类的行为,比如数学运算相关的 __add____sub____mul____div____pow__ 等。详细的魔法方法列表可参考 Python 官方文档。通过定义这些方法,我们可以灵活地控制和定制类的操作和行为。

与python反射相关的魔法方法:
    反射使得程序能够在运行时动态地访问和操作对象的内部结构,包括属性和方法。

__getattr__(self, name):当访问的属性不存在时调用。适用于动态属性访问。
__getattribute__(self, name):访问任何属性时调用,拦截所有对对象属性的访问。谨慎重写,因为它可能导致无限递归。
__setattr__(self, name, value):用于设置或更新对象的属性。当你为对象的属性赋值时,Python会自动调用这个方法。
__delattr__(self, name):删除属性时调用。当使用del语句或delattr函数删除对象的属性时,如果类中定义了__delattr__方法,Python会调用这个方法而不是直接删除属性。
__dir__(self):获取对象的所有属性名和方法名列表,用于dir()函数

8.python垃圾回收机制

在Python中,垃圾回收(Garbage Collection)是一种自动化的内存管理机制,它通过检测和清除不再使用的内存来释放内存资源,从而提高程序的性能和效率。

Python使用了一种称为"引用计数"的策略来跟踪对象的引用次数。每当一个对象被引用时,其引用计数就会增加;当它不再被引用时,引用计数就会减少。 当一个对象的引用计数达到零时,该对象就成为垃圾对象,将被垃圾回收机制清理掉。

除了引用计数,Python还使用了其他垃圾回收策略来处理一些特殊情况,会在下面介绍。

  1. 标记-清除(Mark and Sweep): 当引用计数策略无法解决循环引用问题时,Python使用标记-清除算法来检测和清除不再使用的对象。该算法的原理是,首先从根对象(如全局变量、函数调用栈等)开始标记所有可访问的对象,然后清除那些未标记的对象

  2. 分代回收(Generational Collection): Python中的对象按照其年龄进行分组,被分为三代:0代、1代和2代。大部分新创建的对象属于0代,当一个对象经过一次垃圾回收后仍然存活,它会被移到下一代。分代回收机制的原理是,根据经验观察到的现象,大部分对象在短时间内就会变成垃圾,而那些存活得更久的对象更可能长时间存活下去。因此,分代回收机制可以根据对象的存活情况进行不同频率的垃圾回收,提高效率。

  3. 内存池机制(Memory Pools): Python使用内存池来管理小块内存的分配和释放。内存池是一块连续的内存空间,包含多个大小固定的块,每个块都可以独立分配给一个对象。这个机制显著减少了内存碎片的产生,并且提高了内存分配的效率。

需要注意的是,Python的垃圾回收是自动进行的,开发者不需要显式地调用垃圾回收函数。垃圾回收机制是Python解释器的一部分,它会在适当的时候自动运行,确保内存资源的有效利用。

在这里插入图片描述

;