python八股文

保留字段

def  # 用于定义一个函数
if  # 条件语句,用于根据条件执行代码块
elif  # “else if”的简写,多个条件分支中的一个
and  # 逻辑与操作符,两个操作数都为真时,结果才为真
not  # 逻辑非操作符,将布尔值取反
or  # 逻辑或操作符,只要任一操作数为真,结果就为真
assert  # 调试工具,用于验证条件,如果条件为假,触发异常
try  # 用于定义异常处理块,尝试执行代码块
exec  # 动态执行 Python 代码,通常用于执行字符串或代码对象
finally  # 用于定义无论是否发生异常都会执行的代码块
for  # 用于迭代序列(如列表、元组、字符串)中的每个元素
in  # 检查某个值是否在序列(如列表、字符串)中
break  # 终止循环,即使循环条件仍为真
pass  # 空操作,占位符,表示什么都不做
class  # 用于定义一个类
from  # 从模块中导入指定的部分
print  # 输出信息到控制台(Python 2.x 中是一个关键字,Python 3.x 中是函数)
continue  # 跳过当前循环的剩余部分,并继续下一次循环
global  # 声明在函数内使用全局变量
raise  # 显式引发一个异常
return  # 从函数中返回结果
del  # 删除对象或变量
import  # 导入模块或模块中的指定部分
while  # 用于在条件为真时重复执行代码块
else  # 条件语句或循环结束后执行的代码块
is  # 判断两个对象是否引用自同一内存地址
with  # 用于简化资源管理(如文件操作)的上下文管理器
except  # 用于捕获并处理异常
lambda  # 用于创建匿名函数
yield  # 在生成器函数中生成值,并暂停函数的执行
def  # 用于定义一个函数
if  # 条件语句,用于根据条件执行代码块
elif  # “else if”的简写,多个条件分支中的一个
and  # 逻辑与操作符,两个操作数都为真时,结果才为真
not  # 逻辑非操作符,将布尔值取反
or  # 逻辑或操作符,只要任一操作数为真,结果就为真
assert  # 调试工具,用于验证条件,如果条件为假,触发异常
try  # 用于定义异常处理块,尝试执行代码块
exec  # 动态执行 Python 代码,通常用于执行字符串或代码对象
finally  # 用于定义无论是否发生异常都会执行的代码块
for  # 用于迭代序列(如列表、元组、字符串)中的每个元素
in  # 检查某个值是否在序列(如列表、字符串)中
break  # 终止循环,即使循环条件仍为真
pass  # 空操作,占位符,表示什么都不做
class  # 用于定义一个类
from  # 从模块中导入指定的部分
print  # 输出信息到控制台(Python 2.x 中是一个关键字,Python 3.x 中是函数)
continue  # 跳过当前循环的剩余部分,并继续下一次循环
global  # 声明在函数内使用全局变量
raise  # 显式引发一个异常
return  # 从函数中返回结果
del  # 删除对象或变量
import  # 导入模块或模块中的指定部分
while  # 用于在条件为真时重复执行代码块
else  # 条件语句或循环结束后执行的代码块
is  # 判断两个对象是否引用自同一内存地址
with  # 用于简化资源管理(如文件操作)的上下文管理器
except  # 用于捕获并处理异常
lambda  # 用于创建匿名函数
yield  # 在生成器函数中生成值,并暂停函数的执行

python语言的特性

动态强类型

Python的基本数据类型

  • Number(数字)(包括整型、浮点型、复数、布尔型等) #不可变
  • String(字符串)#不可变
  • Tuple(元组) #不可变
  • List(列表)#可变
  • Set(集合)#可变
  • Dictionary(字典)#可变

py作为后端语言的优缺点

  • 优点
    • 语言简单灵活,开发效率高
    • 胶水语言,轮子多,拥有Django这种的成熟web框架
  • 缺点
    • 执行效率低,性能不如其他语言
    • 动态语言,没有类型声明时就没有自动补全,而且很多问题要运行后才能发现

什么是duck type鸭子类型

鸭子类型更关注对象的行为,只要实现了某种接口方法就行,而不在乎是什么类型

monkey patch

monkey patch就是运行时替换对象,本质上是对象的重新赋值

*args,**kwargs的作用

用来处理可变参数,接收参数后,args会变成一个tuple,kwargs会变成一个dict

CPython GIL全局锁

引入GIL是因为CPython的内存管理并不是线程安全的,
为了保护多线程下对python对象的访问,每个线程在执行过程中都需要先获取GIL,保证同一时刻只有一个线程在执行代码
GIL使得python的多线程不能充分发挥多核CPU的性能,对CPU密集型程序的影响较大

生成器

生成器是一种特殊类型的迭代器,用于逐个生成值,而不是一次性返回所有值。生成器通过使用 yield 关键字来实现,这使得它们在生成大量数据时更高效,因为生成器不会一次性将所有值存储在内存中。
生成器通常通过函数定义,并使用 yield 关键字代替 return 来返回值。每次调用生成器的 __next__() 方法(通常是通过 next() 函数或for 循环隐式调用)时,生成器函数会暂停执行,并返回当前的 yield 表达式的值。在下一次调用时,生成器会从上次暂停的地方继续执行。

