学习日志14 python

divmod(a, b) 

divmod(a,b)是Python内置函数,用于返回两个数相除的商和余数,返回值是一个元组(tuple)。

divmod(a, b) 是 Python 的内置函数,用于同时计算两个数值的商和余数,返回一个包含这两个结果的元组 (商, 余数)。该函数在处理需要同时获取整除结果和余数的场景(如时间单位转换、分页计算)时非常高效。

基本用法

python

运行

result = divmod(a, b)  # 返回 (a // b, a % b)

  • 参数
    • a:被除数(数值类型,如整数或浮点数)。
    • b:除数(数值类型,不可为 0)。
  • 返回值:元组 (商, 余数),其中:
    • 商为 a // b(整除结果)。
    • 余数为 a % b

示例

  1. 整数运算

    python

    运行

    result = divmod(10, 3)  # 返回 (3, 1)
    # 等价于: (10 // 3, 10 % 3)
    
  2. 浮点数运算

    python

    运行

    result = divmod(10.5, 3.2)  # 返回 (3.0, 0.9)
    # 等价于: (10.5 // 3.2, 10.5 % 3.2)
    
  3. 时间单位转换

    python

    运行

    seconds = 3700
    minutes, remainder = divmod(seconds, 60)  # 返回 (61, 40)
    hours, minutes = divmod(minutes, 60)      # 返回 (1, 1)
    print(f"{hours}小时{minutes}分钟{remainder}秒")  # 输出: 1小时1分钟40秒
    

注意事项

  1. 除数不能为 0:否则会触发 ZeroDivisionError
  2. 负数处理:商和余数的符号遵循 Python 的整除规则(向负无穷取整)。例如:

    python

    运行

    divmod(10, -3)  # 返回 (-4, 2),因为 10 = (-4)×(-3) + 2
    divmod(-10, 3)  # 返回 (-4, 2),因为 -10 = (-4)×3 + 2
    
  3. 浮点数精度:当操作数为浮点数时,结果可能存在精度误差(如 divmod(0.1, 0.2) 返回 (0.0, 0.1))。

应用场景

  • 分页计算:计算总页数和剩余项数。
  • 进制转换:逐位提取数值的每一位(如十进制转二进制)。
  • 循环取模:处理周期性任务(如时钟指针旋转)。

通过 divmod,可以避免多次计算商和余数,提高代码效率。

2 对比集合和列表

题目
在Python3中,下列说法正确的是:
sets = {1, 2, 3, 4, 5}
print(sets[2])
程序运行结果为:

A 2
B 3
C 报错
D {3}

正确答案是 C. 报错

原因分析

  1. 集合(set)的特性

    • 集合是无序且元素唯一的数据结构。
    • 由于集合不维护顺序,因此无法通过索引(如 sets[2])访问元素。
  2. 代码错误

    python

    sets = {1, 2, 3, 4, 5}  # 创建一个集合
    print(sets[2])          # 尝试通过索引访问,报错!
    
     
    • 执行 sets[2] 时,Python 会抛出 TypeError: 'set' object is not subscriptable,提示集合不支持下标操作。

补充知识点

1. 集合的正确用法
  • 成员检测

    python

    运行

    print(3 in sets)  # 输出: True
    
  • 遍历元素

    python

    运行

    for element in sets:
        print(element)  # 输出顺序不确定(如 1, 2, 3, 4, 5 或其他顺序)
    
  • 集合操作

    python

    运行

    sets.add(6)         # 添加元素
    sets.remove(4)      # 删除元素
    union_set = sets | {4, 5, 6}  # 并集
    
2. 有序集合的替代方案
  • 使用列表(list)

    python

    运行

    my_list = [1, 2, 3, 4, 5]
    print(my_list[2])  # 输出: 3(列表有序,支持索引)
    
  • 使用有序字典(Python 3.7+)

    python

    运行

    from collections import OrderedDict
    ordered_set = OrderedDict.fromkeys([1, 2, 3, 4, 5])
    print(list(ordered_set.keys())[2])  # 输出: 3
    
