Python面试题

Python面试题回答

1. Python面向对象的三个特征?

Python面向对象编程的三个主要特征是:

  • 封装(Encapsulation):将数据和操作数据的方法绑定在一起,隐藏内部实现细节,只暴露必要的接口。在Python中通过类(class)实现。
  • 继承(Inheritance):子类可以继承父类的属性和方法,实现代码重用。Python支持多重继承。
  • 多态(Polymorphism):同一操作作用于不同对象可以有不同的解释和执行结果。Python通过鸭子类型(duck typing)实现多态。

多态如何实现和使用

在Python中,多态的实现和使用可以通过以下几种方式:

1. 通过鸭子类型实现多态
Python不检查对象类型,而是关注对象是否具有所需方法或属性。只要对象实现了对应方法,就可以被调用。

class Cat:
    def speak(self):
        return "喵喵~"

class Dog:
    def speak(self):
        return "汪汪!"

def animal_speak(animal):
    print(animal.speak())

# 不同对象都可以调用
animal_speak(Cat())  # 输出:喵喵~
animal_speak(Dog())  # 输出:汪汪!

2. 通过继承和方法重写实现多态
子类可以重写父类的方法,实现不同的行为表现。

class Animal:
    def speak(self):
        raise NotImplementedError("子类必须实现此方法")

class Cat(Animal):
    def speak(self):
        return "喵喵~"

class Dog(Animal):
    def speak(self):
        return "汪汪!"

# 统一调用接口
animals = [Cat(), Dog()]
for animal in animals:
    print(animal.speak())

3. 使用抽象基类规范多态
通过abc模块强制要求子类实现特定方法。

from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self):
        pass

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius
    
    def area(self):
        return 3.14 * self.radius ** 2

class Square(Shape):
    def __init__(self, side):
        self.side = side
    
    def area(self):
        return self.side ** 2

# 统一调用方式
shapes = [Circle(5), Square(4)]
for shape in shapes:
    print(f"面积: {shape.area()}")

4. 运算符重载实现多态
通过特殊方法实现运算符的多态行为。

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)
    
    def __str__(self):
        return f"({self.x}, {self.y})"

v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(v1 + v2)  # 输出:(4, 6)

实际应用场景:

  • 支付系统:统一处理支付宝、微信等不同支付方式
  • 数据库操作:不同数据库驱动实现相同接口
  • 游戏开发:不同角色实现相同的攻击接口
  • 插件系统:统一调用插件接口

多态的优势:

  • 提高代码扩展性,新增功能只需添加新类
  • 增强代码可维护性,统一调用接口
  • 降低耦合度,各模块独立发展
  • 提高代码复用性,通用逻辑只需编写一次

注意事项:

  • Python的多态更加灵活,不强制要求继承关系
  • 建议使用抽象基类来规范接口
  • 注意文档说明,明确各子类需要实现的方法
  • 适当使用类型提示提高代码可读性

2. is 和 == 的区别?

  • ==值比较,检查两个对象的值是否相等
  • is身份比较,检查两个对象是否是内存中的同一个对象(即id是否相同)

示例:

a = [1, 2, 3]
b = a
c = [1, 2, 3]

a == b  # True
a is b  # True
a == c  # True
a is c  # False (不同对象)

3. GIL了解吗?说说

GIL(Global Interpreter Lock)是全局解释器锁,是CPython解释器中的一个机制:

  • 同一时刻只允许一个线程执行Python字节码
  • 目的是简化CPython实现和内存管理
  • 主要影响CPU密集型多线程程序(会使多线程无法真正并行)
  • 对I/O密集型任务影响不大(因为I/O操作会释放GIL)
  • 可以通过多进程(而非多线程)来绕过GIL限制

4. 可变类型和不可变类型?

  • 不可变类型(immutable):创建后不能修改内容

    • 数字(int, float, complex)
    • 字符串(str)
    • 元组(tuple)
    • 布尔(bool)
    • frozenset
  • 可变类型(mutable):创建后可以修改内容

    • 列表(list)
    • 字典(dict)
    • 集合(set)
    • 字节数组(bytearray)

5. yield用法?

yield用于定义生成器函数

  • 函数执行到yield时会暂停并返回yield后的值
  • 下次调用时会从暂停处继续执行
  • 相比return,yield可以多次返回值
  • 节省内存,适合处理大数据集(惰性求值)

示例:

def count_up_to(max):
    count = 1
    while count <= max:
        yield count
        count += 1

# 使用
for num in count_up_to(5):
    print(num)

6. 深拷贝和浅拷贝区别?

  • 浅拷贝(copy.copy)

    • 只复制对象本身,不复制内部的子对象
    • 新对象和原对象共享内部子对象
    • 适用于不可变对象或简单结构
  • 深拷贝(copy.deepcopy)

    • 递归复制对象及其所有子对象
    • 新对象和原对象完全独立
    • 适用于嵌套结构或需要完全独立的场景

示例:

import copy

lst1 = [1, [2, 3], 4]
lst2 = copy.copy(lst1)    # 浅拷贝
lst3 = copy.deepcopy(lst1) # 深拷贝

lst1[1][0] = 'changed'
# lst2会看到变化,lst3不会

7. Python中的线程

Python中的线程:

  • 通过threading模块实现
  • 由于GIL限制,多线程不适合CPU密集型任务
  • 适合I/O密集型任务(如网络请求、文件操作)
  • 线程共享同一进程的内存空间
  • 需要注意线程安全问题(使用Lock、RLock等同步机制)

基本使用:

import threading

def worker():
    print("Worker thread")

t = threading.Thread(target=worker)
t.start()

8. 生成器和迭代器区别

  • 迭代器(Iterator)

    • 实现了__iter____next__方法的对象
    • 一次性,遍历后无法重新开始
    • 所有生成器都是迭代器
  • 生成器(Generator)

    • 使用yield关键字定义的函数返回的对象
    • 一种特殊的迭代器,更简洁的实现方式
    • 惰性求值,节省内存
    • 可以通过生成器表达式创建(类似列表推导式,但用圆括号)

示例:

# 迭代器
class Count:
    def __init__(self, low, high):
        self.current = low
        self.high = high
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.current > self.high:
            raise StopIteration
        else:
            self.current += 1
            return self.current - 1

# 生成器
def count_gen(low, high):
    current = low
    while current <= high:
        yield current
        current += 1

9. *args和**kwargs是什么?区别,用法

  • *args

    • 用于接收任意数量的位置参数
    • 参数被打包为元组(tuple)
    • 函数定义时使用
  • **kwargs

    • 用于接收任意数量的关键字参数
    • 参数被打包为字典(dict)
    • 函数定义时使用

区别:

  • *args处理无名参数,**kwargs处理有名参数
  • 可以同时使用,但*args必须在**kwargs之前

用法示例:

def example_func(arg1, *args, **kwargs):
    print(f"固定参数: {arg1}")
    print(f"额外位置参数: {args}")
    print(f"额外关键字参数: {kwargs}")

example_func(1, 2, 3, 4, name="Alice", age=25)

输出:

固定参数: 1
额外位置参数: (2, 3, 4)
额外关键字参数: {'name': 'Alice', 'age': 25}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值