生成器的使用场景

  • 处理大数据: 生成器特别适合处理需要逐步生成或计算的数据,比如读取大文件、一行一行地处理数据。
  • 无限序列: 生成器可以用于生成无限长的序列,比如斐波那契数列、素数序列等。
  • 管道机制: 生成器可以在处理数据流时充当管道的一部分,一步一步处理数据,而不是一次性将所有数据处理完

浅拷贝和深拷贝

  • 浅拷贝出来的是一个独立的对象,但它的子对象还是原对象中的子对象

  • 深拷贝会递归地拷贝原对象中的每一个子对象,因此拷贝后的对象和原对象互不相关。

# 浅拷贝示范
import copy
original_list = [1, 2, [3, 4]]
shallow_copied_list = copy.copy(original_list) #浅拷贝

shallow_copied_list[2][0] = 'changed'

print(original_list)         # 输出: [1, 2, ['changed', 4]]
print(shallow_copied_list)   # 输出: [1, 2, ['changed', 4]]
# 浅拷贝示范
import copy
original_list = [1, 2, [3, 4]]
shallow_copied_list = copy.copy(original_list) #浅拷贝

shallow_copied_list[2][0] = 'changed'

print(original_list)         # 输出: [1, 2, ['changed', 4]]
print(shallow_copied_list)   # 输出: [1, 2, ['changed', 4]]

迭代器与可迭代对象的区别

  • 可迭代对象类,必须自定义__iter__()魔法方法,range,list类的实例化对象都是可迭代对象

  • 迭代器类,必须自定义__iter__()和__next__()魔法方法,用iter()函数可以创建可迭代对象的迭代器

my_list = [1, 2, 3]
for item in my_list:  # my_list 是一个可迭代对象
    print(item)
    
my_list = [1, 2, 3]
my_iterator = iter(my_list)  # 使用 iter() 函数从可迭代对象中获取迭代器

print(next(my_iterator))  # 输出:1
print(next(my_iterator))  # 输出:2
print(next(my_iterator))  # 输出:3
# 如果再次调用 next(my_iterator),会抛出 StopIteration 异常
my_list = [1, 2, 3]
for item in my_list:  # my_list 是一个可迭代对象
    print(item)
    
my_list = [1, 2, 3]
my_iterator = iter(my_list)  # 使用 iter() 函数从可迭代对象中获取迭代器

print(next(my_iterator))  # 输出:1
print(next(my_iterator))  # 输出:2
print(next(my_iterator))  # 输出:3
# 如果再次调用 next(my_iterator),会抛出 StopIteration 异常

闭包

闭包就是一个嵌套函数,它的内部函数 使用了 外部函数的变量或参数,它的外部函数 返回了 内部函数

可以保存外部函数内的变量,不会随着外部函数调用完而销毁

python垃圾回收机制

引用计数为主,标记清除 和 分代回收为辅

引用计数机制是这样的:

  1. 当对象被创建,被引用,作为参数传递,存储到容器中,引用计数+1

  2. 当对象离开作用域,引用指向别的对象,del,从容器中移除,引用计数-1

  3. 当引用计数降为0,python就会自动回收该对象所在的内存空间,

  4. 但是引用计数无法解决循环引用的问题,所以引入了标记清除和分代回收机制

async和await的作用

  • async: 声明一个函数为异步函数,函数内只要有await就要声明为async
  • await: 搭配asyncio.sleep()时会切换协程,当切换回来后再继续执行下面的语句

dict查找原理

  • dict底层是哈希表,哈希表类似于C语言的数组,可以实现按索引随机访问
  • 但dict的key不一定是整数,需要先通过哈希函数,再经过取余操作转换为索引

list tuple的底层结构

  • list和tuple底层都是顺序表结构
  • list底层是可变数组,数组里存放的是元素对象的指针

set的底层结构

哈希表,key就是元素,value都是空

class方法 和 static方法的区别

  • class方法的第一个参数是cls,可以访问类属性,类方法
  • static方法和普通函数一样,只不过是放在类里,要通过类或实例来调用,但是它不能访问类和实例的属性和方法

装饰器

装饰器是一个接收函数作为参数的闭包函数
它可以在不修改函数内部源代码的情况下,给函数添加额外的功能

元类

  • 元类是创建类的类,type还有继承自type的类都是元类

  • 作用: 在类定义时(new, init)和 类实例化时(call) 可以添加自定义的功能

  • 使用场景: ORM框架中创建一个类就代表数据库中的一个表,但是定义这个类时为了统一需要把里面的类属性全部改为小写,这个时候就要用元类重写new方法,把attrs字典里的key转为小写

魔术方法

__new__作用

  • __new__ 是一个静态方法,用于创建一个新的实例。它的主要任务是分配内存并返回一个新的对象实例。
  • __new__ 方法会被调用以创建一个新的实例,然后将这个实例传递给 __init__ 方法进行初始化。

__init__作用

  • __init__ 是构造方法,用于初始化已经创建的实例。它设置对象的初始状态,通常用于初始化实例变量。
  • __init__ 方法在 __new__ 方法之后被调用,用于对新创建的对象进行配置。

__call__ 作用

  • __call__ 是一个特殊方法,使得对象能够像函数一样被调用。具体来说,当你在一个对象后面加上括号(例如 obj()),Python 实际上会调用该对象的 __call__ 方法。

Django的架构模式

它采用了 MVT)架构模式

  • Model(模型)
  • View(视图)
  • Template(模板)