3. 常见集合操作对比
操作 集合(set) 列表(list)
元素唯一性 自动去重 允许重复
顺序性 无序 有序
索引访问 ❌ 不支持 ✅ 支持(如 [2]
成员检测效率 O (1)(哈希表) O (n)(遍历)
添加元素 add() append()insert()

总结

集合(set)适用于去重和快速成员检测,但不支持索引访问。

若需要有序且可索引的数据结构,应使用列表(list)或有序字典(OrderedDict)。

3 原始字符串(raw string)

Python 中字符串的前导 r 代表原始字符串标识符,该字符串中的特殊符号不会被转义,适用于正则表达式中繁杂的特殊符号表示。

在 Python 中,字符串前的 r 表示原始字符串(raw string)

其中的特殊转义字符(如 \n\t 等)会被直接视为普通字符,而不会被解释为特殊含义。

解析题目

python

运行

print(r"\nwoow")
  • 关键点r 前缀使字符串保持原始形式。
  • 输出结果

    plaintext

    \nwoow
    
  • 原因
    • 原始字符串中的 \n 不会被解释为换行符,而是作为两个普通字符 \ 和 n 输出。

原始字符串 vs. 普通字符串

字符串类型 表示方式 解释结果
普通字符串 "hello\nworld" 换行符分隔两行:
hello
world
原始字符串 r"hello\nworld" 包含 \n 的单行:
hello\nworld

常见应用场景

  1. 正则表达式

    • 正则中大量使用 \(如 \d\s),使用原始字符串可避免额外转义。

    python

    运行

    import re
    pattern = r'\d+'  # 等价于普通字符串 '\\d+'
    
  2. 文件路径

    • Windows 路径中的反斜杠无需转义。

    python

    运行

    path = r'C:\Users\Documents'  # 无需写成 'C:\\Users\\Documents'
    
  3. 特殊符号

    • 例如正则中的回溯引用 \1、Unicode 转义 \uXXXX 等。

    python

    运行

    regex = r'(\w+)\1'  # 匹配重复单词(如 "hellohello")
    

注意事项

  1. 原始字符串不能以单个反斜杠结尾

    python

    运行

    r'C:\temp\'  # 语法错误!
    r'C:\temp\\'  # 正确:双反斜杠表示一个反斜杠
    r'C:\temp'   # 正确:不以反斜杠结尾
    
  2. 引号仍需转义:

    python

    运行

    r'"hello"'  # 正确:双引号在单引号字符串中无需转义
    r'\"hello\"'  # 错误:原始字符串中的 \ 不会转义 "
    

总结

  • r 前缀的作用:禁用字符串中的转义字符,使 \ 成为普通字符。
  • 适用场景:正则表达式、Windows 路径、包含大量 \ 的字符串。
  • 限制:原始字符串不能以奇数个 \ 结尾。

4 有关列表的操作

题目

在python3中,对于列表lists=[20, 28, 15, 19, 21],下列选项表述正确的是()

A list(map(lambda x: x>20, lists))的结果为[28, 21]

B list(filter(lambda x: x>20, lists))的结果为[28, 21]

C from functools import reduce
  reduce(lambda x, y: x+y, lists)的结果为103

D lists.insert(3, 25)返回的值为[20, 28, 25, 15, 19, 21]

正确答案:BC
你的答案:BD

以下是对各选项的详细分析,解释为何正确答案是 B 和 C,而 D 是错误的

选项 A

list(map(lambda x: x>20, lists)) 的结果为 [28, 21]
错误

  • 原因
    map() 对每个元素应用函数后返回结果列表。lambda x: x>20 返回布尔值(True 或 False),因此实际结果为:

    python

    运行

    [False, True, False, False, True]
    

    若要筛选出大于 20 的元素,应使用 filter()(选项 B)。

选项 B

list(filter(lambda x: x>20, lists)) 的结果为 [28, 21]
正确

  • 原因
    filter() 只保留函数返回 True 的元素。lambda x: x>20 筛选出 28 和 21,结果为:

    python

    运行

    [28, 21]
    

选项 C

reduce(lambda x, y: x+y, lists) 的结果为 103
正确

  • 原因
    reduce() 从左到右累积计算。对于 lists = [20, 28, 15, 19, 21]
    1. 20 + 28 = 48
    2. 48 + 15 = 63
    3. 63 + 19 = 82
    4. 82 + 21 = 103
      最终结果为 103

选项 D

lists.insert(3, 25) 返回的值为 [20, 28, 25, 15, 19, 21]
错误

  • 原因
    insert() 原地修改列表,但不返回修改后的列表,而是返回 None。正确的操作应为:

    python

    运行

    lists.insert(3, 25)  # 插入元素 25 到索引 3 处
    print(lists)        # 输出: [20, 28, 15, 25, 19, 21]
    

    选项 D 的返回值描述错误,因此不选。

总结

  • B 和 C 正确
    • filter() 筛选元素,reduce() 累加元素。
  • D 错误
    • insert() 不返回列表,而是直接修改原列表。
  • A 错误
    • map() 返回布尔值列表,而非筛选结果。

5 python的映射类型

在 Python 中,映射类型(Mapping Type) 是一种存储键值对(key-value pairs)的数据结构,允许通过键(key)快速查找对应的值(value)。映射类型的核心特点是 键的唯一性 和 高效的查找效率(基于哈希表实现)。

内置映射类型:字典(dict)

Python 中最常用的映射类型是 字典(dict,它是 可变的、无序的(Python 3.7+ 后保持插入顺序)。

基本用法:

python

运行

# 创建字典
person = {
    "name": "Alice",
    "age": 30,
    "city": "New York"
}

# 访问值
print(person["name"])  # 输出: Alice

# 修改值
person["age"] = 31

# 添加新键值对
person["job"] = "Engineer"

# 删除键值对
del person["city"]
主要特性:
  1. 键必须是可哈希的(hashable)

    • 常见的可哈希类型:intfloatstrtuplefrozenset
    • 不可哈希类型(如 listdict)不能作为键,因为它们是可变的。
  2. 值可以是任意类型

    python

    运行

    complex_dict = {
        "numbers": [1, 2, 3],
        "nested": {"a": 1, "b": 2},
        "function": lambda x: x**2
    }
    
  3. 键的唯一性
    重复的键会覆盖原有值:

    python

    运行

    d = {"x": 1, "x": 2}
    print(d)  # 输出: {'x': 2}
    
  4. 内置方法

    python

    运行

    person.keys()    # 返回所有键的视图
    person.values()  # 返回所有值的视图
    person.items()   # 返回所有键值对的视图
    person.get("age")  # 获取值,不存在时返回默认值(None)
    person.pop("age")  # 删除并返回指定键的值
    

其他映射类型

1. defaultdict(collections 模块)
  • 当键不存在时,自动创建默认值:

python

运行

from collections import defaultdict

# 默认值为 0 的字典
counter = defaultdict(int)
counter["apple"] += 1  # 无需先初始化键
print(counter["apple"])  # 输出: 1
2. OrderedDict(collections 模块)
  • 保持插入顺序的字典(Python 3.7+ 后 dict 已默认支持):

python

运行

from collections import OrderedDict

od = OrderedDict()
od["a"] = 1
od["b"] = 2
print(list(od.keys()))  # 输出: ['a', 'b']
3. ChainMap(collections 模块)
  • 将多个映射合并为一个视图:

python

运行

from collections import ChainMap

d1 = {"x": 1}
d2 = {"y": 2}
chain = ChainMap(d1, d2)
print(chain["x"])  # 输出: 1
4. Counter(collections 模块)
  • 专门用于计数的字典:

python

运行

from collections import Counter

words = ["apple", "banana", "apple"]
count = Counter(words)
print(count["apple"])  # 输出: 2
5. UserDict(collections 模块)
  • 用于自定义映射类的基类:

python

运行

from collections import UserDict

class MyDict(UserDict):
    def __missing__(self, key):
        return f"Key '{key}' not found"

映射类型的抽象基类

Python 通过 collections.abc 模块提供映射类型的抽象基类,用于类型检查或自定义实现:

python

运行

from collections.abc import Mapping, MutableMapping

# 检查对象是否为映射类型
isinstance({}, Mapping)  # 返回: True
isinstance([], Mapping)  # 返回: False

总结

类型 特点 适用场景
dict 内置、可变、无序(3.7+ 有序) 通用键值存储
defaultdict 自动初始化不存在的键 简化计数或分组操作
OrderedDict 保持插入顺序 需要顺序敏感的场景
Counter 高效计数 统计元素频率
ChainMap 合并多个映射 配置管理、局部 / 全局变量

映射类型是 Python 中最强大的数据结构之一,广泛用于数据存储、缓存、配置管理等场景。

6 Python装饰器的基本概念和运行机制

基本概念

装饰器(Decorator) 是 Python 中一种特殊的函数或类,用于在不修改原函数代码的前提下,动态扩展其功能。它通过将原函数包装在另一个函数中,实现功能的增强,体现了面向切面编程(AOP) 的思想。

核心作用

  • 分离关注点:将与核心业务逻辑无关的功能(如日志、权限、计时)抽离。
  • 复用代码:避免在多个函数中重复编写相同逻辑。

运行机制

装饰器的本质是一个高阶函数,它接收一个函数作为参数,并返回一个新的函数。其执行流程如下:

  1. 定义装饰器函数

    python

    运行

    def decorator(func):
        def wrapper(*args, **kwargs):
            # 前置操作(如计时开始)
            result = func(*args, **kwargs)  # 调用原函数
            # 后置操作(如计时结束)
            return result
        return wrapper  # 返回包装后的函数
    
  2. 应用装饰器

    python

    运行

    @decorator
    def original_function():
        pass
    
  3. 等价转换
    上述代码等价于:

    python

    运行

    original_function = decorator(original_function)
    

示例:计时器装饰器

python

运行

import time

def timer(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)  # 执行原函数
        end_time = time.time()
        print(f"{func.__name__} 运行时间: {end_time - start_time:.2f}秒")
        return result
    return wrapper

@timer
def calculate_sum(n):
    return sum(range(n + 1))

# 调用被装饰的函数
calculate_sum(1000000)  # 输出: calculate_sum 运行时间: 0.05秒

带参数的装饰器

若装饰器需要接受额外参数(如配置项),需使用三层嵌套函数

python

运行

def repeat(n):  # 装饰器工厂函数,接收装饰器参数
    def decorator(func):
        def wrapper(*args, **kwargs):
            result = None
            for _ in range(n):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(3)  # 传入装饰器参数
def greet():
    print("Hello!")

greet()  # 输出三次 "Hello!"

保留原函数元信息

直接使用装饰器会导致原函数的元信息(如 __name____doc__)丢失。可使用 functools.wraps 解决:

python

运行

from functools import wraps

def my_decorator(func):
    @wraps(func)  # 保留原函数元信息
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

@my_decorator
def example():
    """这是示例函数"""
    pass

print(example.__name__)  # 输出: example(而非 wrapper)
print(example.__doc__)   # 输出: 这是示例函数

类装饰器

除了函数装饰器,还可以用类实现装饰器,通过 __call__ 方法:

python

运行

class CountCalls:
    def __init__(self, func):
        self.func = func
        self.count = 0

    def __call__(self, *args, **kwargs):
        self.count += 1
        print(f"第 {self.count} 次调用 {self.func.__name__}")
        return self.func(*args, **kwargs)

@CountCalls
def say_hello():
    print("Hello!")

say_hello()  # 输出: 第 1 次调用 say_hello
say_hello()  # 输出: 第 2 次调用 say_hello

装饰器链

多个装饰器可叠加使用,执行顺序从上到下:

python

运行

@decorator1
@decorator2
def func():
    pass

# 等价于:
func = decorator1(decorator2(func))

常见应用场景

  1. 日志记录:自动记录函数调用信息。
  2. 权限验证:检查用户权限后再执行函数。
  3. 缓存:缓存函数结果,避免重复计算(如 functools.lru_cache)。
  4. 计时性能:统计函数执行时间。
  5. 事务处理:自动管理数据库事务。

总结

装饰器通过高阶函数或类,在不修改原代码的情况下扩展功能,遵循开放封闭原则(对扩展开放,对修改封闭)。其核心是函数嵌套闭包,掌握 functools.wraps 和参数传递是进阶关键。

题目

有如下函数定义,执行结果为True的是:
def  dec(f):
       n= 3
       def wrapper(*args,**kw):
             return f(*args,**kw) * n
       return wrapper
@dec
def  foo(n):
       return n * 2

A foo(2) == 12

B foo(3) == 12

C foo(2) == 6

D foo(3) == 6

正确答案:A

这道题考察了Python装饰器的基本概念和运行机制。当使用@dec装饰器修饰foo函数时,实际上进行了如下转换:foo = dec(foo)。

让我们分析执行过程:
1. 原始的foo(n)函数会返回n * 2
2. 装饰器dec中定义了n=3,并通过wrapper函数将原始函数的返回值乘以3
3. 所以当调用foo(2)时:
- 首先计算原始函数结果: 2 * 2 = 4
- 然后装饰器将结果乘以3: 4 * 3 = 12

因此foo(2) == 12这个表达式结果为True,A选项正确。

7 列表(list)的删除操作

在 Python 中,列表(list)的删除操作主要通过以下方法实现。根据删除需求(按索引、按值、清空或删除切片),可选择不同的方法:

1. del 语句:按索引或切片删除

  • 语法

    python

    运行

    del list_name[index]       # 删除单个元素
    del list_name[start:end]   # 删除切片(连续范围)
    del list_name[::step]      # 删除间隔元素
    
  • 特点

    • 直接修改原列表,无返回值。
    • 索引超出范围时报错(IndexError)。
  • 示例

    python

    运行

    nums = [10, 20, 30, 40, 50]
    del nums[2]       # 删除索引 2 的元素:[10, 20, 40, 50]
    del nums[1:3]     # 删除索引 1 到 2 的元素:[10, 50]
    del nums[::2]     # 删除偶数索引元素:[20, 40]
    

2. list.pop(index):按索引删除并返回值

  • 语法

    python

    运行

    value = list_name.pop(index)  # 默认删除最后一个元素(index=-1)
    
  • 特点

    • 返回被删除的值。
    • 索引超出范围时报错(IndexError)。
  • 示例

    python

    运行

    fruits = ["apple", "banana", "cherry"]
    popped = fruits.pop(1)  # 删除索引 1 的元素,popped="banana"
    print(fruits)           # 输出: ['apple', 'cherry']
    

3. list.remove(value):按值删除第一个匹配项

  • 语法

    python

    运行

    list_name.remove(value)
    
  • 特点

    • 直接修改原列表,无返回值。
    • 值不存在时报错(ValueError)。
    • 只删除第一个匹配项,重复值需多次调用。
  • 示例

    python

    运行

    nums = [1, 2, 3, 2]
    nums.remove(2)  # 删除第一个 2
    print(nums)     # 输出: [1, 3, 2]
    

4. list.clear():清空列表所有元素

  • 语法

    python

    运行

    list_name.clear()
    
  • 特点

    • 等价于 del list_name[:]
    • 列表变为空列表 [],但对象仍存在。
  • 示例

    python

    运行

    data = [1, 2, 3]
    data.clear()  # data 变为 []
    

5. 列表推导式:按条件过滤并创建新列表

  • 语法

    python

    运行

    new_list = [x for x in old_list if condition]
    
  • 特点

    • 不修改原列表,而是返回新列表。
    • 适合需要保留原始数据的场景。
  • 示例

    python

    运行

    nums = [1, 2, 3, 4, 5]
    even_nums = [x for x in nums if x % 2 == 0]  # 新列表: [2, 4]
    

6. filter() 函数:按条件过滤元素

  • 语法

    python

    运行

    new_list = list(filter(lambda x: condition, old_list))
    
  • 特点

    • 返回迭代器,需用 list() 转换为列表。
    • 不修改原列表
  • 示例

    python

    运行

    nums = [1, 2, 3, 4, 5]
    even_nums = list(filter(lambda x: x % 2 == 0, nums))  # 新列表: [2, 4]
    

对比总结

方法 删除方式 修改原列表 返回值 不存在时的错误
del list[index] 按索引或切片 IndexError
list.pop(index) 按索引 被删除的值 IndexError
list.remove(value) 按值(第一个) ValueError
list.clear() 全部元素
列表推导式 按条件过滤 新列表
filter() 按条件过滤 迭代器(需转为列表)

注意事项

  1. 循环中删除元素

    • 直接在循环中使用 remove() 或 pop() 可能导致索引错位(如跳过元素)。
    • 推荐做法:使用列表推导式或反向循环。

    python

    运行

    # 错误示例:
    nums = [1, 2, 3, 4]
    for num in nums:
        if num % 2 == 0:
            nums.remove(num)  # 结果: [1, 3](跳过 4)
    
    # 正确示例:
    nums = [1, 2, 3, 4]
    nums = [x for x in nums if x % 2 != 0]  # 结果: [1, 3]
    
  2. 多维列表

    • 删除嵌套列表中的元素时,需指定完整索引路径。

    python

    运行

    matrix = [[1, 2], [3, 4]]
    del matrix[0][1]  # 删除第一个子列表的第二个元素
    print(matrix)     # 输出: [[1], [3, 4]]
    
  3. 性能考虑

    • 删除列表头部元素(如 pop(0))的时间复杂度为 O (n),性能较差。
    • 若需频繁删除头部元素,推荐使用 collections.deque

8 字符串查找的异常处理机制

在 Python 中,字符串的查找方法在处理不存在的目标时,采用了不同的异常处理机制。以下是对 index()count()in 和 find() 的详细介绍及异常处理说明:

1. str.index(sub[, start[, end]])

  • 功能
    返回子字符串 sub 在原字符串中第一次出现的索引,若未找到则抛出异常
  • 异常处理
    • 若 sub 不存在,抛出 ValueError: substring not found
  • 示例

    python

    运行

    s = "hello"
    print(s.index("l"))      # 输出: 2
    print(s.index("world"))  # 报错: ValueError
    

2. str.count(sub[, start[, end]])

  • 功能
    返回子字符串 sub 在原字符串中出现的次数,若未找到则返回 0(不抛异常)。
  • 异常处理
    • 不抛出异常,未找到时返回 0
  • 示例

    python

    运行

    s = "hello"
    print(s.count("l"))      # 输出: 2
    print(s.count("world"))  # 输出: 0
    

3. 成员运算符 in

  • 功能
    判断子字符串 sub 是否存在于原字符串中,返回 True 或 False(不抛异常)。
  • 异常处理
    • 不抛出异常,直接返回布尔值。
  • 示例

    python

    运行

    s = "hello"
    print("l" in s)      # 输出: True
    print("world" in s)  # 输出: False
    

4. str.find(sub[, start[, end]])

  • 功能
    返回子字符串 sub 在原字符串中第一次出现的索引,若未找到则返回 -1(不抛异常)。
  • 异常处理
    • 不抛出异常,未找到时返回 -1
  • 示例

    python

    运行

    s = "hello"
    print(s.find("l"))      # 输出: 2
    print(s.find("world"))  # 输出: -1
    

对比总结

方法 未找到时的行为 适用场景
index() 抛出 ValueError 需要明确处理不存在情况的逻辑
count() 返回 0 统计出现次数,无需关心是否存在
in 返回 False 简单的存在性判断
find() 返回 -1 需要索引位置,且希望避免异常处理

异常处理最佳实践

  1. 使用 try-except 处理 index()

    python

    运行

    s = "hello"
    try:
        idx = s.index("world")
    except ValueError:
        print("子字符串不存在")
    
  2. 优先使用 find() 替代 index() 避免异常

    python

    运行

    s = "hello"
    idx = s.find("world")
    if idx != -1:
        print(f"位置: {idx}")
    else:
        print("子字符串不存在")
    
  3. 结合 in 和 index() 提高健壮性

    python

    运行

    s = "hello"
    if "world" in s:
        idx = s.index("world")
    else:
        print("子字符串不存在")
    

性能考虑

  • in 和 find() 的性能通常优于 index(),因为它们在找到目标后立即返回,而 index() 需要进行额外的异常检查。
  • 在需要频繁查找的场景(如循环中),推荐使用 in 或 find()

你可能感兴趣的:(学习,python,开发语言)