当前位置: 首页 > news >正文

第二阶段:数据结构与函数

模块4:常用数据结构 (Organizing Lots of Data)

在前面的模块中,我们学习了如何使用变量来存储单个数据,比如一个数字、一个名字或一个布尔值。但很多时候,我们需要处理一组相关的数据,比如班级里所有学生的名字、一本书的所有章节标题、或者一个用户的各项配置信息。这时,就需要用到数据结构(Data Structures),它们是 Python 中用来组织和存储多个数据项的方式。

这个模块我们将学习 Python 中最常用的四种内置数据结构:列表(List)、元组(Tuple)、字典(Dictionary)和集合(Set)。

4.1 列表 (List): 最常用的“数据清单”

列表是 Python 中最常用、最灵活的数据结构。你可以把它想象成一个有序的、可以修改的清单。

  • 有序 (Ordered): 列表中的每个元素都有一个固定的位置(索引),就像排队一样,顺序很重要。
  • 可变 (Mutable): 你可以在创建列表后,随时添加、删除或修改里面的元素。

1. 创建列表

  • 使用方括号 [],元素之间用逗号 , 分隔。
  • 列表可以包含任何类型的元素,甚至混合类型。
  • 创建一个空列表:[]

Python

# 一个包含数字的列表
numbers = [1, 2, 3, 4, 5]
print(numbers)# 一个包含字符串的列表
fruits = ["apple", "banana", "cherry"]
print(fruits)# 一个混合类型的列表
mixed_list = [10, "hello", 3.14, True, "banana"]
print(mixed_list)# 一个空列表
empty_list = []
print(empty_list)

2. 访问列表元素 (Indexing)

  • 和字符串一样,通过索引访问列表中的元素,索引从 0 开始。
  • 也可以使用负数索引,-1 表示最后一个元素,-2 表示倒数第二个,以此类推。

Python

colors = ["red", "green", "blue", "yellow"]first_color = colors[0]  # 'red'
second_color = colors[1] # 'green'
last_color = colors[-1]  # 'yellow'
second_last = colors[-2] # 'blue'print(f"第一个颜色是: {first_color}")
print(f"最后一个颜色是: {last_color}")# 如果索引超出范围,会报错 IndexError
# print(colors[4]) # 会导致 IndexError

3. 列表切片 (Slicing)

  • 和字符串一样,使用 [start:stop:step] 获取列表的一部分(子列表)。
  • 包含 start 索引处的元素,但不包含 stop 索引处的元素。
  • step 是可选的步长。

Python

numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]# 获取索引 1 到 4 (不含 4) 的元素
sub_list1 = numbers[1:4]   # [1, 2, 3]
print(sub_list1)# 获取从索引 5 到末尾的元素
sub_list2 = numbers[5:]    # [5, 6, 7, 8, 9]
print(sub_list2)# 获取从开头到索引 3 (不含 3) 的元素
sub_list3 = numbers[:3]    # [0, 1, 2]
print(sub_list3)# 获取所有元素的一个副本
copy_list = numbers[:]     # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(copy_list)# 获取步长为 2 的元素 (隔一个取一个)
step_list = numbers[0:10:2] # [0, 2, 4, 6, 8]
print(step_list)

4. 修改列表元素

因为列表是可变的,你可以直接通过索引来修改元素的值。

Python

my_list = [10, 20, 30, 40]
print(f"原始列表: {my_list}")# 修改索引为 1 的元素
my_list[1] = 25
print(f"修改后列表: {my_list}") # 输出: [10, 25, 30, 40]

5. 添加元素

  • append(item): 在列表末尾添加一个元素。
  • insert(index, item): 在指定的索引位置插入一个元素,原来的元素及后面的元素会向后移动。

Python

hobbies = ["reading", "swimming"]
print(f"初始爱好: {hobbies}")# 在末尾添加
hobbies.append("coding")
print(f"添加后: {hobbies}") # ['reading', 'swimming', 'coding']# 在索引 1 的位置插入
hobbies.insert(1, "hiking")
print(f"插入后: {hobbies}") # ['reading', 'hiking', 'swimming', 'coding']

6. 删除元素

  • pop(index): 删除并返回指定索引位置的元素。如果省略 index,默认删除并返回最后一个元素。
  • remove(value): 删除列表中第一个出现的指定。如果值不存在,会报错 ValueError
  • del 语句:通过索引删除元素或切片。

Python

items = ["pen", "pencil", "eraser", "ruler", "pencil"]
print(f"原始物品: {items}")# 删除并获取最后一个元素
last_item = items.pop()
print(f"被 pop 的元素: {last_item}") # 'pencil'
print(f"pop 后列表: {items}")       # ['pen', 'pencil', 'eraser', 'ruler']# 删除索引为 1 的元素
removed_item = items.pop(1)
print(f"被 pop(1) 的元素: {removed_item}") # 'pencil'
print(f"pop(1) 后列表: {items}")         # ['pen', 'eraser', 'ruler']# 删除第一个值为 "eraser" 的元素
items.remove("eraser")
print(f"remove 'eraser' 后列表: {items}") # ['pen', 'ruler']
# 如果 items.remove("notebook") 会报错 ValueError,因为 "notebook" 不存在# 使用 del 删除索引为 0 的元素
del items[0]
print(f"del items[0] 后列表: {items}") # ['ruler']# del 也可以删除切片
numbers = [1, 2, 3, 4, 5, 6]
del numbers[1:4] # 删除索引 1, 2, 3 的元素
print(f"del 切片后列表: {numbers}") # [1, 5, 6]

7. 常用列表方法

  • sort(): 对列表进行原地排序(直接修改原列表)。默认升序。如果列表元素不能互相比较(如数字和字符串混合),会报错 TypeError
  • reverse(): 将列表中的元素原地反转
  • len(list): (这是一个内置函数,不是方法) 返回列表中的元素个数。
  • count(value): 返回列表中某个值出现的次数。
  • index(value): 返回列表中某个值首次出现的索引。如果值不存在,会报错 ValueError

Python

nums = [5, 1, 4, 2, 3, 1]
chars = ['c', 'a', 'b']
print(f"原始 nums: {nums}")
print(f"原始 chars: {chars}")# 获取长度
print(f"nums 的长度: {len(nums)}") # 6# 计数
print(f"nums 中 1 出现的次数: {nums.count(1)}") # 2# 查找索引
print(f"nums 中 4 的索引: {nums.index(4)}") # 2# 排序 (原地修改)
nums.sort()
chars.sort()
print(f"排序后 nums: {nums}") # [1, 1, 2, 3, 4, 5]
print(f"排序后 chars: {chars}") # ['a', 'b', 'c']# 降序排序
nums.sort(reverse=True)
print(f"降序排序后 nums: {nums}") # [5, 4, 3, 2, 1, 1]# 反转 (原地修改)
chars.reverse()
print(f"反转后 chars: {chars}") # ['c', 'b', 'a']

8. 列表推导式 (List Comprehensions) - 初步认识

列表推导式提供了一种更简洁、更高效的方式来创建列表,特别是基于现有列表或范围创建新列表时。

