Skip to main content

Python 题库

基础概念

解释型和编译型语言的区别

解释型语言和编译型语言是两种不同的编程语言类型,它们在代码执行方式和一些其他方面有很大的区别。

  1. 执行方式:

    • 编译型语言:

      • 编译型语言的代码在运行之前需要经过编译器的处理。
      • 编译器将源代码转换为目标代码(通常是机器代码或中间代码)。
      • 目标代码保存在文件中,然后由计算机的处理器执行。
      • 例如,C、C++等是编译型语言。
    • 解释型语言:

      • 解释型语言的代码是逐行解释执行的,无需预先编译为目标代码。
      • 解释器在运行时逐行分析和执行源代码。
      • 例如,Python、JavaScript、Ruby等是解释型语言。
  2. 性能:

    • 编译型语言通常在执行时更快,因为它们的代码已经经过了编译,不需要在每次执行时解释。
    • 解释型语言的执行速度较慢,因为它们需要逐行解释代码。

介绍GIL全局解释器锁

GIL(Global Interpreter Lock)全称全局解释器锁

它是一种机制,用于确保同一时间只有一个线程可以执行Python字节码,从而保证了线程安全性。

在Python解释器中,GIL被设计为一个互斥锁,它控制了对共享内存的访问,以确保线程安全。
虽然GIL确保了线程安全性,但它也限制了Python,导致其无法充分利用多核CPU的优势。

如果需要充分利用多核能力,可以使用多进程。



线程、进程、协程之间的区别

Python中的线程、进程和协程都是用于实现多任务的机制,但是它们的实现方式、使用场景和优缺点都有所不同。

线程

线程是操作系统最小的执行单元,它可以共享当前进程的内存和资源。
但由于Python中的全局解释器锁(GIL)的存在,多线程并不能真正利用多核CPU的优势。

进程

进程是操作系统中独立的执行单元,每个进程都有自己的地址空间和系统资源。

进程的优点是可以真正地利用多核CPU,因为每个进程都可以运行在不同的CPU核心上。

但相比于线程,创建一个进程负担较大,进程之间通信也更加耗时和复杂。

协程

协程是一种轻量级的线程,它在单个线程中实现了多个子程序之间的切换,从而实现了并发执行。

协程的优点是可以在单个线程中实现并发执行,且协程之间的切换是由程序自己控制的。
因此不存在多线程场景下的调度开销,比线程和进程更加轻量级和高效。

但是,由于协程是在单个线程中运行的,因此也无法利用多核CPU的优势,适用于I/O密集型任务,而不是CPU密集型任务。



PEP8

PEP 8 是 Python 的官方风格指南,旨在提供一致性和可读性的代码风格。

比如 变量/函数 命名:采用小写,用下划线连接等。


is 和 == 的区别

is 比较对象的身份(内存地址),而 == 比较对象的内容(值)。

x = [1, 2, 3]
y = x # y和x引用同一个对象
z = [1, 2, 3] # z引用一个不同的对象,内容相同

print(x is y) # 输出: True
print(x is z) # 输出: False
print(x == z) # 输出: True

函数参数类型

  • 位置参数:def person(name, age)
  • 默认参数:def person(name, age=18)
  • 可变参数:person(name, age, *args)
  • 关键字参数:person(name, age, **kwargs)
  • 命名关键字参数:person(name, age, *, city, job)


常用的魔术方法

  • __iter__:可迭代对象
  • __getattr__/__setattr__:操作对象属性
  • __getitem__:下标操作,如 object[0]
  • __slots__
slots

在 Python 中,每个对象都包含了一些属性和方法,它们在类中定义的。

默认情况下,Python 会使用一个字典来保存这些属性和方法。 这样的好处是,可以动态地向对象中添加新的属性和方法。 但是,这样也带来了一些性能上的问题,因为字典查找操作比直接访问实例变量要慢。 此外,字典还会占用额外的内存空间,这对于某些应用程序来说可能是一个问题。

为了解决这些问题,Python 提供了 slots 方法。slots 是一个特殊的类变量, 它指定了一个类实例中可以存在的属性的名称列表。如果一个类定义了 slots, 那么这个类的实例将不再使用字典来存储实例变量和方法,而是使用一个固定大小的数组来保存实例变量, 从而提高了访问实例变量的速度,并且减少了内存的使用。



深拷贝和浅拷贝

浅拷贝和深拷贝之间的区别,主要在于拷贝的深度。

