介绍
一些有趣的编程练习题用来练习学过的知识
数字相关
猜数字游戏
python
from random import randint
def main():
chances = 3 # 总共有多少次输入(猜测)的机会
is_win = False # 是否赢得游戏
print(f"猜数字游戏开始, 你有 {chances} 次机会!")
min_num = 0
max_num = 10
print(f"请输入[{min_num} - {max_num}]范围内的一个数字!")
anwser_num = randint(min_num, max_num)
# print(f"答案是: {anwser_num}")
while chances > 0:
chances -= 1
input_num = int(input("请输入一个数字: \n "))
if input_num < min_num or input_num > max_num:
print(f"输入的数字超出范围, 你还有{chances}次机会!!")
elif input_num > anwser_num:
print(f"你猜的数字大于答案, 你还有{chances}次机会!")
elif input_num < anwser_num:
print(f"你猜的数字小于答案, 你还有{chances}次机会!")
else:
is_win = True
print("🎉 恭喜你猜对了, 你赢得了游戏")
break
if not is_win:
print("😢 游戏结束, 你输了")
if __name__ == "__main__":
main()向上/向下/四舍五入取整
python
import math
def main():
f1 = 1.1
f2 = 1.8
f3 = 1.5
f4 = 1.4
# 向上取整
print(f"{f1} 向上取整: {math.ceil(f1)}")
print(f"{f2} 向上取整: {math.ceil(f2)}")
print(f"{f3} 向上取整: {math.ceil(f3)}")
print(f"{f4} 向上取整: {math.ceil(f4)}")
# 向下取整
print(f"{f1} 向下取整: {math.floor(f1)}")
print(f"{f2} 向下取整: {math.floor(f2)}")
print(f"{f3} 向下取整: {math.floor(f3)}")
print(f"{f4} 向下取整: {math.floor(f4)}")
# 四舍五入取整: 注意是使用 builtins.round 而不是 math.round
print(f"{f1} 四舍五入取整: {round(f1)}")
print(f"{f2} 四舍五入取整: {round(f2)}")
print(f"{f3} 四舍五入取整: {round(f3)}")
print(f"{f4} 四舍五入取整: {round(f4)}")
if __name__ == "__main__":
main()最大/最小/绝对值/求和/求平均值
python
def main():
nums = [1, 3, 5, -7, -9, 12, 18]
print(f"{nums}中的最大值{max(nums)}")
print(f"{nums}中的最小值{min(nums)}")
print(f"{nums}中的所有数字的和{sum(nums)}")
print(f"{nums}中的所有数字的平均值{sum(nums) / len(nums)}")
print(f"一个数字的绝对值: -5 绝对值{abs(-5)}, 6 绝对值{abs(6)}")
print(f"一个数字的n次方: 5 的 2 次方: {5**2}, 2 的 5 次方:{pow(2, 5)}")
if __name__ == "__main__":
main()日期时间处理
python
from datetime import datetime
import time
def main():
# 1.获取当前日期+时间+毫秒
now = datetime.now()
print("now:", now) # 2020-01-12 12:01:33.053142
# 2.获取当前的日期
date = datetime.now().date()
print("date:", date) # 2020-01-12
# 3.获取格式化的日期+时间字符串
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print("formated datetime:", now) # 2020-01-12 12:01:33
# 4.获取当前时间戳
timestamp = int(datetime.now().timestamp())
print("timestamp:", timestamp) # 1600709953
# 5.使用 time 模块获取时间戳(秒)
timestamp = int(time.time())
print("timestamp:", timestamp) # 1600709953.053142
# 6.获取指定时间的时间戳
time_str = "2024-03-20 12:00:00"
time_tuple = time.strptime(time_str, "%Y-%m-%d %H:%M:%S")
time_stamp = int(time.mktime(time_tuple))
print("time_stamp:", time_stamp) # 1710907200
if __name__ == "__main__":
main()字符串处理
- https://docs.python.org/zh-cn/3.14/library/stdtypes.html#text-and-binary-sequence-type-methods-summary
- https://docs.python.org/zh-cn/3.14/library/string.html
格式化
python
def main():
# f 模板字符串
user = "tom"
message = f"hello {user}!"
print(message)
# format 方法
formated_str = "{a} + {b} = {result}".format(a=1, b=2, result=1 + 2)
print(formated_str)
if __name__ == "__main__":
main()搜索替换
python
def main():
message = "python is best program language in the world!"
### 搜索 ###
# 1.find 方法查询子字符串的开始位置
start_idx1 = message.find("best") # 找到返回开始索引位置10
start_idx2 = message.find("hello") # 找不到返回 -1
print(start_idx1, start_idx2)
# 2.index 方法查询子字符串的开始位置
start_idx3 = message.index("best") # 找到返回开始索引位置 10
print(start_idx3)
# index 找不到抛出异常: ValueError: substring not found
# start_idx4 = message.index("hello")
# print(start_idx4)
# 3.字符串是否以某个字符串开始/结尾
if message.startswith("python"):
print("message starts with python")
if message.endswith("world"):
print("message ends with world")
# 4.一个字符串是否包含某个字符串
# 4.1 使用 find/index 方法
if message.find("best") != -1:
print("best is in message")
try:
message.index("bast")
print("bast is in message")
except ValueError:
print("bast not is in message")
# 4.2 使用 in/not in 运算符
if "best" in message:
print("best is in message")
if "bast" in message:
print("bast is in message")
else:
print("bast not in message")
if "bast" not in message:
print("bast not in message")
### 替换 ###
# 1.直接替换
result = message.replace("world", "universe")
print(result)
# 2.替换所有
strs = "donwload.apple.com,update.apple.com,shop.apple.com"
result = strs.replace("apple", "pear")
print(result) # donwload.pear.com,update.pear.com,shop.pear.com
# 3.只替换一次
result = strs.replace("apple", "pear", 1)
print(result) # donwload.pear.com,update.apple.com,shop.apple.com
if __name__ == "__main__":
main()拆分合并
python
def main():
# split: 将字符串切割为列表
strs = "donwload.apple.com,update.apple.com,shop.apple.com"
urls = strs.split(",")
print(urls) # ['donwload.apple.com', 'update.apple.com', 'shop.apple.com']
# join: 将列表合并为字符串
str2 = "-".join(urls)
print(str2) # donwload.apple.com-update.apple.com-shop.apple.com
# +运算符/模板字符串拼接两个字符串
str1 = "abc"
str2 = "def"
str3 = str1 + str2
str4 = f"{str1}{str2}"
print(str3) # abcdef
print(str4) # abcdef
if __name__ == "__main__":
main()字符串分类
python
def main():
# 1.是否是全部大写
print("abc".isupper())
print("aBc".isupper())
print("ABC".isupper())
# 2.是否是全部小写
print("abc".islower())
print("aBc".islower())
print("ABC".islower())
# 3.是否是空白字符
print("".isspace()) # 空字符串 False
print(" ".isspace()) # 空格 True
print("\t".isspace()) # 制表符 True
print("\n".isspace()) # 换行符 True
if __name__ == "__main__":
main()大小写操作
python
def main():
# 1.全部转大写
print("abc abc".upper()) # ABC ABC
# 2.全部转小写
print("aBc aBc".lower()) # abc abc
# 3.首字母大写
print("abc abc".capitalize()) # Abc abc
if __name__ == "__main__":
main()填充去除操作
python
def main():
# 去除两边空白字符(包含空格/制表符/换行)
print(" abc\t ".strip() + "def") # abcdef
# 去除两边空格字符(不包括换行和tab)
print(" abc\t ".strip(" ") + "def") # abc\tdef
# 去除指定的非空字符
print("###abc@@@".strip("#@")) # abc
# 去除左边的指定字符
print("###abc@@@".lstrip("#@")) # abc@@@
# 去除右边的指定字符
print("###abc@@@".rstrip("#@")) # ###abc
if __name__ == "__main__":
main()转写与编码格式
python
def main():
# 字符串转二进制数据
message = "python is a easy to learn, powerful programming language!"
bytes_msg = message.encode("utf-8")
print(bytes_msg)
# 二进制数据转字符串
bytes2 = b"python is a easy programming language!"
print(bytes2.decode("utf-8"))
# 字符串转unicode
message = "你好,python"
unicode_msg = message.encode("unicode_escape")
print(unicode_msg)
# unicode转字符串
print(unicode_msg.decode("unicode_escape"))
if __name__ == "__main__":
main()列表
- https://docs.python.org/zh-cn/3.14/library/stdtypes.html#lists
- https://docs.python.org/zh-cn/3.14/tutorial/datastructures.html#more-on-lists
python
from types import FunctionType
def main():
# 1.元组转列表
lst1 = list((1, 2, 3, 4, 5))
print(lst1)
# 2.字符串转切割为列表
lst2 = "hello world".split(" ")
print(lst2)
# 3.判断是否是列表
if isinstance(lst2, list):
print("lst2 is list")
# 4.列表是否包含某个元素
if "hello" in lst2:
print("hello in lst2")
if "hi" not in lst2:
print("hi not in lst2")
# 5.拼接两个数组
merged = lst1 + lst2
print(merged)
# 6. 遍历数组
for i in lst2:
print(i)
# 7. map 闭包获得新列表
lst3 = list(map(lambda x: x * 2, lst1))
print(lst3)
# 8. filter 过滤获得新列表
# lst4 = [num for num in lst1 if num % 2 == 0]
lst4 = list(filter(lambda x: x % 2 == 0, lst1))
print(lst4)
# 9.查询是否有符合条件的
def find(lst: list, handler: FunctionType):
for item in lst:
if handler(item):
return item
target1 = find([1, 2, 3, 4, 5], lambda x: x > 3)
target2 = find([1, 2, 3, 4, 5], lambda x: x > 10)
print(f"target1={target1}, target2={target2}")
# 10.是否所有元素都符合条件
def every(lst: list, handler: FunctionType):
for item in lst:
if not handler(item):
return False
return True
every1 = every([4, 5, 6, 7, 8], lambda x: x > 3)
every2 = every([4, 5, 6, 7, 8], lambda x: x > 5)
print(f"every1={every1}, every2={every2}")
# 11. 是否有一个元素符合条件
def some(lst: list, handler: FunctionType):
for item in lst:
if handler(item):
return True
return False
some1 = some([4, 5, 6, 7, 8], lambda x: x > 5)
some2 = some([4, 5, 6, 7, 8], lambda x: x > 10)
print(f"some1={some1}, some2={some2}")
# pop/shift
items = [1, 2, 3, 4, 5]
pop_item = items.pop()
shift_item = items.pop(0)
print(f"items={items}, pop_item={pop_item}, shift_item={shift_item}")
# unshift/push
items = [1, 3, 5]
items.append(7)
print(f"items={items}")
items.insert(0, 9)
print(f"items={items}")
# 排序
origin = [9, 8, 7, 1, 3, 5]
origin.sort()
print(f"origin={origin}")
# 根据集合的某一列排序
items = [
{
"id": 1002,
"name": "张三",
},
{
"id": 1003,
"name": "李四",
},
{
"id": 1001,
"name": "王五",
},
]
items.sort(key=lambda x: x["id"])
print(items)
if __name__ == "__main__":
main()字典
python
def main():
obj = {
"id": 1001,
"name": "张三",
}
# 1.是否有某个key
if "id" in obj:
print("有id属性")
# 2.获取某个属性
# 2.1 获取存在的键
print(obj["id"])
print(obj.get("id"))
# 2.1 获取可能不存在的键, 使用默认值
print(obj.get("name", "zhangsang"))
print(obj.get("email", "zhangsang@example.com"))
# 3.设置值
# 3.1 使用 [] 语法
obj["age"] = 18
# 3.2 使用 update 方法
obj.update(name="zhangsang")
print(obj)
# 4.获取所有key/value
print(obj.keys())
print(obj.values())
# 5.删除值
# 5.1 删除某个键
del obj["age"]
print(obj)
# 5.2 删除所有键
obj.clear()
print(obj)
if __name__ == "__main__":
main()执行操作系统命令
python
import subprocess
def main():
# 1.执行操作系统命令
results = subprocess.run(["python", "--version"], capture_output=True, text=True)
# 2.获取命令执行是否成功 returncode = 0 表示执行成功
print(results.returncode)
# 3.获取命令执行的输出结果
print(results.stdout)
# 4.执行封装的函数
result2 = exec_os_cmd(["date", "+%Y-%m-%d"])
print(result2)
# 4. 封装一个函数
def exec_os_cmd(cmd, **kwargs):
"""安全执行命令的简易封装"""
kwargs.setdefault("capture_output", True)
kwargs.setdefault("text", True)
kwargs.setdefault("check", False)
try:
result = subprocess.run(cmd, **kwargs)
return {
"success": result.returncode == 0,
"stdout": result.stdout.strip() if result.stdout else "",
"stderr": result.stderr.strip() if result.stderr else "",
"returncode": result.returncode,
}
except Exception as e:
return {
"success": False,
"error": str(e),
}
if __name__ == "__main__":
main()实现 Stack
使用列表来实现
python
class Stack:
__items = []
def __init__(self):
self.__items = []
# 栈大小
def size(self):
return len(self.__items)
# 是否为空
def is_empty(self):
return self.size() == 0
# 查看最后一个但是不出栈
def peek(self):
if not self.is_empty():
return self.__items[self.size() - 1]
# 压栈
def push(self, item):
self.__items.append(item)
# 出栈
def pop(self):
return self.__items.pop()
# 清栈
def clear(self):
self.__items.clear()python
import unittest
from stack import Stack
class TestStack(unittest.TestCase):
def test_init(self):
s = Stack()
self.assertTrue(isinstance(s, Stack))
self.assertEqual(s.size(), 0)
self.assertTrue(s.is_empty())
def test_push(self):
s = Stack()
s.push(1)
self.assertEqual(s.size(), 1)
self.assertFalse(s.is_empty())
def test_peek(self):
s = Stack()
s.push(1)
last = s.peek()
self.assertEqual(last, 1)
s.push(2)
last = s.peek()
self.assertEqual(last, 2)
def test_pop(self):
s = Stack()
s.push(1)
s.push(2)
s.push(3)
last = s.pop()
self.assertEqual(last, 3)
last = s.pop()
self.assertEqual(last, 2)
last = s.pop()
self.assertEqual(last, 1)
self.assertTrue(s.is_empty())
def test_clear(self):
s = Stack()
s.push(1)
s.push(2)
s.push(3)
s.clear()
self.assertTrue(s.is_empty())
if __name__ == "__main__":
unittest.main()实现 Queue
python
class Queue:
def __init__(self):
self.__items = []
# 队列是否为空
def is_empty(self):
return self.size() == 0
# 队列的长度
def size(self):
return len(self.__items)
# 入列
def enqueue(self, value):
self.__items.append(value)
# 出列
def dequeue(self):
return self.__items.pop(0)
# 清除队列
def clear(self):
self.__items.clear()python
import unittest
from queue import Queue
class TestQueue(unittest.TestCase):
def test_init(self):
q = Queue()
self.assertTrue(isinstance(q, Queue))
def test_enqueue(self):
q = Queue()
self.assertEqual(q.size(), 0)
q.enqueue(1)
q.enqueue(2)
q.enqueue(3)
self.assertEqual(q.size(), 3)
def test_dequeue(self):
q = Queue()
q.enqueue(1)
q.enqueue(2)
self.assertEqual(q.size(), 2)
v = q.dequeue()
self.assertEqual(q.size(), 1)
self.assertEqual(v, 1)
v = q.dequeue()
self.assertEqual(q.size(), 0)
self.assertEqual(v, 2)
def test_clear(self):
q = Queue()
q.enqueue(1)
q.enqueue(2)
self.assertEqual(q.size(), 2)
q.clear()
self.assertEqual(q.size(), 0)
def test_is_empty(self):
q = Queue()
self.assertTrue(q.is_empty())
q.enqueue(1)
self.assertFalse(q.is_empty())
q.dequeue()
self.assertTrue(q.is_empty())
if __name__ == "__main__":
unittest.main()实现链表
- 单链表: LinkedLis
- 双向链表: DoublyLinkedList
- 环形链表: CirularLinkedList
python
from typing import Self
class LinkedListNode:
def __init__(self, value):
self.value = value
self.next = None
def set_next(self, node):
self.next = node
def is_linkedlist_node(node):
return isinstance(node, LinkedListNode)
class LinkedList:
def __init__(self):
self.__head = None
self.__tail = None
self.__size = 0 # 添加 size 便于操作
# 头部添加节点
def prepend(self, value) -> Self:
new_node = LinkedListNode(value)
if self.__head is None:
self.__head = new_node
self.__tail = new_node
else:
new_node.next = self.__head
self.__head = new_node
self.__size += 1
return self
# 尾部添加节点
def append(self, value) -> Self:
new_node = LinkedListNode(value)
if self.__tail is None:
self.__head = new_node
self.__tail = new_node
else:
self.__tail.next = new_node
self.__tail = new_node
self.__size += 1
return self
# 指定位置插入节点
def insert(self, raw_index, value) -> Self:
# 处理负数索引
if raw_index < 0:
index = self.__size + raw_index
else:
index = raw_index
# 边界检查
if index < 0 or index > self.__size:
raise IndexError(f"Index {raw_index} out of range")
# 头部插入
if index == 0:
return self.prepend(value)
# 尾部插入
if index == self.__size:
return self.append(value)
# 中间插入
new_node = LinkedListNode(value)
current = self.__head
for _ in range(index - 1):
current = current.next
new_node.next = current.next
current.next = new_node
self.__size += 1
return self
# 移除指定值的节点(删除第一个匹配的)
def delete(self, value):
if self.__head is None:
return None
# 头部匹配
if self.__head.value == value:
return self.delete_head()
current = self.__head
while current.next:
if current.next.value == value:
deleted_node = current.next
current.next = current.next.next
if current.next is None: # 删除的是尾节点
self.__tail = current
self.__size -= 1
return deleted_node.value
current = current.next
return None
# 删除头部节点
def delete_head(self):
if self.__head is None:
return None
deleted_value = self.__head.value
self.__head = self.__head.next
if self.__head is None: # 链表为空了
self.__tail = None
self.__size -= 1
return deleted_value
# 删除尾部节点
def delete_tail(self):
if self.__tail is None:
return None
if self.__head == self.__tail: # 只有一个节点
return self.delete_head()
current = self.__head
while current.next != self.__tail:
current = current.next
deleted_value = self.__tail.value
current.next = None
self.__tail = current
self.__size -= 1
return deleted_value
# 根据值查找节点
def find_value(self, value):
current = self.__head
index = 0
while current:
if current.value == value:
return index
current = current.next
index += 1
return -1
# 根据自定义函数查找节点
def find(self, func):
current = self.__head
index = 0
while current:
if func(current.value):
return {"index": index, "value": current.value}
current = current.next
index += 1
return None
# 将链表转为列表
def to_list(self):
result = []
current = self.__head
while current:
result.append(current.value)
current = current.next
return result
# 将链表转为字符串
def __str__(self):
values = self.to_list()
return " -> ".join(str(v) for v in values) if values else "Empty"
# 将 list 转为链表
@staticmethod
def from_list(items: list):
ll = LinkedList()
for item in items:
ll.append(item)
return ll
# 辅助方法:获取长度
def __len__(self):
return self.__size
# 辅助方法:判空
def is_empty(self):
return self.__size == 0python
from typing import Self, Optional, Any, Callable, Dict, List
class DoublyListNode:
def __init__(self, value):
self.value = value
self.next: Optional[DoublyListNode] = None
self.prev: Optional[DoublyListNode] = None
def is_doublylinkedlist_node(node) -> bool:
return isinstance(node, DoublyListNode)
class DoublyLinkedList:
def __init__(self):
self.__head: Optional[DoublyListNode] = None
self.__tail: Optional[DoublyListNode] = None
self.__size = 0
# 头部添加
def prepend(self, value) -> Self:
new_node = DoublyListNode(value)
if self.__head is None:
self.__head = self.__tail = new_node
else:
new_node.next = self.__head
self.__head.prev = new_node
self.__head = new_node
self.__size += 1
return self
# 尾部添加
def append(self, value) -> Self:
new_node = DoublyListNode(value)
if self.__tail is None:
self.__head = self.__tail = new_node
else:
new_node.prev = self.__tail
self.__tail.next = new_node
self.__tail = new_node
self.__size += 1
return self
# 指定位置插入(支持负索引)
def insert(self, raw_index: int, value) -> Self:
if raw_index < 0:
index = self.__size + raw_index
else:
index = raw_index
if index < 0 or index > self.__size:
raise IndexError(f"Index {raw_index} out of range for size {self.__size}")
if index == 0:
return self.prepend(value)
if index == self.__size:
return self.append(value)
# 在中间插入:找到 index-1 位置的节点(prev_node)
prev_node = self.__head
for _ in range(index - 1):
prev_node = prev_node.next
new_node = DoublyListNode(value)
next_node = prev_node.next
new_node.prev = prev_node
new_node.next = next_node
prev_node.next = new_node
if next_node is not None:
next_node.prev = new_node
self.__size += 1
return self
# 删除第一个匹配 value 的节点
def delete(self, value) -> Optional[Any]:
if self.__head is None:
return None
# 头部匹配
if self.__head.value == value:
return self.delete_head()
current = self.__head
while current.next:
if current.next.value == value:
target = current.next
# 断开 target
current.next = target.next
if target.next:
target.next.prev = current
else:
self.__tail = current # target was tail
self.__size -= 1
return target.value
current = current.next
return None
# 删除头节点
def delete_head(self) -> Optional[Any]:
if self.__head is None:
return None
deleted_value = self.__head.value
if self.__head == self.__tail: # only one node
self.__head = self.__tail = None
else:
self.__head = self.__head.next
self.__head.prev = None
self.__size -= 1
return deleted_value
# 删除尾节点
def delete_tail(self) -> Optional[Any]:
if self.__tail is None:
return None
if self.__head == self.__tail:
return self.delete_head()
deleted_value = self.__tail.value
self.__tail = self.__tail.prev
self.__tail.next = None
self.__size -= 1
return deleted_value
# 查找值首次出现的索引
def find_value(self, value) -> int:
current = self.__head
index = 0
while current:
if current.value == value:
return index
current = current.next
index += 1
return -1
# 根据函数查找(返回字典)
def find(self, func: Callable[[Any], bool]) -> Optional[Dict[str, Any]]:
current = self.__head
index = 0
while current:
if func(current.value):
return {"index": index, "value": current.value}
current = current.next
index += 1
return None
# 转为普通 list
def to_list(self) -> List[Any]:
result = []
current = self.__head
while current:
result.append(current.value)
current = current.next
return result
# 字符串表示(正向)
def __str__(self) -> str:
values = self.to_list()
return " <-> ".join(str(v) for v in values) if values else "Empty"
# 从 list 构建
@staticmethod
def from_list(items: List[Any]) -> Self:
dll = DoublyLinkedList()
for item in items:
dll.append(item)
return dll
# 长度协议
def __len__(self) -> int:
return self.__size
# 判空
def is_empty(self) -> bool:
return self.__size == 0
# ✨ 新增:反向遍历(可用于调试或扩展)
def to_list_reverse(self) -> List[Any]:
result = []
current = self.__tail
while current:
result.append(current.value)
current = current.prev
return resultpython
class CircularListNode:
def __init__(self, value):
self.value = value
self.next: Optional[CircularListNode] = None
def is_circularlinkedlist_node(node) -> bool:
return isinstance(node, CircularListNode)
class CircularLinkedList:
def __init__(self):
self.__head: Optional[CircularListNode] = None
self.__tail: Optional[CircularListNode] = None # 用于 O(1) 尾插/删
self.__size = 0
# 头部添加(新节点成为新 head)
def prepend(self, value) -> Self:
new_node = CircularListNode(value)
if self.__head is None:
self.__head = self.__tail = new_node
self.__head.next = self.__head # 自循环
else:
# 插入到 head 前:即 tail → new → head
new_node.next = self.__head
self.__tail.next = new_node
self.__head = new_node
self.__size += 1
return self
# 尾部添加(新节点成为新 tail)
def append(self, value) -> Self:
new_node = CircularListNode(value)
if self.__head is None:
self.__head = self.__tail = new_node
self.__head.next = self.__head
else:
new_node.next = self.__head
self.__tail.next = new_node
self.__tail = new_node
self.__size += 1
return self
# 指定位置插入(支持负索引)
def insert(self, raw_index: int, value) -> Self:
if raw_index < 0:
index = self.__size + raw_index
else:
index = raw_index
if index < 0 or index > self.__size:
raise IndexError(f"Index {raw_index} out of range for size {self.__size}")
if index == 0:
return self.prepend(value)
if index == self.__size:
return self.append(value)
# 找到第 index-1 个节点(prev)
prev = self.__head
for _ in range(index - 1):
prev = prev.next
new_node = CircularListNode(value)
new_node.next = prev.next
prev.next = new_node
# 若插入在 tail 后(即原 tail → head),则更新 tail
if prev == self.__tail:
self.__tail = new_node
self.__size += 1
return self
# 删除第一个匹配 value 的节点
def delete(self, value) -> Optional[Any]:
if self.__head is None:
return None
# 头部匹配
if self.__head.value == value:
return self.delete_head()
current = self.__head
while current.next != self.__head:
if current.next.value == value:
target = current.next
current.next = target.next
if target == self.__tail:
self.__tail = current
self.__size -= 1
return target.value
current = current.next
return None
# 删除头节点
def delete_head(self) -> Optional[Any]:
if self.__head is None:
return None
deleted_value = self.__head.value
if self.__head == self.__tail: # only one node
self.__head = self.__tail = None
else:
self.__tail.next = self.__head.next
self.__head = self.__head.next
self.__size -= 1
return deleted_value
# 删除尾节点
def delete_tail(self) -> Optional[Any]:
if self.__tail is None:
return None
if self.__head == self.__tail:
return self.delete_head()
# 找到 tail 的前驱(即 tail.prev 逻辑)
prev = self.__head
while prev.next != self.__tail:
prev = prev.next
deleted_value = self.__tail.value
prev.next = self.__head
self.__tail = prev
self.__size -= 1
return deleted_value
# 查找值首次出现的索引(最多遍历 size 次)
def find_value(self, value) -> int:
if self.__head is None:
return -1
current = self.__head
index = 0
# 安全计数避免死循环(理论上不会超 size)
for _ in range(self.__size):
if current.value == value:
return index
current = current.next
index += 1
return -1
# 根据函数查找
def find(self, func: Callable[[Any], bool]) -> Optional[Dict[str, Any]]:
if self.__head is None:
return None
current = self.__head
index = 0
for _ in range(self.__size):
if func(current.value):
return {"index": index, "value": current.value}
current = current.next
index += 1
return None
# 转为普通 list(正向,从 head 开始)
def to_list(self) -> List[Any]:
if self.__head is None:
return []
result = []
current = self.__head
for _ in range(self.__size):
result.append(current.value)
current = current.next
return result
# 字符串表示(显示循环性,加 `(circular)` 提示)
def __str__(self) -> str:
values = self.to_list()
if not values:
return "Empty (circular)"
return " -> ".join(str(v) for v in values) + " -> (back to head)"
# 从 list 构建
@staticmethod
def from_list(items: List[Any]) -> Self:
cll = CircularLinkedList()
for item in items:
cll.append(item)
return cll
# 长度协议
def __len__(self) -> int:
return self.__size
# 判空
def is_empty(self) -> bool:
return self.__size == 0python
import unittest
from linkedlist import LinkedList, LinkedListNode, is_linkedlist_node
class TestLinkedList(unittest.TestCase):
def setUp(self):
"""每个测试前创建空链表"""
self.ll = LinkedList()
def test_prepend(self):
"""测试头部添加"""
self.ll.prepend(1).prepend(2).prepend(3)
self.assertEqual(self.ll.to_list(), [3, 2, 1])
self.assertEqual(len(self.ll), 3)
def test_append(self):
"""测试尾部添加"""
self.ll.append(1).append(2).append(3)
self.assertEqual(self.ll.to_list(), [1, 2, 3])
self.assertEqual(len(self.ll), 3)
def test_insert(self):
"""测试指定位置插入"""
self.ll.append(1).append(3)
self.ll.insert(1, 2) # 1 -> 2 -> 3
self.assertEqual(self.ll.to_list(), [1, 2, 3])
# 头部插入
self.ll.insert(0, 0)
self.assertEqual(self.ll.to_list()[0], 0)
# 尾部插入
self.ll.insert(4, 4)
self.assertEqual(self.ll.to_list(), [0, 1, 2, 3, 4])
def test_insert_negative_index(self):
"""测试负数索引插入"""
self.ll.append(1).append(2).append(3)
self.ll.insert(-1, 99) # 在倒数第1个位置插入(即索引2)
self.assertEqual(self.ll.to_list(), [1, 2, 99, 3])
def test_insert_out_of_range(self):
"""测试越界插入"""
with self.assertRaises(IndexError):
self.ll.insert(5, 1)
def test_delete(self):
"""测试删除指定值"""
self.ll.append(1).append(2).append(3).append(2)
# 删除中间的2
self.assertEqual(self.ll.delete(2), 2)
self.assertEqual(self.ll.to_list(), [1, 3, 2])
# 删除不存在的值
self.assertIsNone(self.ll.delete(999))
def test_delete_head(self):
"""测试删除头部"""
self.ll.append(1).append(2).append(3)
self.assertEqual(self.ll.delete_head(), 1)
self.assertEqual(self.ll.to_list(), [2, 3])
# 空链表
empty = LinkedList()
self.assertIsNone(empty.delete_head())
def test_delete_tail(self):
"""测试删除尾部"""
self.ll.append(1).append(2).append(3)
self.assertEqual(self.ll.delete_tail(), 3)
self.assertEqual(self.ll.to_list(), [1, 2])
# 只剩一个节点
single = LinkedList()
single.append(1)
self.assertEqual(single.delete_tail(), 1)
self.assertTrue(single.is_empty())
def test_find_value(self):
"""测试按值查找索引"""
self.ll.append(10).append(20).append(30)
self.assertEqual(self.ll.find_value(20), 1)
self.assertEqual(self.ll.find_value(999), -1)
def test_find_with_function(self):
"""测试按自定义函数查找"""
self.ll.append(1).append(2).append(3).append(4)
# 查找第一个偶数
result = self.ll.find(lambda x: x % 2 == 0)
self.assertEqual(result, {"index": 1, "value": 2})
# 查找不存在的
result = self.ll.find(lambda x: x > 10)
self.assertIsNone(result)
def test_to_list(self):
"""测试转为列表"""
self.assertEqual(self.ll.to_list(), [])
self.ll.append(1).append(2)
self.assertEqual(self.ll.to_list(), [1, 2])
def test_str(self):
"""测试字符串表示"""
self.assertEqual(str(self.ll), "Empty")
self.ll.append(1).append(2)
self.assertEqual(str(self.ll), "1 -> 2")
def test_from_list(self):
"""测试从列表创建链表"""
ll = LinkedList.from_list([1, 2, 3, 4])
self.assertEqual(ll.to_list(), [1, 2, 3, 4])
def test_chained_operations(self):
"""测试链式调用"""
result = self.ll.append(1).append(2).prepend(0).insert(2, 1.5)
self.assertEqual(result.to_list(), [0, 1, 1.5, 2])
def test_is_linkedlist_node(self):
"""测试节点类型检查"""
node = LinkedListNode(1)
self.assertTrue(is_linkedlist_node(node))
self.assertFalse(is_linkedlist_node(123))
self.assertFalse(is_linkedlist_node(None))
if __name__ == "__main__":
# 运行测试
unittest.main(verbosity=2)实现一个备份脚本
- 配置需要备份的目录路径/保存备份的目记录
- 配置备份文件名的前缀/后缀
- 配置文件的个数(只保留n个)
python
import os
import pathlib
import tarfile
from datetime import datetime
# 配置
source_path = pathlib.Path("./python-demo")
target_path = pathlib.Path("./backup-path")
max_backup_file_count = 7
bakfname_prefix = "backup"
bakfname_suffix = ".tar.gz"
bakfname_seperator = "__"
# 备份压缩包
def backup_archive():
try:
output_archive = target_path.joinpath(generate_bakfname())
with tarfile.open(output_archive, "w:gz") as tar:
with os.scandir(source_path) as entries:
for item in entries:
# ingore hidden files
if item.name.startswith("."):
continue
# add item to tar
tar.add(item.path, arcname=item.name)
print(f"[archive completed]: {output_archive}")
except Exception as e:
print(f"打包过程中发生错误: {e}")
# 生成备份文件名
def generate_bakfname() -> str:
now = datetime.now()
date = now.date()
timestamp = int(now.timestamp())
return bakfname_seperator.join(
[
bakfname_prefix,
date,
str(timestamp),
bakfname_suffix,
]
)
# 解析备份文件名
def parse_bakfname_with_order(bakfname: str):
parts = bakfname.split(bakfname_seperator)
if len(parts) >= 2 and parts[2]:
return {
"order": int(parts[2]),
"filename": bakfname,
}
# 检查已有的备份文件数量
def count_target_files() -> int:
backup_file_count = 0
with os.scandir(target_path) as entries:
for entry in entries:
if entry.name.endswith(bakfname_suffix):
backup_file_count += 1
return backup_file_count
# 清理已有的备份文件(最多保存七个备份)
def clear_target_files() -> None:
bakfname_with_order_items = []
with os.scandir(target_path) as entries:
for entry in entries:
result = parse_bakfname_with_order(entry.name)
if result:
bakfname_with_order_items.append(result)
# sort by order
bakfname_with_order_items.sort(key=lambda x: x["order"])
delete_item = bakfname_with_order_items[0]
delete_item_path = target_path.joinpath(delete_item["filename"])
delete_item_path.unlink(missing_ok=True)
# 初始化路径
def init_paths():
if not source_path.exists():
raise FileNotFoundError("[init]source_path is not exist")
if not target_path.exists():
os.makedirs(target_path)
# main
def main():
init_paths()
if count_target_files() >= max_backup_file_count:
clear_target_files()
backup_archive()
if __name__ == "__main__":
main()