基本语法: [expression for item in iterable if condition]

  • expression: 对 item 进行处理的表达式,结果将是新列表的元素。
  • for item in iterable: 循环遍历一个可迭代对象(如列表、range() 等)。
  • if condition: (可选) 只有当 conditionTrue 时,item 才会被处理并添加到新列表中。

示例:

Python

# 1. 创建一个 0 到 9 的平方数的列表
squares = []
for x in range(10):squares.append(x**2)
print(f"传统方法创建平方数列表: {squares}")# 使用列表推导式
squares_comp = [x**2 for x in range(10)]
print(f"列表推导式创建平方数列表: {squares_comp}")# 2. 创建一个 0 到 9 中偶数的列表
evens = []
for x in range(10):if x % 2 == 0:evens.append(x)
print(f"传统方法创建偶数列表: {evens}")# 使用列表推导式
evens_comp = [x for x in range(10) if x % 2 == 0]
print(f"列表推导式创建偶数列表: {evens_comp}")# 3. 将一个字符串列表中的所有单词转为大写
words = ["hello", "world", "python"]
upper_words = [word.upper() for word in words]
print(f"单词转大写: {upper_words}") # ['HELLO', 'WORLD', 'PYTHON']

列表推导式非常强大且常用,刚开始可能觉得有点抽象,但多练习几次就会发现它的便利。

4.2 元组 (Tuple): 不可变的“数据清单”

元组和列表非常相似,也是有序的序列。但它们之间有一个关键区别:元组是不可变的 (Immutable)。一旦创建,你就不能修改元组中的元素(不能添加、删除或更改)。

1. 创建元组

  • 使用圆括号 (),元素之间用逗号 , 分隔。
  • 注意: 创建只包含一个元素的元组时,必须在该元素后面加上逗号 ,,否则 Python 会把它当作普通的值。
  • 创建空元组:()
  • 在某些情况下,括号可以省略(比如赋值时),Python 也能识别它是元组。

Python

# 一个包含数字的元组
numbers_tuple = (1, 2, 3)
print(numbers_tuple)# 一个混合类型的元组
mixed_tuple = (10, "hello", 3.14)
print(mixed_tuple)# 创建单元素元组 - 注意逗号!
single_tuple = (99,)
not_a_tuple = (99)
print(f"这是一个元组: {single_tuple}, 类型: {type(single_tuple)}")
print(f"这不是元组: {not_a_tuple}, 类型: {type(not_a_tuple)}") # 这是 int 类型# 空元组
empty_tuple = ()
print(empty_tuple)# 省略括号创建元组
point = 10, 20 # 这也是一个元组 (10, 20)
print(point)
print(type(point))

2. 访问元组元素 (Indexing & Slicing)

  • 和列表、字符串完全一样,使用索引 [] 和切片 [:]

Python

my_tuple = ('a', 'b', 'c', 'd', 'e')
print(my_tuple[0])    # 'a'
print(my_tuple[-1])   # 'e'
print(my_tuple[1:3])  # ('b', 'c')

3. 不可变性 (Immutability)

这是元组的核心特性。尝试修改元组会引发 TypeError

Python

immutable_tuple = (1, 2, 3)
# 下面的代码会报错 TypeError: 'tuple' object does not support item assignment
# immutable_tuple[0] = 100# 下面的代码也会报错 AttributeError: 'tuple' object has no attribute 'append'
# immutable_tuple.append(4)# 下面的代码也会报错 AttributeError: 'tuple' object has no attribute 'remove'
# immutable_tuple.remove(1)

4. 为什么使用元组?

既然列表那么灵活,为什么还需要不可变的元组呢?

  • 性能: 元组通常比列表占用更少的内存,并且在某些操作上(如迭代访问)可能稍微快一点(尽管差异通常很小)。

  • 安全性/数据保护: 不可变性确保了数据在创建后不会被意外修改,适用于存储不应改变的数据,如坐标点 (x, y)、RGB颜色值 (r, g, b) 等。

  • 可以作为字典的键: 因为元组是不可变的,所以它可以作为字典的键(我们马上会学到字典),而列表不行。

  • 元组解包 (Tuple Unpacking): 可以方便地将元组中的元素赋值给多个变量。

    Python

    coordinates = (10, 20, 30)
    x, y, z = coordinates # 解包
    print(f"x={x}, y={y}, z={z}") # x=10, y=20, z=30
    

4.3 字典 (Dictionary / dict): 键值对应的“查找表”

字典是另一种非常有用的数据结构,它存储的是键值对 (Key-Value Pairs)。你可以把它想象成一本真实的字典或电话簿:

  • 键 (Key): 就像字典里的单词或电话簿里的名字,用来查找信息。键必须是唯一的、不可变的 (通常使用字符串、数字或元组)。
  • 值 (Value): 就像单词的释义或人对应的电话号码,是与键相关联的数据。值可以是任何数据类型,也可以重复。

字典在 Python 3.7+ 版本中是按插入顺序存储的,但在更早的版本中是无序的。字典查找速度非常快,特别适合需要通过某个唯一标识来快速获取对应信息的场景。

1. 创建字典

  • 使用花括号 {},键值对之间用逗号 , 分隔,键和值之间用冒号 : 分隔。
  • 创建空字典:{}

Python

# 一个存储学生信息的字典
student = {"name": "Alice","age": 20,"major": "Computer Science","is_graduated": False,"courses": ["Math", "Physics", "Programming"] # 值可以是列表
}
print(student)# 一个存储商品价格的字典
prices = {"apple": 5.5,"banana": 3.0,"orange": 4.5
}
print(prices)# 一个空字典
empty_dict = {}
print(empty_dict)

2. 访问字典的值

  • 使用放在方括号 [] 中来访问对应的值。如果键不存在,会引发 KeyError
  • 使用 get(key, default=None) 方法访问值。如果键不存在,它会返回 None (或者你指定的 default 值),而不会报错。这通常是更安全的方式。

Python

student = {"name": "Bob", "age": 22, "major": "Physics"}# 使用方括号访问
print(f"姓名: {student['name']}") # Bob
print(f"年龄: {student['age']}")   # 22# 尝试访问不存在的键会报错 KeyError
# print(student['city'])# 使用 get() 方法访问
print(f"专业: {student.get('major')}") # Physics
print(f"城市: {student.get('city')}")   # None (键不存在,返回 None)
print(f"城市 (带默认值): {student.get('city', 'Unknown')}") # Unknown (键不存在,返回指定的默认值 'Unknown')

3. 添加和修改键值对

  • 直接给一个新键赋值,就可以添加新的键值对。
  • 给一个已存在的键赋值,就会修改该键对应的值。

Python

student = {"name": "Charlie", "age": 19}
print(f"原始字典: {student}")# 修改 age
student['age'] = 20
print(f"修改年龄后: {student}")# 添加新的键值对 city
student['city'] = "London"
print(f"添加城市后: {student}") # {'name': 'Charlie', 'age': 20, 'city': 'London'}

4. 删除键值对

  • pop(key): 删除指定的键值对,并返回对应的值。如果键不存在,会报错 KeyError
  • del 语句:通过键删除键值对。如果键不存在,也会报错 KeyError

Python

