Skip to content

中级面试题

什么是鸭子类型

面试题目

  • 级别: L2
  • 知识模块: Python 编程语言

请说一下什么是 Python 中的鸭子类型?

公司

  • 美团

招聘类型

社招

题目解析

此题目是考察对 Python 面象对象及 Python 特性的理解深度

答案

鸭子类型的概念

  • 鸭子类型(Duck Typing)是动态类型语言中的一个概念,源自一句格言:“如果它走起路来像鸭子,叫起来像鸭子,那么它就是鸭子。”
  • 这个概念在程序设计中指的是关注对象的行为(方法和属性)而不是对象的类型。

鸭子类型的特征

  • 在鸭子类型中,关注的是对象是否具有特定的方法和属性,而不是关注对象的具体类型。
  • 当代码中需要调用特定的方法或属性时,程序会查找对象是否具有这些方法或属性,而不关心对象的具体类型。
  • 如果对象拥有对应的方法或属性,在运行时就可以被调用,即使对象的类型与要求的类型不同。

鸭子类型的应用

  • 一个经典的鸭子类型的例子是在 Python 中使用迭代器。
  • 在 Python 中,只要对象实现了 __iter__()__next__() 方法,它就可以被视为一个迭代器,即使它并非继承自任何特定的迭代器类。

鸭子类型的优势

  • 鸭子类型的思想使代码更加灵活,可以适应不同的对象类型,同时也鼓励了面向对象的设计原则中的接口隔离和依赖倒置。
  • 通过鸭子类型,程序可以更加简洁、可扩展,同时减少了对类型的依赖,提高了代码的易维护性和可读性。

什么是多态

面试题目

  • 级别: L2
  • 知识模块: Python 编程语言

请讲一下 Python 中的多态。

公司

  • 美团

招聘类型

社招

题目解析

这个问题考察的是对Python面向对象编程及其特性(尤其是多态)的理解深度。多态是面向对象编程中的一个核心概念,它允许不同类的对象以相同的方式被操作,从而提供了灵活性和可扩展性。

在 Python 中,多态是面向对象程序设计中的一个重要概念。它指的是同一个方法调用可以在不同对象上有不同的行为。换句话说,多态允许使用相同的接口来调用不同对象的方法,而根据对象的类型,会产生不同的行为。

  • 在多态性下,对象对同一消息可以作出多种反应。这样就允许将具体的操作延迟到运行时,而不必在编译时确定。

  • 多态性通常与继承和接口(或抽象类)一起使用,通过继承和接口的实现,不同的子类可以对同一方法进行不同的实现,实现了多态性。

  • Python 由于类型动态推导机制,并没有在编译阶段确定一个对象的类型,所以天生具备多态性,这种多态称为鸭子类型

  • 鸭子类型(Duck Typing)是动态类型语言中的一个概念,源自一句格言:“如果它走起路来像鸭子,叫起来像鸭子,那么它就是鸭子。”

  • 这个概念在程序设计中指的是关注对象的行为(方法和属性)而不是对象的类型。

  • 可以使用 isinstance()issubclass()类型注解 对对象执行的方法进行判断或约束。

答案

在Python中,多态是面向对象编程的核心概念,允许同一个方法在不同对象上有不同的行为。简单来说,多态使得不同类的对象可以通过相同的接口调用各自不同的实现,从而提高了灵活性和扩展性。

Python的多态主要体现在“鸭子类型”上,即关注对象的行为而不是对象的具体类型。例如,如果一个对象实现了特定的方法,它就可以被视为符合某个接口,不论它的具体类是什么。Python的动态类型特性自然支持这种多态。

多态通常与继承和接口(或抽象类)一起使用,通过这些机制,不同的子类可以对相同的方法进行不同的实现,从而实现多态。通过使用isinstance()、issubclass()等工具,可以检查对象的类型或约束对象的方法。

用过哪些装饰器

面试题目

  • 级别: L2
  • 知识模块: Python 编程语言

用过那些装饰器

公司

  • 小米外包

招聘类型

社招

题目解析

分享曾用过的装饰器。

答案

  • @classmethod 定义类方法装饰器
  • @staticmethod 定义静态方法装饰器
  • @property 计算属性装饰器,用来将一个方法转变为属性,可以在调用时像访问属性一样调用,而不需要加括号。常用于访问和设置对象的私有属性。
  • @pytest.mark.skip Pytest 跳过测试用例装饰器
  • @pytest.mark.parametrize Pytest 测试框架参数化装饰器
  • @pytest.fixture Pytest 夹具装饰器
  • app.route flask 框架定义路由装饰器

