学习日志09 python
回家=吃吃吃睡睡睡玩玩玩,好了好了好了,该学学了,脑子不用感觉生锈了。!(其实用了也不太聪明,,,)
囤一下要做的:
- Python:爬取豆瓣电影 Top250、做一个简单的贪吃蛇游戏(用 pygame)。
- Java:写一个简易的图书借阅系统(控制台版)、用 Spring Boot 搭一个简单的后端接口。
- C:实现一个简单的命令行计算器、写一个冒泡排序的可视化程序(用图形库)。
1 python里的update怎么用?
在 Python 中,update()
是一个常用的方法,主要用于更新对象的内容。它在不同的数据类型中有不同的用途和行为。下面介绍几种常见的用法:
1. 字典(dict)的 update()
方法
字典的 update()
方法用于将另一个字典或可迭代对象的键值对更新到当前字典中。
- 语法:
dict.update([other])
- 参数:
other
可以是字典或包含键值对的可迭代对象。 - 示例:
python
运行
# 创建一个字典
student = {'name': 'Alice', 'age': 20}# 使用另一个字典更新
student.update({'age': 21, 'gender': 'female'})
print(student) # 输出: {'name': 'Alice', 'age': 21, 'gender': 'female'}# 使用可迭代对象更新(如元组列表)
student.update([('city', 'Beijing'), ('score', 90)])
print(student) # 输出: {'name': 'Alice', 'age': 21, 'gender': 'female', 'city': 'Beijing', 'score': 90}# 使用关键字参数更新
student.update(id=1001, grade='A')
print(student) # 输出: {'name': 'Alice', 'age': 21, 'gender': 'female', 'city': 'Beijing', 'score': 90, 'id': 1001, 'grade': 'A'}
- 注意:如果被更新的键已存在,则会覆盖原有的值;如果不存在,则会添加新的键值对。
2. 集合(set 和 frozenset)的 update()
方法
集合的 update()
方法用于将另一个可迭代对象的元素添加到当前集合中,相当于执行并集操作。
- 语法:
set.update(*others)
- 参数:
others
可以是一个或多个可迭代对象。 - 示例:
python
运行
# 创建一个集合
s = {1, 2, 3}# 使用另一个集合更新
s.update({3, 4, 5})
print(s) # 输出: {1, 2, 3, 4, 5}# 使用列表更新
s.update([5, 6, 7])
print(s) # 输出: {1, 2, 3, 4, 5, 6, 7}# 使用多个可迭代对象更新
s.update((7, 8), {8, 9})
print(s) # 输出: {1, 2, 3, 4, 5, 6, 7, 8, 9}
- 注意:集合中的元素具有唯一性,重复的元素会被自动过滤。
3. 其他对象的 update()
方法
一些第三方库或自定义类也可能实现 update()
方法,其行为取决于具体的实现。例如,collections.Counter
类的 update()
方法用于更新计数器:
python
运行
from collections import Counter# 创建一个计数器
count = Counter('abc')
print(count) # 输出: Counter({'a': 1, 'b': 1, 'c': 1})# 使用另一个计数器更新
count.update(Counter('bcd'))
print(count) # 输出: Counter({'b': 2, 'c': 2, 'a': 1, 'd': 1})# 使用字符串更新
count.update('cde')
print(count) # 输出: Counter({'c': 3, 'b': 2, 'a': 1, 'd': 2, 'e': 1})
总结
- 字典:更新键值对,可覆盖或添加。
- 集合:添加元素,执行并集操作,自动去重。
- 其他对象:根据具体实现而定,通常用于更新对象状态。
使用时需注意对象类型和 update()
方法的具体参数要求。
2 python迭代器适合处理大文件
在 Python 中,迭代器(Iterator) 是处理大文件、海量数据或无限序列的核心工具。它允许你逐个访问元素,而不必一次性将整个数据集加载到内存中。下面帮你系统回顾迭代器的相关知识:
一、基本概念:可迭代对象 vs 迭代器
可迭代对象(Iterable)
- 任何实现了
__iter__()
方法的对象(如列表、字符串、文件)。 - 可以用
for
循环遍历,但本身不保存迭代状态。
- 任何实现了
迭代器(Iterator)
- 实现了
__iter__()
和__next__()
方法的对象。 __next__()
方法返回下一个元素,直到没有元素时抛出StopIteration
异常。- 迭代器是一次性消耗品,遍历完后不能重复使用。
- 实现了
关系
- 可迭代对象通过
iter()
函数转换为迭代器。 - 迭代器自身也是可迭代对象(
__iter__()
返回自身)。
- 可迭代对象通过
二、迭代器的核心方法
__iter__()
- 返回迭代器对象本身(用于
for
循环或iter()
函数)。
- 返回迭代器对象本身(用于
__next__()
- 返回下一个元素,若没有元素则抛出
StopIteration
。
- 返回下一个元素,若没有元素则抛出
示例:手动实现一个简单的迭代器
python
运行
class MyRange:def __init__(self, start, end):self.start = startself.end = endself.current = startdef __iter__(self):return self # 返回自身作为迭代器def __next__(self):if self.current < self.end:value = self.currentself.current += 1return valueelse:raise StopIteration # 结束迭代# 使用自定义迭代器
my_range = MyRange(0, 3)
print(next(my_range)) # 输出 0
print(next(my_range)) # 输出 1
print(next(my_range)) # 输出 2
print(next(my_range)) # 抛出 StopIteration
三、为什么处理大文件时迭代器是最优选择?
内存效率高
- 文件对象是天然的迭代器,逐行读取不占内存。
- 示例:处理 10GB 大文件,传统读取 vs 迭代器读取
python
运行
# 传统方法(一次性加载,可能内存溢出)
with open('large_file.txt') as f:lines = f.readlines() # 全部读入内存for line in lines:print(line)# 迭代器方法(逐行读取,内存占用恒定)
with open('large_file.txt') as f:for line in f: # 文件对象本身就是迭代器print(line) # 每次只处理一行
四、常用的迭代器工具
生成器(Generator)
- 特殊的迭代器,用函数 +
yield
关键字实现。 - 示例:生成斐波那契数列
python
运行
def fib_generator():a, b = 0, 1while True:yield a # 暂停执行并返回当前值a, b = b, a + bfib = fib_generator() print(next(fib)) # 0 print(next(fib)) # 1 print(next(fib)) # 1
- 特殊的迭代器,用函数 +
内置迭代器函数
iter(iterable)
:将可迭代对象转换为迭代器。next(iterator[, default])
:获取下一个元素,可指定默认值避免异常。
标准库工具
itertools
模块:提供各种高效迭代器(如count
、cycle
、chain
、islice
)。python
运行
from itertools import islice# 读取文件前10行 with open('large_file.txt') as f:first_10_lines = islice(f, 10)for line in first_10_lines:print(line)
五、处理大文件的进阶技巧
逐块读取二进制文件
python
运行
with open('large_binary_file.bin', 'rb') as f:while chunk := f.read(4096): # 每次读取4KBprocess_chunk(chunk)
自定义迭代器处理非标准格式
例如处理按特定分隔符分块的文件:python
运行
class ChunkIterator:def __init__(self, file, separator):self.file = fileself.separator = separatordef __iter__(self):return selfdef __next__(self):chunk = []for line in self.file:chunk.append(line)if self.separator in line:return ''.join(chunk)if not chunk:raise StopIterationreturn ''.join(chunk)# 使用自定义迭代器按块读取 with open('log_file.log') as f:for chunk in ChunkIterator(f, 'END_OF_RECORD'):process_chunk(chunk)
六、迭代器 vs 生成器 vs 列表推导式
特性 | 列表推导式 | 生成器表达式 | 手动迭代器 |
---|---|---|---|
语法 | [x for x in iterable] | (x for x in iterable) | 类 +__iter__ +__next__ |
内存占用 | 高(一次性生成所有元素) | 低(按需生成) | 低(按需生成) |
是否可重复使用 | 是 | 否 | 否 |
适用场景 | 小数据量、需要多次遍历 | 大数据量、一次性遍历 | 复杂状态管理、自定义逻辑 |
七、常见面试题
手写一个迭代器,实现
range(start, stop, step)
功能python
运行
class MyRange:def __init__(self, start, stop, step=1):self.start = startself.stop = stopself.step = stepself.current = startdef __iter__(self):return selfdef __next__(self):if (self.step > 0 and self.current >= self.stop) or \(self.step < 0 and self.current <= self.stop):raise StopIterationvalue = self.currentself.current += self.stepreturn value
如何判断一个对象是否是迭代器?
python
运行
from collections.abc import Iteratorobj = iter([1, 2, 3]) print(isinstance(obj, Iterator)) # True
处理大文件时,
readlines()
和直接迭代文件对象的区别?readlines()
:一次性读取所有行到列表,内存占用高。- 直接迭代:逐行读取,内存占用恒定。
八、总结
- 核心优势:节省内存,适合处理无限序列或大文件。
- 使用场景:大数据处理、流式计算、无限序列(如随机数生成)。
- 最佳实践:
- 优先用生成器表达式(简洁)。
- 复杂逻辑用
yield
实现生成器函数。 - 超大文件用
read(size)
按块读取。
掌握迭代器,你就能优雅地处理 GB 级数据,而不用担心内存溢出的问题!如果需要进一步练习,可以尝试用迭代器实现一个大文件的词频统计功能。
3 python有关文件的读取
在 Python 中,文件读取是数据处理的基础操作。结合迭代器的特性,下面系统整理文件读取的核心语法、最佳实践及进阶技巧:
一、基础文件操作:打开、读取、关闭
1. 打开文件:open()
函数
python
运行
file = open('filename.txt', mode='r', encoding='utf-8')
模式参数
mode
:'r'
:读取(默认)'w'
:写入(覆盖)'a'
:追加'b'
:二进制模式(与其他模式组合,如'rb'
)'+'
:读写模式(如'r+'
)
编码参数
encoding
:
推荐显式指定(如'utf-8'
),避免中文等非 ASCII 字符乱码。
2. 读取文件内容
python
运行
# 一次性读取全部内容(小文件适用)
content = file.read() # 字符串# 读取指定字节数
first_10_bytes = file.read(10) # 读取前10个字节# 按行读取(返回列表)
lines = file.readlines() # ['line1\n', 'line2\n', ...]# 逐行读取(迭代器方式,大文件推荐)
for line in file:process(line)
3. 关闭文件
python
运行
file.close() # 手动关闭# 推荐用 with 语句(自动管理资源)
with open('filename.txt', 'r') as file:content = file.read()
# 离开 with 块时,文件自动关闭
二、大文件读取的最佳实践
1. 逐行读取(内存效率最高)
python
运行
with open('large_file.txt') as f:for line in f: # 文件对象是天然的迭代器process(line) # 每次处理一行
2. 按块读取(二进制文件)
python
运行
CHUNK_SIZE = 4096 # 4KB
with open('data.bin', 'rb') as f:while chunk := f.read(CHUNK_SIZE): # Python 3.8+ 海象运算符process(chunk)
3. 读取前 N 行
python
运行
from itertools import islicewith open('large_file.txt') as f:first_10_lines = islice(f, 10) # 读取前10行for line in first_10_lines:print(line)
三、文件读取进阶技巧
1. 处理非标准分隔符的文件
python
运行
def read_in_chunks(file_obj, separator):"""按自定义分隔符读取文件块"""buffer = ""for line in file_obj:buffer += lineif separator in buffer:chunks = buffer.split(separator)for chunk in chunks[:-1]:yield chunk + separatorbuffer = chunks[-1]if buffer:yield buffer# 使用示例
with open('log.txt') as f:for chunk in read_in_chunks(f, 'END'):process_chunk(chunk)
2. 跳过文件头部或尾部
python
运行
with open('data.csv') as f:# 跳过标题行next(f) # 直接调用 next() 跳过第一行# 处理数据行for line in f:process_data(line)
3. 同时读取多个文件
python
运行
with open('file1.txt') as f1, open('file2.txt') as f2:for line1, line2 in zip(f1, f2):# 并行处理两个文件的同一行process(line1, line2)
四、文件解析工具
1. CSV 文件
python
运行
import csvwith open('data.csv', newline='') as f:reader = csv.reader(f)for row in reader:print(row) # 每行为列表# 带标题的 CSV
with open('data.csv', newline='') as f:reader = csv.DictReader(f)for row in reader:print(row['column_name']) # 按列名访问
2. JSON 文件
python
运行
import jsonwith open('data.json') as f:data = json.load(f) # 解析为字典/列表for item in data:process(item)
3. XML 文件
python
运行
import xml.etree.ElementTree as ETtree = ET.parse('data.xml')
root = tree.getroot()for child in root:print(child.tag, child.attrib)
五、常见错误处理
1. 文件不存在
python
运行
try:with open('nonexistent.txt') as f:content = f.read()
except FileNotFoundError:print("文件不存在,请检查路径!")
2. 权限错误
python
运行
try:with open('/etc/passwd', 'w') as f: # 尝试写入系统文件f.write('data')
except PermissionError:print("没有权限操作该文件!")
3. 编码错误
python
运行
try:with open('file.txt', encoding='utf-8') as f:content = f.read()
except UnicodeDecodeError:print("文件编码可能不是 UTF-8,尝试其他编码...")
六、性能优化
1. 读取 vs 解析分离
python
运行
# 低效:边读取边解析
with open('data.csv') as f:for line in f:parts = line.strip().split(',') # 每行都执行 split# 高效:批量解析
with open('data.csv') as f:lines = f.readlines() # 一次性读取所有行parsed_data = [line.strip().split(',') for line in lines]
2. 使用生成器处理超大文件
python
运行
def process_large_file(filename):with open(filename) as f:for line in f:yield process_line(line) # 逐行处理并生成结果# 使用生成器
for result in process_large_file('huge_data.txt'):save_result(result)
七、面试高频问题
1. 如何高效读取 10GB 大文件?
- 用迭代器逐行读取(
for line in file
) - 按块读取(
read(CHUNK_SIZE)
) - 避免使用
readlines()
一次性加载
2. 如何在不加载整个文件的情况下获取文件行数?
python
运行
count = 0
with open('large_file.txt') as f:for _ in f: # 逐行迭代但不处理内容count += 1
print(f"文件行数: {count}")
3. 如何实现文件的倒序读取?
python
运行
from collections import dequedef tail(filename, n=10):"""获取文件最后 n 行(类似 Linux tail 命令)"""with open(filename) as f:return deque(f, n) # deque 的 maxlen 参数自动保留最后 n 个元素print(tail('data.log', 5)) # 获取最后 5 行
八、总结
场景 | 推荐方法 | 示例代码 |
---|---|---|
小文件读取 | read() 或 readlines() | with open('file.txt') as f: content = f.read() |
大文件逐行处理 | 迭代器方式 | with open('large.txt') as f: for line in f: ... |
二进制文件分块读取 | read(CHUNK_SIZE) | while chunk := f.read(4096): process(chunk) |
CSV 文件解析 | csv.reader 或 csv.DictReader | with open('data.csv') as f: reader = csv.DictReader(f) |
JSON 文件解析 | json.load() | with open('data.json') as f: data = json.load(f) |
掌握这些技巧后,你可以高效处理从几 KB 到几十 GB 的各种文件,同时避免内存溢出的风险。
4 在 Python的命名规范中有关单下划线(_
)和双下划线(__
)
在 Python 里,命名规范借助单下划线(_
)和双下划线(__
)来体现变量、方法或者类的特殊用途和可见性。下面详细介绍各类命名方式及其使用场景:
1. 单前导下划线(例如 _var
)
这一命名方式用于表明某个变量或者方法是 “内部使用” 的。虽然 Python 不会强制限制访问,但按照惯例,它不应该被外部直接调用。这种方式常见于模块、类或者函数内部的私有元素。
python
运行
class MyClass:def __init__(self):self._internal_var = 42 # 内部变量,外部不应直接访问def _internal_method(self): # 内部方法,外部不应直接调用pass
2. 单末尾下划线(例如 var_
)
当某个变量名与 Python 内置关键字冲突时,会采用这种命名方式。这样做是为了避免命名冲突。
python
运行
def my_function(class_): # 使用 class_ 避免与内置关键字 class 冲突pass
3. 双前导下划线(例如 __var
)
这是一种 “名称修饰” 机制。在类中使用双前导下划线命名的属性或者方法,会自动将名称修改为 _ClassName__var
,以此来避免子类意外覆盖该名称。
python
运行
class Parent:def __init__(self):self.__private_var = 10 # 名称会被修饰为 _Parent__private_varclass Child(Parent):def __init__(self):super().__init__()self.__private_var = 20 # 名称会被修饰为 _Child__private_varprint(Child()._Parent__private_var) # 输出 10
print(Child()._Child__private_var) # 输出 20
4. 双前导和双末尾下划线(例如 __var__
)
这类名称被称为 “魔术方法” 或者 “特殊方法”,是 Python 内置的特殊方法,像 __init__
、__str__
、__len__
等都属于此类。我们应该避免自己定义这类名称,而是按照 Python 的约定去使用它们。
python
运行
class MyClass:def __init__(self, value): # 初始化方法self.value = valuedef __str__(self): # 字符串表示方法return f"MyClass({self.value})"
5. 单下划线(例如 _
)
在以下几种场景中会使用单下划线:
- 在交互式解释器里,
_
会存储上一次执行的表达式结果。 - 用于忽略某些变量的值,也就是作为 “占位符”。
- 在国际化(i18n)的场景中,
_
常被用作翻译函数名。
python
运行
x, _, y = (1, 2, 3) # 忽略中间的值
for _ in range(3): # 不需要使用循环计数器print("Hello")
总结
命名方式 | 示例 | 用途 |
---|---|---|
单前导下划线 | _var | 内部使用(惯例) |
单末尾下划线 | var_ | 避免与 Python 关键字冲突 |
双前导下划线 | __var | 类私有成员,通过名称修饰防止子类覆盖 |
双前导双末尾下划线 | __var__ | Python 内置的特殊方法(魔术方法) |
单下划线 | _ | 临时变量、占位符或存储上一次的结果 |
最佳实践建议
- 对于内部使用的变量和方法,推荐使用单前导下划线(
_var
)。 - 只有当确实需要防止子类覆盖某个名称时,才使用双前导下划线(
__var
)。 - 除非是实现特殊方法,否则不要使用双前导双末尾下划线(
__var__
)。 - 单下划线(
_
)要谨慎使用,避免在函数或者类中用它来命名重要的变量。
遵循这些命名规范,能够让你的代码更加清晰易读,同时也能避免一些常见的编程陷阱。
5 Python 中列表的sort
方法、自定义排序函数以及字符串切片操作
这个题目主要考察 Python 中列表的sort
方法、自定义排序函数以及字符串切片操作。下面为你详细分析:
代码分析
- 列表定义:
python
运行
lis = ['apple', 'lemon', 'pear', 'peach']
这里创建了一个包含四个水果名称的列表。
- 自定义排序函数:
python
运行
def fn(x):return x[::-1]
此函数接收一个字符串作为参数,通过切片操作[::-1]
将字符串反转后返回。例如,fn('apple')
会返回'elppa'
。
- 列表排序:
python
运行
lis.sort(key=fn, reverse=True)
key=fn
:表示按照每个元素经过fn
函数处理后的结果进行排序。也就是对每个字符串先反转,再依据反转后的字符串进行排序。reverse=True
:意味着按照降序排列。
- 输出结果:
python
运行
print(lis)
最终会打印出排序后的列表。
具体排序过程
首先,对列表中的每个字符串进行反转:
'apple'
反转后是'elppa'
'lemon'
反转后是'nomel'
'pear'
反转后是'raep'
'peach'
反转后是'hcaep'
然后,按照反转后的字符串进行降序排序。在 Python 中,字符串的排序是基于字典序的,降序排序就是从大到小排列。反转后的字符串降序排列为:
'raep'
(对应原字符串'pear'
)'nomel'
(对应原字符串'lemon'
)'hcaep'
(对应原字符串'peach'
)'elppa'
(对应原字符串'apple'
)
所以,原列表排序后的结果是:
python
运行
['pear', 'lemon', 'peach', 'apple']
考察的知识点
- 列表排序:考生需要掌握列表的
sort
方法,清楚key
和reverse
参数的用法。 - 函数作为参数:要理解可以将函数作为参数传递给
sort
方法,用于自定义排序规则。 - 字符串切片:要明白
[::-1]
这种切片操作能够实现字符串的反转。 - 字典序排序:要知道 Python 中字符串排序是基于字典序的,并且清楚升序和降序的区别。
答案
执行该程序,输出结果为:
python
运行
['pear', 'lemon', 'peach', 'apple']