contact = {"name": "David", "phone": "123-456", "email": "david@example.com"}
print(f"原始联系人: {contact}")# 删除 email 并获取其值
removed_email = contact.pop("email")
print(f"被 pop 的 email: {removed_email}") # david@example.com
print(f"pop email 后: {contact}")       # {'name': 'David', 'phone': '123-456'}# 使用 del 删除 phone
del contact["phone"]
print(f"del phone 后: {contact}") # {'name': 'David'}# 尝试删除不存在的键会报错
# del contact["address"] # KeyError
# contact.pop("city")    # KeyError

5. 常用字典方法

  • keys(): 返回一个包含所有的“视图对象”(可以像列表一样遍历)。
  • values(): 返回一个包含所有的“视图对象”。
  • items(): 返回一个包含所有**(键, 值)**元组对的“视图对象”。

Python

student = {"name": "Eve", "age": 21, "major": "Biology"}# 获取所有键
keys = student.keys()
print(f"所有键: {keys}")      # dict_keys(['name', 'age', 'major'])
print(list(keys))           # 可以转换为列表 ['name', 'age', 'major']# 获取所有值
values = student.values()
print(f"所有值: {values}")    # dict_values(['Eve', 21, 'Biology'])
print(list(values))         # 可以转换为列表 ['Eve', 21, 'Biology']# 获取所有键值对
items = student.items()
print(f"所有项: {items}")      # dict_items([('name', 'Eve'), ('age', 21), ('major', 'Biology')])
print(list(items))          # 可以转换为列表 [('name', 'Eve'), ('age', 21), ('major', 'Biology')]

6. 遍历字典

有几种常用的方式来遍历字典:

Python

student = {"name": "Frank", "age": 23, "major": "Chemistry"}# 遍历键 (默认方式)
print("\n遍历键:")
for key in student:print(f"键: {key}, 值: {student[key]}") # 通过键再次访问值# 遍历值
print("\n遍历值:")
for value in student.values():print(value)# 遍历键值对 (推荐方式)
print("\n遍历键值对 (使用 .items()):")
for key, value in student.items(): # 使用元组解包print(f"{key}: {value}")

4.4 集合 (Set): 无序且唯一的“元素包”

集合是一个无序的、包含不重复元素的集合。你可以把它想象成一个袋子,里面装的东西没有顺序,而且同样的东西只能装一个。

集合的主要用途:

  • 去重 (Removing Duplicates): 快速去除列表或其他序列中的重复元素。
  • 成员检测 (Membership Testing): 快速判断一个元素是否存在于集合中(比在列表中查找快得多)。
  • 集合运算 (Set Operations): 进行数学上的集合运算,如交集、并集、差集等。

1. 创建集合

  • 使用花括号 {},元素之间用逗号 , 分隔。
  • 注意: 创建空集合必须使用 set() 函数,因为 {} 创建的是空字典!
  • 可以直接从列表或其他可迭代对象创建集合,它会自动去重。

Python

# 创建一个包含数字的集合 (重复的 3 会被忽略)
numbers_set = {1, 2, 3, 4, 3, 2}
print(numbers_set) # 输出可能是 {1, 2, 3, 4} (顺序不固定)# 创建一个包含字符串的集合
fruits_set = {"apple", "banana", "cherry"}
print(fruits_set)# 创建空集合 - 必须用 set()
empty_set = set()
print(empty_set)
print(type(empty_set)) # <class 'set'># 从列表创建集合 (自动去重)
my_list = [1, 1, 2, 3, 4, 4, 4, 5]
my_set_from_list = set(my_list)
print(my_set_from_list) # {1, 2, 3, 4, 5}

2. 无序性

集合不保证元素的顺序,所以你不能像列表或元组那样使用索引来访问元素。

Python

my_set = {10, 20, 30}
# 下面的代码会报错 TypeError: 'set' object is not subscriptable
# print(my_set[0])

3. 唯一性

集合中不允许有重复的元素。如果你尝试添加一个已存在的元素,集合不会发生任何变化。

4. 添加和删除元素

  • add(element): 添加一个元素到集合中。如果元素已存在,则什么也不做。
  • remove(element): 从集合中删除一个元素。如果元素不存在,会引发 KeyError
  • discard(element): 从集合中删除一个元素。如果元素不存在,它不会报错,而是什么也不做。通常 discard 更安全。

Python

colors = {"red", "green"}
print(f"原始集合: {colors}")# 添加元素
colors.add("blue")
print(f"添加 blue 后: {colors}")colors.add("red") # 尝试添加已存在的元素
print(f"再次添加 red 后: {colors}") # 集合不变# 删除元素
colors.remove("green")
print(f"删除 green 后: {colors}")# 尝试 remove 不存在的元素会报错
# colors.remove("yellow") # KeyError# 使用 discard 删除存在的元素
colors.discard("blue")
print(f"discard blue 后: {colors}")# 使用 discard 删除不存在的元素 (不会报错)
colors.discard("yellow")
print(f"discard yellow 后: {colors}") # 集合不变

5. 集合运算

集合支持标准的数学集合运算:

  • 成员检测 (in): 判断元素是否在集合中(非常高效)。
  • 并集 (|union()): 返回包含两个集合中所有元素的新集合。
  • 交集 (&intersection()): 返回两个集合中共同存在的元素组成的新集合。
  • 差集 (-difference()): 返回存在于第一个集合但不在第二个集合中的元素组成的新集合。
  • 对称差集 (^symmetric_difference()): 返回存在于两个集合中,但不同时存在于两个集合中的元素(即并集减去交集)。

Python

set_a = {1, 2, 3, 4}
set_b = {3, 4, 5, 6}
print(f"集合 A: {set_a}")
print(f"集合 B: {set_b}")# 成员检测
print(f"2 在 A 中吗? {2 in set_a}")  # True
print(f"5 在 A 中吗? {5 in set_a}")  # False# 并集
union_set = set_a | set_b
# union_set = set_a.union(set_b)
print(f"并集 A | B: {union_set}") # {1, 2, 3, 4, 5, 6}# 交集
intersection_set = set_a & set_b
# intersection_set = set_a.intersection(set_b)
print(f"交集 A & B: {intersection_set}") # {3, 4}# 差集 (A 中有,B 中没有)
difference_set = set_a - set_b
# difference_set = set_a.difference(set_b)
print(f"差集 A - B: {difference_set}") # {1, 2}# 差集 (B 中有,A 中没有)
print(f"差集 B - A: {set_b - set_a}") # {5, 6}# 对称差集 (只在 A 或只在 B 中的元素)
sym_diff_set = set_a ^ set_b
# sym_diff_set = set_a.symmetric_difference(set_b)
print(f"对称差集 A ^ B: {sym_diff_set}") # {1, 2, 5, 6}

4.5 实践时间!