什么是MRO

面试题目

  • 级别: L2
  • 知识模块: Python 编程语言

Python 中的 MRO 是什么?

公司

  • 美团

招聘类型

社招

题目解析

此题目是考察对 Python 面象对象的理解深度

答案

  • MRO(Method Resolution Order)即方法解析顺序。

  • 它是用于确定在多继承情况下,调用方法时搜索方法的顺序。

  • 在 Python 中,类的 MRO 顺序是通过 C3 算法计算出来的。

  • 解决了早期多继承时可能出现的“菱形继承”和“时间倾斜”等问题。

  • 通过调用类的 mro(类名) 方法或 类名.__mro__魔法属性,可以查看该类的方法解析顺序。

  • C3 算法简单理解就是在搜索父类时,先去查找当前类的父类的所有子类,当所有子类都查找完毕后,再去查找父类,然后再去查找其它继承关系

  • 总结一下就是,先广度查找,再深度查找

示例:


class A:
    pass

class B(A):
    pass

class C(A):
    pass

class D(B,C):
    pass

class X:
    pass

class Y(X):
    pass

class Z(X):
    pass

class T(D,Z,Y):
    pass

if __name__ == '__main__':
    print("T1")
    print(T1.mro())
    print(T1.__mro__)
    print("T2")
    print(T2.mro())
    print(T2.__mro__)

# 输出
# T1
# (<class '__main__.T1'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class '__main__.Z'>, <class '__main__.Y'>, <class '__main__.X'>, <class 'object'>)
# (<class '__main__.T1'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class '__main__.Z'>, <class '__main__.Y'>, <class '__main__.X'>, <class 'object'>)
# T2
# (<class '__main__.T2'>, <class '__main__.Z'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class '__main__.Y'>, <class '__main__.X'>, <class 'object'>)
# (<class '__main__.T2'>, <class '__main__.Z'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class '__main__.Y'>, <class '__main__.X'>, <class 'object'>)


Python对文件的操作

面试题目

  • 级别: L2
  • 知识模块: Python 编程语言

Python 对文件的操作?

公司

  • 字节外包

招聘类型

  • 社招

题目解析

Python 提供了丰富的文件操作功能,包括文件的读、写、追加等操作。掌握文件操作是编写数据处理、日志记录、配置管理等程序的基础技能。

文件操作的基本步骤

  1. 打开文件: 使用 open() 函数打开文件,返回一个文件对象。可以指定文件模式,如读、写、追加等。
file = open('example.txt', 'r')  # 以只读模式打开文件
  1. 读写文件: 使用文件对象的方法进行读写操作,如 read(), write(), readline(), readlines(), writelines() 等。
  2. 读取文件内容:
content = file.read()  # 读取整个文件内容

lines = file.readlines()  # 按行读取文件内容,返回一个列表
  • 写入文件内容:
file = open('example.txt', 'w')  # 以写模式打开文件
file.write('Hello, World!')  # 写入字符串到文件

file.writelines(['Line 1\n', 'Line 2\n'])  # 写入多行字符串到文件
  1. 关闭文件: 完成读写操作后,应关闭文件以释放资源。
file.close()  # 关闭文件

文件操作的上下文管理 使用 with 语句可以更简洁、安全地进行文件操作,自动管理文件的打开和关闭。 在 with 语句块中,文件会在块结束后自动关闭。

with open('example.txt', 'r') as file:
    content = file.read()
    print(content)

文件模式

常用的文件模式有:

  • 'r': 只读模式(默认)
  • 'w': 写模式(会覆盖文件内容)
  • 'a': 追加模式(在文件末尾添加内容)
  • 'b': 二进制模式(如 'rb' 读二进制文件,'wb' 写二进制文件)
  • '+': 读写模式(如 'r+' 读写文件)

示例:

# 以只读模式打开文本文件
with open('example.txt', 'r') as file:
    content = file.read()
    print(content)

# 以写模式打开文本文件
with open('example.txt', 'w') as file:
    file.write('Hello, World!')

# 以追加模式打开文本文件
with open('example.txt', 'a') as file:
    file.write('\nAppend this line.')

# 以二进制读模式打开文件
with open('example.bin', 'rb') as file:
    binary_content = file.read()
    print(binary_content)

文件指针的操作 文件对象提供了 seek() 和 tell() 方法来操作文件指针。 - seek(offset, whence): 移动文件指针到指定位置。 - tell(): 返回当前文件指针位置。

示例:

