Python 函数中的持久变量
Persistent variable in Python function
我已经编写了这个脚本,它在 运行 通过一个大文件时进行一些涉及的解析。对于文件中的每一行(经过一些繁重的操作之后),我需要添加一个检查以查看它是否符合特定条件,如果符合,则将其包含在列表中以便稍后进行额外处理。
做解析的函数已经有点乱了,我想知道是否可以将行检查和列表操作分流到另一个函数,以便以后更容易修改。我倾向于使用一个由函数修改的全局变量,但我知道这通常是一种糟糕的形式。到目前为止,我从未使用过 类,但我依稀记得它们在持久性局部变量方面有一些优势。
这部分脚本的一个版本可能是:
matchingLines = []
def lineProcess(line):
global matchingLines
if line.startswith(criteria):
matchingLines.append(line)
for line in myFile:
# lots of other stuff
lineProcess(line)
显然,在这个简单的示例中,只需在主函数中进行检查而不用为任何其他函数打扰就不会很痛苦。但原则上,我想知道在不使用外部变量的情况下做这种事情的更好的通用方法是什么。
编辑:我觉得单独的函数有吸引力的部分原因是因为一旦我收集了行列表,我将使用它们来操作另一个外部文件并且让整个操作很方便包裹在一个包含的模块中。但是,我认识到这可能是过早的优化。
您可以使用 class,并将 matching_lines
作为属性。但你也可以这样做:
def process_line(line, matching_lines):
if line.startswith(criteria):
matching_lines.append(line)
...
matches = []
for line in my_file:
# lots of other stuff
process_line(line, matches)
像下面这样的东西可能被认为更 pythonic:
def is_valid_line(line):
"""Return True if the line is valid, else False."""
return line.startswith(criteria)
valid_lines = [l for l in myFile if is_valid_line(l)]
顺便说一句,使用生成器表达式而不是列表会更好,例如
valid_lines = (l for l in myFile if is_valid_line(l))
这样,文件读取和行验证只会在尝试迭代 valid_lines 时才会真正发生,而不是之前。例如。在以下情况下:
valid_lines = [l for l in myFile if is_valid_line(l)]
for line in valid lines:
stuff_that_can_raise_exception(line)
在这种情况下,您已经读取并验证了整个(巨大的)文件并拥有已验证行的完整列表,然后第一行导致错误,验证整个文件所花费的时间被浪费了。如果您使用生成器表达式((x for x in y)
)版本而不是列表理解([x for x in y]
),那么当错误发生时您实际上还没有验证文件(只有第一行)。我只提到它是因为我自己不经常这样做很糟糕,并且在很多情况下它可以产生很大的性能提升(在 CPU 和内存中)。
我已经编写了这个脚本,它在 运行 通过一个大文件时进行一些涉及的解析。对于文件中的每一行(经过一些繁重的操作之后),我需要添加一个检查以查看它是否符合特定条件,如果符合,则将其包含在列表中以便稍后进行额外处理。
做解析的函数已经有点乱了,我想知道是否可以将行检查和列表操作分流到另一个函数,以便以后更容易修改。我倾向于使用一个由函数修改的全局变量,但我知道这通常是一种糟糕的形式。到目前为止,我从未使用过 类,但我依稀记得它们在持久性局部变量方面有一些优势。
这部分脚本的一个版本可能是:
matchingLines = []
def lineProcess(line):
global matchingLines
if line.startswith(criteria):
matchingLines.append(line)
for line in myFile:
# lots of other stuff
lineProcess(line)
显然,在这个简单的示例中,只需在主函数中进行检查而不用为任何其他函数打扰就不会很痛苦。但原则上,我想知道在不使用外部变量的情况下做这种事情的更好的通用方法是什么。
编辑:我觉得单独的函数有吸引力的部分原因是因为一旦我收集了行列表,我将使用它们来操作另一个外部文件并且让整个操作很方便包裹在一个包含的模块中。但是,我认识到这可能是过早的优化。
您可以使用 class,并将 matching_lines
作为属性。但你也可以这样做:
def process_line(line, matching_lines):
if line.startswith(criteria):
matching_lines.append(line)
...
matches = []
for line in my_file:
# lots of other stuff
process_line(line, matches)
像下面这样的东西可能被认为更 pythonic:
def is_valid_line(line):
"""Return True if the line is valid, else False."""
return line.startswith(criteria)
valid_lines = [l for l in myFile if is_valid_line(l)]
顺便说一句,使用生成器表达式而不是列表会更好,例如
valid_lines = (l for l in myFile if is_valid_line(l))
这样,文件读取和行验证只会在尝试迭代 valid_lines 时才会真正发生,而不是之前。例如。在以下情况下:
valid_lines = [l for l in myFile if is_valid_line(l)]
for line in valid lines:
stuff_that_can_raise_exception(line)
在这种情况下,您已经读取并验证了整个(巨大的)文件并拥有已验证行的完整列表,然后第一行导致错误,验证整个文件所花费的时间被浪费了。如果您使用生成器表达式((x for x in y)
)版本而不是列表理解([x for x in y]
),那么当错误发生时您实际上还没有验证文件(只有第一行)。我只提到它是因为我自己不经常这样做很糟糕,并且在很多情况下它可以产生很大的性能提升(在 CPU 和内存中)。