练习1:简单的学生成绩管理

  1. 创建一个列表,名为 students。这个列表将用来存储多个学生的信息。
  2. 列表中的每个元素都是一个字典,代表一个学生。每个学生字典至少包含以下键:
    • "name": 学生姓名 (字符串)
    • "grades": 一个包含该学生各科成绩(数字)的列表
    • 例如:{"name": "Alice", "grades": [85, 90, 78]}
  3. students 列表中添加至少3个学生的信息。
  4. 编写代码,计算并打印出每个学生的平均成绩。你需要遍历 students 列表,对于每个学生字典,再遍历其 "grades" 列表来计算总分和平均分。
  5. (可选)添加一个新功能:允许用户输入学生姓名,然后查找并打印该学生的成绩列表和平均分。如果学生不存在,则打印提示信息。

练习2:词频统计

  1. 定义一个包含一段文本的字符串变量(比如一句或几句话)。
  2. 预处理文本:
    • 将文本全部转换为小写(使用字符串的 lower() 方法)。
    • (可选,简化处理)去除标点符号。你可以用 replace() 方法将常见的标点符号(如 ., ,, ?, !)替换为空格或空字符串。
  3. 分词: 使用字符串的 split() 方法将处理后的文本分割成一个单词列表。默认情况下,split() 会按空格分割。
  4. 统计词频:
    • 创建一个空字典,名为 word_counts,用来存储每个单词出现的次数。
    • 遍历你的单词列表。
    • 对于列表中的每个单词:
      • 检查这个单词是否已经是 word_counts 字典的
      • 如果是,将该键对应的值(计数)加 1。
      • 如果不是,将这个单词作为新键添加到字典中,并将值设为 1。
      • (提示:使用 get(word, 0) 可以很方便地获取当前计数,如果单词不存在则返回0,然后加1即可:word_counts[word] = word_counts.get(word, 0) + 1
  5. 遍历 word_counts 字典,打印出每个单词及其出现的次数。

模块5:函数——代码的复用

在我们之前的编程练习中,你可能已经注意到,有时我们会重复写几乎完全一样的代码块。比如,计算平均分的逻辑、打印特定格式信息的代码等。如果这样的代码很多,程序会变得冗长、难以阅读,而且一旦需要修改这部分逻辑,你就得找到所有重复的地方一一修改,非常麻烦且容易出错。

函数(Function)就是解决这个问题的利器!它可以让你把一段具有特定功能的代码打包起来,给它起一个名字,然后在需要执行这段代码的任何地方,简单地“调用”这个名字即可。

5.1 为什么需要函数?(DRY 原则)

使用函数的主要原因是为了遵循 DRY 原则Don't Repeat Yourself(不要重复你自己)。

  • 提高代码复用性: 定义一次,多次调用。
  • 提高代码可读性: 将复杂的任务分解成小的、有明确功能的函数,让主程序逻辑更清晰。给函数起一个有意义的名字本身就是一种注释。
  • 提高代码可维护性: 如果需要修改某项功能的逻辑,只需要修改对应的函数定义即可,所有调用该函数的地方都会自动生效。
  • 方便协作: 不同的开发者可以分工编写不同的函数模块。

5.2 定义函数

使用 def 关键字来定义一个函数。

基本语法:

Python

def function_name(parameters):"""(可选) 函数文档字符串 (Docstring) - 解释函数的作用、参数和返回值。通常用三引号包裹。"""# 函数体 (缩进的代码块)# 这里是函数的具体逻辑statement1statement2# ...return value # (可选) 返回一个结果
  • def: 定义函数的关键字。
  • function_name: 你给函数起的名字,遵循变量命名规则(snake_case)。
  • (): 函数名后面的圆括号,必须有。
  • parameters: (可选) 括号里的变量名,是函数接收的输入值(参数),多个参数用逗号分隔。如果没有参数,括号也是空的 ()
  • :: 圆括号后面必须有冒号。
  • Docstring: (可选但强烈推荐) 一个用三引号 """Docstring goes here""" 包裹的字符串,用于解释函数的功能。好的文档字符串对于理解和使用函数至关重要。
  • 函数体: 缩进的代码块,包含函数的实际逻辑。
  • return value: (可选) 使用 return 关键字将函数的结果(值)发送回调用它的地方。如果函数没有 return 语句,或者 return 后面没有值,它默认返回 None

示例:一个简单的问候函数

Python

def greet():"""打印一句简单的问候语。"""print("Hello there! Welcome.")def greet_user(name):"""根据提供的名字打印个性化问候语。Args:name: 要问候的人的名字 (字符串)。"""print(f"Hello, {name}! Nice to meet you.")

5.3 调用函数

定义好函数后,你需要调用(Call 或 Invoke)它来执行函数体内的代码。调用函数的方法是写出函数名,后面跟上圆括号 (),并在括号内提供必要的参数(Arguments)

Python

# 调用没有参数的函数
greet() # 输出: Hello there! Welcome.# 调用有参数的函数,需要提供参数值
greet_user("Alice") # 输出: Hello, Alice! Nice to meet you.
greet_user("Bob")   # 输出: Hello, Bob! Nice to meet you.

当程序执行到函数调用时,它会“跳转”到函数的定义处,执行函数体内的代码,然后再“跳回”到函数被调用的地方继续执行。

5.4 参数 (Parameters) 与 实参 (Arguments)

这两个词经常互换使用,但严格来说:

  • 参数 (Parameters): 定义函数时,写在圆括号里的变量名(如 greet_user 函数中的 name)。它们是函数内部使用的占位符。
  • 实参 (Arguments): 调用函数时,传递给函数的实际值(如 greet_user("Alice") 中的 "Alice")。

Python 支持多种传递参数的方式:

1. 位置参数 (Positional Arguments)

最常见的方式。实参会按照它们在调用时出现的顺序,依次传递给函数定义中的参数。

Python

def describe_pet(animal_type, pet_name):"""显示宠物的信息。"""print(f"I have a {animal_type}.")print(f"My {animal_type}'s name is {pet_name.title()}.")describe_pet("hamster", "harry") # "hamster" 传给 animal_type, "harry" 传给 pet_name
describe_pet("dog", "willie")

注意:位置参数的顺序很重要,传错了会导致逻辑错误。 describe_pet("willie", "dog") 就会输出错误的信息。

2. 关键字参数 (Keyword Arguments)

调用函数时,你可以明确指定哪个实参传递给哪个参数,使用 参数名=值 的形式。这时,实参的顺序就不重要了

Python

describe_pet(animal_type="cat", pet_name="whiskers")
describe_pet(pet_name="goldie", animal_type="fish") # 顺序不同,但结果正确

注意:在一个函数调用中,关键字参数必须跟在所有位置参数之后。

3. 默认参数值 (Default Parameter Values)

在定义函数时,可以为参数指定一个默认值。如果在调用函数时没有为该参数提供实参,那么就会使用这个默认值。

Python

def power(base, exponent=2): # exponent 参数默认值为 2"""计算 base 的 exponent 次方。"""result = base ** exponentprint(f"{base} 的 {exponent} 次方是 {result}")power(5)      # 没有提供 exponent,使用默认值 2。输出: 5 的 2 次方是 25
power(3, 3)   # 提供了 exponent,使用提供的值 3。输出: 3 的 3 次方是 27
power(base=4) # 也可以用关键字参数调用
power(base=2, exponent=5)

注意:在函数定义中,所有带默认值的参数必须放在所有不带默认值的参数之后。

4. 可变参数 (Variable-Length Arguments) - 初步认识

有时你希望函数能接受任意数量的参数。

  • *args (任意数量的位置参数): 在参数名前加一个星号 *。这会将调用时提供的多余的位置参数收集到一个元组 (tuple) 中。参数名通常约定俗成用 args,但也可以用别的名字(如 *numbers)。

    Python

    def make_pizza(size, *toppings):"""概述要制作的比萨。Args:size: 比萨的尺寸。*toppings: 一个包含所有配料的元组。"""print(f"\nMaking a {size}-inch pizza with the following toppings:")if toppings: # 检查 toppings 元组是否为空for topping in toppings:print(f"- {topping}")else:print("- Plain cheese")make_pizza(12, "mushrooms")
    make_pizza(16, "mushrooms", "green peppers", "extra cheese")
    make_pizza(10) # toppings 会是一个空元组
    
  • **kwargs (任意数量的关键字参数): 在参数名前加两个星号 **。这会将调用时提供的多余的关键字参数收集到一个字典 (dict) 中。参数名通常约定俗成用 kwargs,但也可以用别的名字(如 **user_info)。

    Python

    def build_profile(first, last, **user_info):"""创建一个字典,包含我们知道的有关用户的一切。Args:first: 名。last: 姓。**user_info: 包含其他信息的字典。"""profile = {}profile['first_name'] = firstprofile['last_name'] = lastfor key, value in user_info.items(): # 遍历 kwargs 字典profile[key] = valuereturn profile # 返回构建好的字典user_profile = build_profile('albert', 'einstein',location='princeton',field='physics')
    print(user_profile)
    # 输出: {'first_name': 'albert', 'last_name': 'einstein', 'location': 'princeton', 'field': 'physics'}user_profile2 = build_profile('marie', 'curie',field='physics', award='Nobel Prize')
    print(user_profile2)
    

注意:在函数定义中,参数的顺序通常是:普通位置参数 -> 默认参数 -> *args -> **kwargs。对于初学者,理解 *args**kwargs 的基本概念(收集多余参数)即可。

5.5 返回值 (Return Values)

函数不仅可以执行操作(比如打印),还可以计算一个结果并将其“返回”给调用它的代码。这通过 return 语句实现。

  • 当执行到 return 语句时,函数立即停止执行,并将 return 后面的值作为结果返回。
  • 调用函数的地方可以接收这个返回值,通常是赋给一个变量。
  • 如果函数没有 return 语句,或者 return 后面没有值,它默认返回特殊值 None
  • 一个函数可以有多个 return 语句(例如在不同的 if 分支里),但只要执行到任何一个 return,函数就会结束。
  • 可以返回任何类型的数据:数字、字符串、列表、字典,甚至另一个函数!
  • 可以一次返回多个值,它们会被自动打包成一个元组

Python

def add(x, y):"""计算两个数的和并返回结果。"""result = x + yreturn resultsum_result = add(5, 3)
print(f"5 + 3 = {sum_result}") # 输出: 5 + 3 = 8def get_name_parts(full_name):"""将全名分割成名和姓。"""parts = full_name.split() # 按空格分割if len(parts) >= 2:first_name = parts[0]last_name = " ".join(parts[1:]) # 处理可能有中间名的情况return first_name, last_name # 返回两个值 (打包成元组)elif len(parts) == 1:return parts[0], None # 如果只有一个部分,姓氏返回 Noneelse:return None, None # 如果输入为空,都返回 Nonefirst, last = get_name_parts("Albert Einstein")
print(f"First: {first}, Last: {last}") # First: Albert, Last: Einsteinfirst, last = get_name_parts("Marie Curie")
print(f"First: {first}, Last: {last}") # First: Marie, Last: Curiefirst, last = get_name_parts("Madonna")
print(f"First: {first}, Last: {last}") # First: Madonna, Last: Nonedef check_even(number):"""检查数字是否为偶数。"""if number % 2 == 0:return True # 如果是偶数,返回 True 并结束函数# 如果上面的 if 不满足,会执行到这里return Falseprint(f"4 是偶数吗? {check_even(4)}") # True
print(f"7 是偶数吗? {check_even(7)}") # Falsedef print_and_return_nothing(message):"""打印消息,但不显式返回值。"""print(message)result_none = print_and_return_nothing("Hello") # 会打印 Hello
print(f"函数返回值: {result_none}")            # 输出: 函数返回值: None

5.6 函数的作用域 (Scope)

作用域指的是变量能够被访问的区域。

  • 局部变量 (Local Variables): 在函数内部定义的变量(包括参数)是局部变量。它们只在函数被调用时创建,在函数执行结束时销毁。局部变量只能在函数内部访问,不能在函数外部访问。

    Python

    def my_function():local_var = 10 # 局部变量print(f"函数内部: {local_var}")my_function() # 输出: 函数内部: 10
    # 下面这行会报错 NameError: name 'local_var' is not defined
    # print(f"函数外部: {local_var}")
    
  • 全局变量 (Global Variables): 在所有函数外部定义的变量是全局变量。它们在程序的整个生命周期内都存在。全局变量可以在程序的任何地方(包括函数内部)被读取。

    Python

    global_var = 100 # 全局变量def read_global():print(f"函数内部读取全局变量: {global_var}")def try_modify_global():# 试图直接修改全局变量 (不推荐,且可能产生 UnboundLocalError)# global_var = global_var + 1 # 这会报错,Python 认为你想创建一个新的局部变量print(f"函数内部尝试修改前读取: {global_var}") # 可以读取read_global() # 输出: 函数内部读取全局变量: 100
    try_modify_global()
    print(f"函数外部: {global_var}") # 输出: 函数外部: 100 (全局变量未被修改)
    
  • 修改全局变量 (global 关键字): 如果确实需要在函数内部修改全局变量的值,需要使用 global 关键字明确声明。但通常不推荐这样做,因为它会破坏函数的封装性,使代码更难理解和调试。更好的做法是将需要修改的值作为参数传入,然后返回修改后的值。

    Python

    count = 0 # 全局变量def increment_global():global count # 声明要修改的是全局变量 countcount += 1print(f"函数内 count: {count}")increment_global() # 输出: 函数内 count: 1
    increment_global() # 输出: 函数内 count: 2
    print(f"函数外 count: {count}") # 输出: 函数外 count: 2
    

对于初学者,主要理解函数内部定义的变量是局部的,外部无法访问即可。尽量避免使用 global 关键字。

5.7 匿名函数 (lambda) - (可选/简要了解)

有时你需要一个非常简单的、只用一次的小函数,lambda 表达式提供了一种快速定义这种匿名函数(没有名字的函数)的方式。

语法: lambda arguments: expression

  • lambda: 关键字。
  • arguments: 和普通函数的参数一样。
  • :: 分隔符。
  • expression: 一个表达式,它的计算结果就是函数的返回值(不需要 return 关键字)。Lambda 函数体只能包含一个表达式。

Python

# 普通函数定义
def add_regular(x, y):return x + y# 等效的 lambda 函数
add_lambda = lambda x, y: x + yprint(add_regular(5, 3)) # 8
print(add_lambda(5, 3))  # 8# 直接使用 lambda
result = (lambda a, b: a * b)(6, 7) # 定义并立即调用
print(result) # 42# lambda 常用于需要传入简单函数的地方,比如排序的 key
points = [(1, 2), (3, 1), (5, -4), (0, 8)]
# 按每个元组的第二个元素排序
points.sort(key=lambda point: point[1])
print(points) # [(5, -4), (3, 1), (1, 2), (0, 8)]

Lambda 对于初学者来说不是必需掌握的,了解有这样一种简洁写法即可,当你看到别人代码里用 lambda 时能大概理解它的意思就行。

5.8 实践时间!

练习1:将之前的练习改写成函数形式

  1. 重构闰年判断器:
    • 定义一个函数 is_leap(year)
    • 它接收一个年份 year 作为参数。
    • 函数体包含之前判断闰年的逻辑。
    • 函数应该返回 True(如果 year 是闰年)或 False(如果不是)。
    • 在主程序部分,获取用户输入,调用 is_leap() 函数,并根据返回值打印结果。
  2. 重构简单计算器:
    • 定义一个函数 calculate(num1, num2, operator)
    • 接收两个数字 num1, num2 和一个代表运算符的字符串 operator ('+', '-', '*', /) 作为参数。
    • 根据 operator 执行相应的计算。
    • 返回计算结果。如果运算符无效或除数为零,可以考虑返回 None 或打印错误信息并返回 None
    • 在主程序部分,获取用户输入的两个数字和运算符,调用 calculate() 函数,并打印结果(如果结果不是 None)。

练习2:编写工具函数 - 计算平均值

  1. 定义一个函数 calculate_average(numbers)
  2. 它接收一个包含数字的列表 numbers 作为参数。
  3. 函数应该计算并返回列表中所有数字的平均值。
  4. 考虑边界情况: 如果输入的列表 numbers 是空的,直接计算平均值会报错(除以零)。在函数开始时检查列表是否为空 (if not numbers: 或者 if len(numbers) == 0:),如果为空,可以返回 0 或者 None(并在文档字符串中说明)。
  5. 测试你的函数:创建一个数字列表,调用 calculate_average() 并打印结果。也测试一下空列表的情况。

相关文章:

第二阶段:数据结构与函数

模块4&#xff1a;常用数据结构 (Organizing Lots of Data) 在前面的模块中&#xff0c;我们学习了如何使用变量来存储单个数据&#xff0c;比如一个数字、一个名字或一个布尔值。但很多时候&#xff0c;我们需要处理一组相关的数据&#xff0c;比如班级里所有学生的名字、一本…...

matlab中simulink的快捷使用方法

连接系统模块还有如下更有效的方式:单击起始模块。 按下 Ctrl键&#xff0c;并单击目标块。 图示为已经连接好的系统模块 旋转模块&#xff1a;选中模块后按图示点击即可...

Redux部分

在src文件夹下 的store文件夹下创建modules/user.js和index.js module/ user.js // 存储用户相关const { createSlice } require("reduxjs/toolkit");const userStore createSlice({name:"user",// 数据状态initialState:{token:},// 同步修改方法red…...

基于STM32F103C8T6的温湿度检测装置

一、系统方案设计 1、系统功能分析 本项目设计的是一款基于STM32F103C8T6的温室大棚检测系统低配版。由 STM32F103C8T6最小系统板&#xff0c;OLED显示屏&#xff0c;DHT11温湿度检测传感器&#xff0c;光敏电阻传感器组成&#xff0c; 可以实现如下功能&#xff1a; 使用D…...

设计模式 - 单例模式

一个类不管创建多少次对象&#xff0c;永远只能得到该类型一个对象的实力 常用到的&#xff0c;比如日志模块&#xff0c;数据库模块 饿汉式单例模式&#xff1a;还没有获取实例对象&#xff0c;实例对象就已经产生了 懒汉式单例模式&#xff1a;唯一的实例对象&#xff0c;…...

Linux驱动开发1 - Platform设备

背景 所有驱动开发都是基于全志T507&#xff08;Android 10&#xff09;进行开发&#xff0c;用于记录驱动开发过程。 简介 什么是platform驱动自己上网搜索了解。 在driver/linux/platform_device.h中定义了platform_driver结构体。 struct platform_driver {int (*probe…...

力扣-hot100(盛最多水的容器)

11. 盛最多水的容器 中等 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明&#xf…...

使用 PyTorch 构建 UNet 图像去噪模型:从数据加载到模型训练的完整流程

图像去噪是计算机视觉中的一个基础问题&#xff0c;在医学图像、遥感、夜间视觉等领域有广泛应用。本文将手把手带你用 PyTorch 构建一个 UNet 架构的图像去噪模型&#xff0c;包括数据预处理、网络搭建、PSNR 评估与模型保存的完整流程。 本项目已支持将数据增强版本保存为独立…...

从信号处理角度理解图像处理的滤波函数

目录 1、预备知识 1.1 什么是LTI系统? 1.1.1 首先来看什么是线性系统,前提我们要了解什么是齐次性和叠加性。...

集合框架--List集合详解

List集合 List 接口直接继承 Collection 接口&#xff0c;它定义为可以存储重复元素的集合&#xff0c;并且元素按照插入顺序有序排列&#xff0c;且可以通过索引访问指定位置的元素。常见的实现有&#xff1a;ArrayList、LinkedList。 Arraylist:有序、可重复、有索引 Linke…...

需求分析---软件架构师武器库中的天眼系统

在软件架构中&#xff0c;需求分析决定了系统的核心设计方向。 然而&#xff0c;现实中的需求往往存在以下问题&#xff1a; 需求被二次加工&#xff1a;产品经理或业务方可能直接提供“解决方案”&#xff08;如“我们需要一个聊天功能”&#xff09;&#xff0c;而非原始需…...

Spring Cloud Gateway 的执行链路详解

Spring Cloud Gateway 的执行链路详解 &#x1f3af; 核心目标 明确 Spring Cloud Gateway 的请求处理全过程&#xff08;从接收到请求 → 到转发 → 到返回响应&#xff09;&#xff0c;方便你在合适的生命周期节点插入你的逻辑。 &#x1f9f1; 核心执行链路图&#xff08;执…...

Python----机器学习(基于PyTorch框架的逻辑回归)

逻辑回归是一种广泛使用的统计学习方法&#xff0c;主要用于处理二分类问题。它基于线性回归模型&#xff0c;通过Sigmoid函数将输出映射到[0, 1]范围内&#xff0c;表示实例属于正类别的概率。尽管逻辑回归适用于二分类任务&#xff0c;但在多分类问题中常使用Softmax函数&…...

工业数据治理范式革新:时序数据库 TDengine虚拟表技术解析

小T导读&#xff1a;在工业数字化过程中&#xff0c;数据如何从设备采集顺利“爬坡”到上层应用&#xff0c;一直是个难题。传统“单列模型”虽贴合设备协议&#xff0c;却让上层分析举步维艰。TDengine 用一种更聪明的方法打通了这条数据通路&#xff1a;不强求建模、不手动转…...

Linux的应用领域,Linux的介绍,VirtualBox和Ubuntu的安装,VMware的安装和打开虚拟机CentOS

目录 Linux的应用领域 Linux的介绍 Linux的介绍 Linux发行版 Unix和Linux的渊源 虚拟机和Linux的安装 VirtualBox和Ubuntu的安装 安装VirtualBox 安装Ubuntu 下载Ubuntu操作系统的镜像文件 创建虚拟机 虚拟机设置 启动虚拟机&#xff0c;安装Ubuntu系统 Ubuntu基…...

使用 Java 8 Stream实现List重复数据判断

import java.util.*; import java.util.stream.Collectors;public class DeduplicateStreamExample {static class ArchiveItem {// 字段定义与Getter/Setter省略&#xff08;需根据实际补充&#xff09;private String mATNR;private String lIFNR;private String suppSpecMod…...

GDAL:地理数据的万能瑞士军刀

目录 1. 什么是GDAL&#xff1f;2. 为什么需要GDAL&#xff1f;3. GDAL的主要功能3.1. 数据转换3.2. 数据裁剪和处理3.3. 读取和写入多种格式 4. 实际应用场景4.1 环境监测4.2 城市规划4.3 导航系统 5. 技术原理简单解释6. 如何使用GDAL&#xff1f;6.1 简单命令示例 7. 学习建…...

每日文献(十三)——Part two

今天从第三章节&#xff1a;“实现细节”开始介绍。 目录 三、实现细节 四、实验 五、总结贡献 六、致谢 三、实现细节 我们在多尺度图像上训练和测试区域建议和目标检测网络。这是在KITTI目标检测基准[13]上基于CNN的目标检测的趋势。例如&#xff0c;在[16]中&#xff…...

ArrayList 和 LinkedList 区别

ArrayList 和 LinkedList 是 Java 集合框架中两种常用的列表实现&#xff0c;它们在底层数据结构、性能特点和适用场景上有显著的区别。以下是它们的详细对比以及 ArrayList 的扩容机制。 1. ArrayList 和 LinkedList 的底层区别 (1) 底层数据结构 ArrayList&#xff1a; 基于…...

【iOS】UITableView性能优化

UITableView性能优化 前言优化从何入手优化的本质 CPU层级优化1. Cell的复用2. 尽量少定义Cell&#xff0c;善于使用hidden控制显示视图3. 提前计算并缓存高度UITableView的代理方法执行顺序Cell高度缓存高度数组 4. 异步绘制5. 滑动时按需加载6. 使用异步加载图片&#xff0c;…...

通过检索增强生成(RAG)和重排序提升大语言模型(LLM)的准确性

探索大语言模型&#xff08;LLM&#xff09;结合有效信息检索机制的优势。实现重排序方法&#xff0c;并将其整合到您自己的LLM流程中。 想象一下&#xff0c;一个大语言模型&#xff08;LLM&#xff09;不仅能提供相关答案&#xff0c;还能根据您的具体需求进行精细筛选、优先…...

IDEA202403常用快捷键【持续更新】

文章目录 一、全局搜索二、美化格式三、替换四、Git提交五、代码移动六、调试运行 在使用IDEA进行程序开发&#xff0c;快捷键会让这个过程更加酸爽&#xff0c;下面记录各种快捷键的功能。 一、全局搜索 快捷键功能说明Shift Shift全局搜索Ctrl N搜索Java类 二、美化格式 …...

硬件元件三极管:从基础到进阶的电子探秘

一、基础理论 1. PN结&#xff08;二极管&#xff09; PN 结是采用不同的掺杂工艺&#xff0c;将 P 型半导体与 N 型半导体紧密接触而形成的一个界面区域。也就是我们常说的二极管。&#xff08;P型带正电、N型带负电&#xff0c;电流由P流向N&#xff09; 形成过程&#xff1…...

4. k8s核心概念 pod deployment service

以下是 Kubernetes 的核心概念详解&#xff0c;涵盖 Pod、Service、Deployment 和 Node&#xff0c;以及它们之间的关系和实际应用场景&#xff1a; 1. Pod 定义与作用 • 最小部署单元&#xff1a;Pod 是 Kubernetes 中可创建和管理的最小计算单元&#xff0c;包含一个或多个…...

12.第二阶段x64游戏实战-远程调试

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 上一个内容&#xff1a;11.第二阶段x64游戏实战-框架代码细节优化 本次写的内容是关于调试、排错相关的…...

自然语言处理的进化:BERT模型深度剖析

自然语言处理&#xff08;NLP&#xff09;领域近年来取得了跨越式的发展&#xff0c;尤其是随着深度学习技术的应用&#xff0c;不少新兴模型应运而生。其中&#xff0c;BERT&#xff08;Bidirectional Encoder Representations from Transformers&#xff09;作为一种革命性的…...

鸿蒙学习笔记(5)-HTTP请求数据

一、Http请求数据 http模块是鸿蒙内置的一个模块&#xff0c;提供了网络请求的能力。不需要再写比较原始的AJAS代码。 ps:在项目中如果要访问网络资源&#xff0c;不管是图片文件还是网络请求&#xff0c;必须给项目开放权限。 &#xff08;1&#xff09;网络连接方式 HTTP数…...

Golang 的 GMP 协程模型详解

Golang 的 GMP 协程模型详解 Golang 的并发模型基于 GMP&#xff08;Goroutine-M-Processor&#xff09; 机制&#xff0c;是其高并发能力的核心支撑。以下从原理、机制、优势、缺点和设计理念展开分析&#xff1a; 一、GMP 的组成与运作原理 Goroutine&#xff08;G&#xff…...

ReportLab 导出 PDF(页面布局)

ReportLab 导出 PDF&#xff08;文档创建&#xff09; ReportLab 导出 PDF&#xff08;页面布局&#xff09; ReportLab 导出 PDF&#xff08;图文表格) PLATYPUS - 页面布局和排版 1. 设计目标2. 开始3. Flowables3.1. Flowable.draw()3.2. Flowable.drawOn(canvas,x,y)3.3. F…...

Ubuntu 安装与配置 Docker

Ubuntu 安装与配置 Docker Docker 是一个开源的容器化平台&#xff0c;允许开发者将应用程序及其依赖项打包在一个轻量级、可移植的容器中。它可以帮助开发者和运维人员快速构建、部署和管理应用程序&#xff0c;提升开发和运维效率。本文将介绍如何在 Ubuntu 系统上安装和配置…...

【数据结构与算法】LeetCode每日一题

此题跟27.移除数组中的指定值 类似&#xff0c;都是移除且双指针玩法&#xff0c;只不过判断条件发生了变化...

【HDFS入门】数据存储原理全解,从分块到复制的完整流程剖析

目录 1 HDFS架构概览 2 文件分块机制 2.1 为什么需要分块&#xff1f; 2.2 块大小配置 3 数据写入流程 4 数据复制机制 4.1 副本放置策略 4.2 复制流程 5 数据读取流程 6 一致性模型 7 容错机制 7.1 数据节点故障处理 7.2 校验和验证 8 总结 在大数据时代&#x…...

力扣热题100——普通数组(不普通)

普通数组但一点不普通&#xff01; 最大子数组和合并区间轮转数组除自身以外数组的乘积缺失的第一个正数 最大子数组和 这道题是非常经典的适用动态规划解决题目&#xff0c;但同时这里给出两种解法 动态规划、分治法 那么动态规划方法大家可以在我的另外一篇博客总结中看到&am…...

Ubuntu中snap

通过Snap可以安装众多的软件包。需要注意的是&#xff0c;snap是一种全新的软件包管理方式&#xff0c;它类似一个容器拥有一个应用程序所有的文件和库&#xff0c;各个应用程序之间完全独立。所以使用snap包的好处就是它解决了应用程序之间的依赖问题&#xff0c;使应用程序之…...

uniapp(Vue)开发微信小程序 之 保存图片到本地

一、保存图片到本地&#xff08;要拿到图片的 src&#xff09;&#xff1a; 查看隐私条约是否加上相册&#xff08;仅写入&#xff09;权限&#xff1a; 微信公众平台 -》 左下角头像 -》账号设置 -》 用户隐私保护指引 -》去完善 -》 相册&#xff08;仅写入&#xff09;权限 …...

TailwindCss快速上手

什么是Tailwind Css? 一个实用优先的 CSS 框架&#xff0c;可以直接在标记中组合以构建任何设计。 开始使用Tailwind Css 如何安装 下面是使用vite构建工具的方法 ①安装 Tailwind CSS: tailwindcss通过tailwindcss/vitenpm安装。 npm install tailwindcss tailwindcss…...

Gladinet CentreStack Triofox 远程RCE漏洞(CVE-2025-30406)

免责声明 本文档所述漏洞详情及复现方法仅限用于合法授权的安全研究和学术教育用途。任何个人或组织不得利用本文内容从事未经许可的渗透测试、网络攻击或其他违法行为。使用者应确保其行为符合相关法律法规,并取得目标系统的明确授权。 对于因不当使用本文信息而造成的任何直…...

ASP.NET WEB 手动推送 URL 到百度站长工具实例

下面是一个完整的 ASP.NET Web 应用程序示例,演示如何手动推送 URL 到百度站长工具。 1. 创建推送页面 (PushToBaidu.aspx) <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="PushToBaidu.aspx.cs" Inherits="BaiduPushEx…...

【Ragflow】18.更好的推理框架:vLLM的docker部署方式

概述 看到不少人说“Ollama就图一乐,生产环境还得用vLLM”。 本文决定使用docker对vLLM进行部署,并解决模型配置中,IP地址的硬编码问题。 Ollama与vLLM风评比较 查询相关资料,Ollama与vLLM主要特点及对比情况如下[1]: Ollama:轻量级本地大模型部署工具,面向个人用户…...

智能 GitHub Copilot 副驾驶® 更新升级!

智能 GitHub Copilot 副驾驶 迎来重大升级&#xff01;现在&#xff0c;所有 VS Code 用户都能体验支持 Multi-Context Protocol&#xff08;MCP&#xff09;的全新 Agent Mode。此外&#xff0c;微软还推出了智能 GitHub Copilot 副驾驶 Pro 订阅计划&#xff0c;提供更强大的…...

什么是高防服务器

高防服务器是具备高强度防御能力、专门应对网络攻击(如DDoS、 CC攻击)的服务器类 型&#xff0c;通过流量清洗、多层防护等技术保障业务稳定运行。具备高强度防御能力和智能攻击识别技术&#xff0c;可保障业务在极端网络环境下稳定运行。其核心特点及技术原理如下&#xff1a…...

纷析云开源财务软件:企业财务数字化转型的灵活解决方案

纷析云是一家专注于开源财务软件研发的公司&#xff0c;自2018年成立以来&#xff0c;始终以“开源开放”为核心理念&#xff0c;致力于通过技术创新助力企业实现财务管理的数字化与智能化转型。其开源财务软件凭借高扩展性、灵活部署和全面的功能模块&#xff0c;成为众多企业…...

open webui 介绍 是一个可扩展、功能丰富且用户友好的本地部署 AI 平台,支持完全离线运行。

AI MCP 系列 AgentGPT-01-入门介绍 Browser-use 是连接你的AI代理与浏览器的最简单方式 AI MCP(大模型上下文)-01-入门介绍 AI MCP(大模型上下文)-02-awesome-mcp-servers 精选的 MCP 服务器 AI MCP(大模型上下文)-03-open webui 介绍 是一个可扩展、功能丰富且用户友好的…...

Spring缓存抽象机制

一、核心架构图解 #mermaid-svg-pUShmqsPanYTNVBI {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-pUShmqsPanYTNVBI .error-icon{fill:#552222;}#mermaid-svg-pUShmqsPanYTNVBI .error-text{fill:#552222;stroke:#5…...

[Jenkins]pnpm install ‘pnpm‘ 不是内部或外部命令,也不是可运行的程序或批处理文件。

这个错误提示再次说明&#xff1a;你的系统&#xff08;CMD 或 Jenkins 环境&#xff09;找不到 pnpm 命令的位置。虽然你可能已经用 npm install -g pnpm 安装过&#xff0c;但系统不知道它装在哪里&#xff0c;也就无法执行 pnpm 命令。 ✅ 快速解决方法&#xff1a;直接用完…...

如何用AI辅助数据分析及工具推荐

以下是针对数据分析的 AI辅助工具推荐&#xff0c;结合国内外主流工具的功能特点、优劣势及适用场景分析&#xff0c;并标注是否为国内软件及付费情况&#xff1a; 一、国内工具推荐 1. WPS AI 特点&#xff1a;集成于WPS Office套件&#xff0c;支持智能数据分析、自动生成可…...

使用KeilAssistant代替keil的UI界面

目录 一、keil Assistant的优势和缺点 二、使用方法 &#xff08;1&#xff09;配置keil的路径 &#xff08;2&#xff09;导入并使用工程 &#xff08;3&#xff09;默认使用keil自带的ARM编译器而非GUN工具链 一、keil Assistant的优势和缺点 在日常学…...

spark-SQL数据加载和保存

数据加载与保存 通用方式&#xff1a; 通过 spark.read.load 和 df.write.save 实现数据加载与保存。可利用 format 指定数据格式&#xff0c;如 csv 、 jdbc 等&#xff1b; option 用于设置特定参数&#xff0c;像 jdbc 格式下的数据库连接信息&#xff1b; load 和 save 则…...

strings.Replace 使用详解

目录 1. 官方包 2. 支持版本 3. 官方说明 4. 作用 5. 实现原理 6. 推荐使用场景和不推荐使用场景 推荐场景 不推荐场景 7. 使用场景示例 示例1&#xff1a;官方示例 示例2&#xff1a;模板变量替换 示例3&#xff1a;敏感信息脱敏&#xff08;隐藏手机号中间四位&a…...

K8S微服务部署及模拟故障观测

概述 本文介绍了如何在 Kubernetes (K8S) 集群中部署微服务&#xff0c;并模拟常见的故障场景&#xff08;如 Pod 故障、节点故障、网络故障&#xff09;以测试系统的容错能力。通过本实验&#xff0c;了解 Kubernetes 的自动恢复机制以及如何通过监控和日志分析快速定位和解决…...