with open('example.txt', 'r') as file:
    file.seek(5)  # 移动文件指针到位置 5
    print(file.read())  # 从位置 5 开始读取文件
    position = file.tell()  # 获取当前文件指针位置
    print(f'Current position: {position}')

答案

Python 提供了简洁且功能强大的文件操作接口,能够满足日常开发中的各种文件读写需求。使用 open() 函数打开文件,结合上下文管理 (with 语句) 进行文件操作,是编写安全可靠文件处理代码的最佳实践。掌握文件模式和文件指针操作,能够更灵活地处理文件内容。

python中类方法,类实例方法,静态方法的区别

面试题目

  • 级别: L2
  • 知识模块: Python 编程语言

python 中类方法,类实例方法,静态方法的区别?

公司

  • 字节外包

招聘类型

  • 社招

题目解析

在 Python 中,类方法、实例方法和静态方法是定义在类中的不同类型的方法,它们的使用场景和行为有所不同。理解它们的区别对于设计和使用类时非常重要。以下是这三种方法的详细说明:

  1. 实例方法(Instance Method)

    • 定义:实例方法是最常见的方法类型。它需要一个实例对象作为第一个参数(通常是 self),并且可以访问类的实例属性和调用其他实例方法。
    • 特点:
      • 通过类的实例调用。
      • 可以访问和修改实例的状态。
      • 不能在没有创建类的实例的情况下调用。
    • 示例:
class MyClass:
    def __init__(self, value):
        self.value = value

    def instance_method(self):
        return self.value

obj = MyClass(10)
print(obj.instance_method())  # 输出: 10
  1. 类方法(Class Method)

    • 定义:类方法是绑定到类而不是实例的方法。它需要一个类对象作为第一个参数(通常是 cls),可以通过 @classmethod 装饰器定义。
    • 特点:
      • 通过类名或实例调用。
      • 只能访问类属性,不能访问实例属性。
      • 适用于需要操作类级别的数据或方法的场景。
    • 示例:
class MyClass:
    class_variable = 'class value'

    @classmethod
    def class_method(cls):
        return cls.class_variable

print(MyClass.class_method())  # 输出: class value
obj = MyClass()
print(obj.class_method())      # 输出: class value
  1. 静态方法(Static Method)

    • 定义:静态方法既不依赖于类实例,也不依赖于类本身。它不需要接受 self 或 cls 参数,可以通过 @staticmethod 装饰器定义。
    • 特点:
      • 通过类名或实例调用。
      • 无法访问实例属性或类属性。
      • 适用于与类的内部状态无关的功能。
    • 示例:
class MyClass:

    @staticmethod
    def static_method(x, y):
        return x + y

print(MyClass.static_method(5, 10))  # 输出: 15
obj = MyClass()
print(obj.static_method(5, 10))      # 输出: 15

答案

  1. 实例方法是最常见的一种方法,它需要一个实例对象作为第一个参数(通常是 self),并且可以访问类的实例属性和调用其他实例方法。实例方法可以访问和修改实例的状态,不能在没有创建类的实例的情况下调用。实例方法通过类的实例调用。

  2. 类方法是绑定到类而不是实例的方法,它需要一个类对象作为第一个参数(通常是 cls),可以通过 @classmethod 装饰器定义。类方法只能访问类属性,不能访问实例属性。类方法通过类名或实例调用,适用于需要操作类级别的数据或方法的场景。

  3. 静态方法既不依赖于类实例,也不依赖于类本身。它不需要接受 selfcls 参数,可以通过 @staticmethod 装饰器定义。静态方法通过类名或实例调用,无法访问实例属性或类属性,适用于与类的内部状态无关的功能。

python引用参数和值参数的区别

面试题目

  • 级别: L2
  • 知识模块: Python 编程语言

python 引用参数和值参数的区别

公司

  • 字节外包

招聘类型

  • 社招

题目解析

引用参数(Reference Parameter)

定义:引用参数传递方式是指函数接收到的是实际参数的引用(即内存地址)。函数内部对参数的修改会直接影响原始数据,因为函数操作的是原始数据的引用。

特点:

  • 传递的是数据的地址或引用。
  • 修改引用会直接影响原始数据。

值参数(Value Parameter)

定义:值参数传递方式是指函数接收到的是实际参数的副本。函数内部对参数的修改不会影响原始数据,因为函数操作的是副本而不是原始数据。

特点:

  • 只传递数据的副本。
  • 修改副本不会影响原始数据。

