python 用法小结及常见错误

环境信息

  • Python3

字符串转换为变量名

locals() 方法

>>> str1 = 666
>>> a = 'str1'
>>>
>>>
>>> locals()[a]
666

vars() 方法


>>>
>>> str1 = 666
>>> a = 'str1'
>>>
>>>
>>>
>>> vars()[a]
666
>>>

eval() 方法

>>> str1 = 666
>>> a = 'str1'
>>>
>>>
>>> eval(a)
666

yield

yield 指令和 return 相似,都是用来在函数中返回。使用 yield 关键字创建生成器函数时,生成器函数并不会在传统意义上 返回。相反,生成器函数在遇到 yield 语句时会暂停其执行,并返回一个值给调用者。生成器函数的状态会被保存,因此在下一次调用时,它可以从暂停的地方继续执行。

yield 指令 将函数转换成生成器(Generator,它在函数中产生一个值,然后暂停函数并保存其状态(下一次调用函数会从此状态恢复执行),再次恢复执行时再生成(返回)yield 的值。

每次调用生成器函数时,并不会立即执行,会创建一个新的生成器对象。

第一次使用 next() 或在 for 循环中开始迭代生成器时,生成器函数开始执行,直到遇到第一个 yield 语句。yield 会暂停生成器函数的执行,并将一个值返回给调用者。再次调用 next() 或继续迭代(for)时,生成器函数从上次暂停的 yield 处继续执行,直到遇到下一个 yield 语句或执行结束。

生成器函数在没有 yield 语句时结束执行,相当于隐式地在最后一个 yield 语句之后遇到 return

当生成器函数结束时,进一步调用 next() 会引发 StopIteration 异常,表示生成器中的值已被全部生成。

yield 有以下优点:

  • 能够以更高效的方式处理大量数据,因为它不需要一次性将所有数据存储在内存中。通过减少内存消耗,提高程序性能。
  • 它提供了一种新的方法来控制函数的执行流程,使得函数可以在任意点暂停和恢复。生成器函数在被暂停后(遇到 yield)不会继续执行,直到再次调用 next() 或通过迭代器进行迭代(for)。

yield 读取大文本数据

在处理大文本数据(如超过 10G)时,如果一次性读取所有文本内容,在可用内存较小的情况下可能出现内存不足导致程序执行失败。这时候可以考虑使用 yield 来批量加载数据。

定义如下函数读取文件内容:

def read_large_file(file_path):
"""
Generator function to read a large file line by line.
"""
with open(file_path, 'r') as file:
for line in file:
yield line

使用以下方法使用大文本中的数据

  1. next 方法。调用生成器函数(read_large_file),会返回一个 Generator 对象,通过 next() 方法会迭代调用生成器的下一个值(yield 表达式的值)
    file_path = 'large_file.txt'

    # next 方法: 首先
    line = read_large_file(file_path)

    next(line) # 返回第一行
    next(line) # 返回第二行,以此类推可以读取所有行

  2. for 循环。调用生成器函数返回一个生成器对象,这个对象实现了迭代器协议。
    def read_large_file(file_path):
    """
    Generator function to read a large file line by line.
    """
    with open(file_path, 'r') as file:
    for line in file:
    yield line

    # Usage example
    file_path = 'large_file.txt'
    for line in read_large_file(file_path):
    print(line.strip())

分批读取大文件中的数据

在处理大文件的过程中,如果需要批量多行读取文件内容,参考以下代码

def read_file_in_chunks(file_path, chunk_size=1024):
"""
Generator function to read a file in chunks.
"""
with open(file_path, 'r') as file:
while True:
chunk = file.readlines(chunk_size)
if not chunk:
break
for line in chunk:
yield line

# Usage example
file_path = 'large_file.txt'
for line in read_file_in_chunks(file_path):
print(line.strip())

enumerate

enumerate 是 Python 内置函数之一,用于遍历可迭代对象(如列表、元组或字符串)时获取元素和对应的索引。

语法:

enumerate(iterable, start=0)
  • iterable : 任何可迭代对象(如列表、字符串、元组、文件对象等)。
  • start : 索引的起始值,默认为 0。如果要让索引号从 1 开始,配置 start=1
# 示例列表
>>> fruits = ['apple', 'banana', 'cherry']

# 使用 enumerate 获取元素及其索引
>>> for index, fruit in enumerate(fruits):
... print(index, fruit)
...
0 apple
1 banana
2 cherry
>>>


# 使用 enumerate 获取元素及其索引,并将起始索引改为 1
>>> for index, fruit in enumerate(fruits, start=1):
... print(index, fruit)
...
1 apple
2 banana
3 cherry

# 使用 enumerate 获取文件中的行号及其内容
>>> f = open('temp_file')
>>> for line_number, line in enumerate(f):
... print(line_number, line)
...
0 85d37fac5cc284914b5d6f79982942b8/Y1iY3k1U.ts

1 85d37fac5cc284914b5d6f79982942b8/Y1x0V8Rc.ts

2 85d37fac5cc284914b5d6f79982942b8/Y22fhGiC.ts

3 85d37fac5cc284914b5d6f79982942b8/Y3p95oau.ts

常见错误

NameError: name ‘null‘ is not defined

使用 evalstring 转化成 dict 时出错,经过排查,发现 string 数据中包含 null,在转换时就会报错: NameError: name ‘null‘ is not defined

解决方法

使用 json 进行转换

try:
response_dict = eval(response)
except NameError:
response_dict = json.loads(str(response.decode()))