浅拷贝仅复制第一层的对象,而深拷贝则会递归复制整个对象。

如果复制对象仅由一层,那么浅拷贝和深拷贝效果时一样的,但如果复制对象嵌套多层,则可以根据实际使用场景考虑使用浅拷贝还是深拷贝。



迭代器与生成器之间的区别

迭代器是一个对象,它实现了迭代器协议,包括iter()和next()方法。
iter()方法返回迭代器对象本身,并且next()方法返回序列中的下一个元素。
当没有元素可供迭代时,next()方法会引发StopIteration异常。

生成器是一种特殊的迭代器,它是使用yield语句定义的函数。
生成器函数执行到yield语句时,会返回一个值并暂停执行,直到下一次调用生成器时继续执行。
生成器函数可以保存它们的状态,因此可以在每次调用时生成一个新值。



装饰器原理

装饰器本质是基于闭包实现的。

闭包:在函数内部定义,但在函数外部使用的变量。闭包可以访问定义在它作用域内的所有变量、参数、函数等。

此外,Python 装饰器可以再不改变既有函数的前提下,对函数拓展能力。



新式类和旧式类

在Python 2中,有两种不同的类类型:新式类(new-style classes)和旧式类(old-style classes)。 这区别主要影响了类的继承、多重继承以及一些其他方面的行为。在Python 3中,只有新式类的概念,所以旧式类不再存在。


如何判断是函数还是方法

判断对象是函数还是方法,可以通过 inspect 函数实现。包括解析函数具体入参等,都是通过此方法。


什么是元类

元类(metaclass)是一种高级 Python 编程概念,用于控制类的创建和行为。 元类本身是类的类,它定义了如何创建类,类似于类定义了如何创建对象。通过定义自定义元类, 你可以定制和控制类的行为,包括添加属性、方法、验证类的属性等。 元类通常用于框架、ORM(对象-关系映射)、代码检查等高级应用。


什么是反射

在Python中,"反射" 是指在运行时获取和操作对象的属性、方法以及其他元素的能力。 反射允许你以字符串的形式访问对象的属性和方法,而不是通过直接引用它们的名称。

Python 提供了一些内置函数和特殊方法来实现反射:setattr、getattr、hasattr


什么是继承

在Python中,继承是一种面向对象编程(OOP)的基本概念, 允许你创建一个新的类(子类)并从现有类(父类或基类)继承其属性和方法。 继承允许子类重用父类的代码,并扩展或修改其行为。


字典底层原理

字典是 Python 中常用的数据结构之一。它用于存储键值对数据,并支持快速查找、插入、删除等操作。

字典底层是基于哈希表实现的。哈希表本质是一个数组,它通过一定逻辑将键值计算出一个位置,从而实现快速的定位数据并进行操作。

哈希表中每一个位置都称之为哈希桶,桶中存储了该键值对的具体信息。

在 Python 中,字典底层采用了「开放地址法」的哈希表实现方式,一旦发生哈希冲突时,即不同的键值映射到同一个哈希桶时, 会按照一定的规则来探测其他的空桶,当空桶数量达到一定阈值时,会触发扩容并进行 rehash 操作。

与 Java 不同中,Java 采用的是「链表」的哈希实现方式,即相同的值映射到同一个哈希桶时会在当前桶后追加链式数据。


内存管理机制

Python 内存管理机制由三个模块组成,即:引用计数、标记清除法、分代回收法

编码熟练度

new和init有什么区别

在Python中,__new____init__ 是两个特殊的方法,用于创建对象初始化对象

基于new创建单例模式
class Singleton:
_instance = None

def __new__(cls):
if cls._instance is None:
cls._instance = super(Singleton, cls).__new__(cls)
return cls._instance

new必须要有返回值,返回实例化出来的实例。 init有一个参数self,就是这个new返回的实例。 initnew的基础上可以完成一些其它初始化的动作,init不需要返回值。


isintance和type区别

isinstance用于判断对象obj是否属于指定类的示例。type用于返回对象obj的类型。


super函数作用

super() 函数是一个内置函数,用于在子类中调用父类的方法。 它主要用于多重继承的情况,以确保正确调用父类的方法,而不会引发冲突或歧义。

编程实战

strip函数

以下代码输出什么
>>> "aabbccdd".strip("abcd")
""

以上代码输出为空,即整个字符串都被 strip 掉了。因为 strip 会剔除存在指定集合中的元素。