在 Python 中,参数的传递机制可以分为“值传递”和“引用传递”。尽管 Python 的参数传递被称为“对象引用传递”,它与传统的“值传递”或“引用传递”有些不同。以下是这两种传递机制的核心概念及其区别:

  1. 值传递:

    • 在值传递中,函数接收的是参数值的副本。对副本的任何修改不会影响原始数据。这意味着函数内部的改变不会影响外部变量。
  2. 引用传递:

    • 在引用传递中,函数接收的是对象的引用(即地址),而不是对象本身。函数内部的修改将直接影响原始对象。
  3. Python 的传递机制:

    • Python 实际上采用的是“对象引用传递”的机制。传递给函数的是对象的引用(即对象的地址),但不是对象的引用本身。函数可以修改传递的对象(如果对象是可变的),但不能改变对象的引用(即不能使其指向一个新的对象)。

    • 如果传递的是可变对象(如列表、字典),函数内部的修改会影响原始对象。

    • 如果传递的是不可变对象(如整数、字符串、元组),函数内部的修改不会改变原始对象。

示例:

def modify_list(lst):
    lst.append(4)

def modify_integer(n):
    n += 1

my_list = [1, 2, 3]
my_integer = 10

modify_list(my_list)
modify_integer(my_integer)

print(my_list)       # 输出: [1, 2, 3, 4]
print(my_integer)   # 输出: 10

在这个例子中,modify_list 函数修改了传入的列表(可变对象),因此 my_list 被改变了。而 modify_integer 函数试图修改整数(不可变对象),但 my_integer 没有被改变。

答案

值参数:

  • 传递的是数据的副本。
  • 修改副本不会影响原始数据。

引用参数:

  • 传递的是数据的地址或引用。
  • 修改引用会直接影响原始数据。

Python 中,参数的传递机制可以分为“值传递”和“引用传递”。

  • 值传递:在值传递中,函数接收的是参数值的副本。对副本的任何修改不会影响原始数据。这意味着函数内部的改变不会影响外部变量。

  • 引用传递:在引用传递中,函数接收的是对象的引用(即地址),而不是对象本身。函数内部的修改将直接影响原始对象。

python中序列化有几种实现方式

面试题目

  • 级别: L2
  • 知识模块: Python 编程语言

python 中序列化有几种实现方式

公司

  • 传音控股

招聘类型

社招

题目解析

序列化是将 Python 对象转换为可存储或传输格式的过程,以便在不同的环境或会话中恢复原始对象。在 Python 中,序列化通常指将对象转换为字节流或字符串,以便进行存储或传输。反序列化则是将这些数据重新转换为对象。Python 提供了多种实现序列化的方式,主要包括以下几种:

  1. json 模块:

  2. 功能:json 模块用于将 Python 对象转换为 JSON 格式(序列化)以及从 JSON 格式恢复对象(反序列化)。JSON 是一种轻量级的数据交换格式,广泛用于 Web 开发和数据交换。

  3. 优点:格式简单,广泛支持,易于与其他编程语言进行交互。
  4. 缺点:只支持部分 Python 数据类型,如字典、列表、字符串、数字等;不支持自定义对象。
  5. 示例:
import json

# 序列化
data = {'key': 'value', 'number': 42}
with open('data.json', 'w') as f:
    json.dump(data, f)

# 反序列化
with open('data.json', 'r') as f:
    loaded_data = json.load(f)
print(loaded_data)  # 输出: {'key': 'value', 'number': 42}
  1. yaml 模块:

  2. 功能:yaml 模块用于将 Python 对象转换为 YAML 格式(序列化)以及从 YAML 格式恢复对象(反序列化)。 YAML 是一种可读性强的数据序列化格式,常用于配置文件。

  3. 优点:格式可读性强,支持复杂数据结构。
  4. 缺点:需要额外的库(如 pyyaml),可能存在安全性问题(避免加载不信任的 YAML 数据)。
  5. 示例:
import yaml

# 序列化
data = {'key': 'value', 'number': 42}
with open('data.yaml', 'w') as f:
    yaml.dump(data, f)

# 反序列化
with open('data.yaml', 'r') as f:
    loaded_data = yaml.safe_load(f)
print(loaded_data)  # 输出: {'key': 'value', 'number': 42}

答案

  1. json 模块:将 Python 对象序列化为 JSON 格式,广泛用于数据交换和配置文件。只支持基本数据类型,不支持自定义对象。

  2. yaml 模块:将 Python 对象序列化为 YAML 格式,适用于配置文件和数据交换。需要安装额外的库(如 pyyaml),格式可读性强。