下面我有两个代码块 - 除了一行 - 其余的都是相同的。
for id in ids_list:
id_dir = os.path.join(dir, id)
os.chdir(id_dir)
for path in glob('*' + file_extention):
with open(path) as file:
# count number of lines in file
names[path] = sum(1 for line in file if line.strip())
for id in ids_list:
id_dir = os.path.join(dir, id)
os.chdir(id_dir)
for path in glob('*' + file_extention):
with open(filepath) as file:
# get file content
content = file.read()
我想知道是否有办法创建一个方法(可能会有ids_list
,file_extention
,当然还有语句(要么计算行数或获取内容)作为参数。我正在努力解决如何使用语句。任何帮助,特别是用一些示例代码说明,因为我是Python新手会很棒。
答案 0 :(得分:2)
这可以通过将一个函数作为参数传递给另一个函数来完成。
def last_line():
content = file.read()
def do_last_line(func):
for id in ids_list:
id_dir = os.path.join(dir, id)
os.chdir(id_dir)
for path in glob('*' + file_extention):
with open(filepath) as file:
func()
do_last_line(last_line)
应该这样做,尽管content
变量在函数外部不可用。你可以退货。
另一种方法是使用exec()或eval(),但这通常被认为是不好的做法。
答案 1 :(得分:2)
您的情况是使用回调函数可以提供帮助的情况。
通常,回调是具有约定参数的函数,有时也返回值。该 回调函数作为参数传递给另一个函数,该函数调用它同意传递 它的参数并将处理留给回调函数。
为了让您的代码正常工作,我不得不对其进行一些修改。所有代码都来自一个文件,例如有名字 “et.py”
为了解释它,我会一点一点地展示它。
import os
from glob import glob
你的例子是将值读入content
变量,每个循环用新值重写它,所以
最后,你只有最后的价值。
我通过添加全局变量GLOB_CONTENT
来修改代码,我追加了它
每个文件的内容一个接一个。
GLOB_CONTENT = []
def read_file_content(path):
global GLOB_CONTENT
with open(path) as f:
# get file content
content = f.read()
# do some content processing here
GLOB_CONTENT.append(content)
全局变量的使用有时是可疑的,但它是保持全局状态的一种方式 东西。
任何函数都可以用作回调(如果它遵循预期的签名)。一个案例是
类实例的方法。它将从dict
派生,以便能够记住下的某些值
密钥名称,它将添加方法count_file_lines
,作为文件的参数名称:
class FilesLineCounter(dict):
def count_file_lines(self, path):
with open(path) as file:
self[path] = sum(1 for line in file if line.strip())
它会计算文件中的非空行并记住它本身。
循环可以推广到函数中:
def process_ids(dir_path, ids_list, file_extension, callback):
for itm_id in ids_list:
id_dir = os.path.join(dir_path, itm_id)
for path in glob(id_dir + '/*' + file_extension):
callback(path)
如您所见,它获取了查找正确文件所需的所有参数,以及使用的callback
函数
处理找到的文件。
以下是代码的最后一部分:
if __name__ == "__main__":
dir_path = "subdir"
ids_list = ["1", "2"]
file_extension = ".txt"
cntr = FilesLineCounter()
# goint to use the callback magic
process_ids(dir_path, ids_list, file_extension, cntr.count_file_lines)
process_ids(dir_path, ids_list, file_extension, read_file_content)
# time to show our results
for path, numoflines in cntr.items():
print("File {} has {} lines".format(path, numoflines))
for i, content in enumerate(GLOB_CONTENT):
print("File # {} last 3 bytes are {}".format(i, content[-3:]))
cntr = FilesLineCounter()
创建了我们特殊的扩展字典。 cntr
为空
已添加方法count_file_lines
的字典。由于该方法可用作函数,我们使用
cntr.count_file_lines
作为回调的价值。
当process_ids
处理它时,我们会在cntr
中找到每个已处理文件的一个密钥,每个
具有该文件中非空行数的值。
同样,我们阅读了内容。
运行$ python et.py
我得到以下输出:
File subdir/1/one-plus.txt has 1 lines
File subdir/2/empty.txt has 0 lines
File subdir/1/one.txt has 8 lines
File subdir/2/long.txt has 42 lines
File # 0 last 3 bytes are fa
File # 1 last 3 bytes are hi
File # 2 last 3 bytes are fa
File # 3 last 3 bytes are
答案 2 :(得分:2)
如我的另一个答案中所述,不是使用回调,而是可以反转解决方案。
我们可能会在循环内部循环path
值而不是调用某些函数
创建一个生成器,产生path
值并让代码执行任何要做的事情。
import os
from glob import glob
def files_to_process(dir_path, ids_list, file_extension):
for itm_id in ids_list:
id_dir = os.path.join(dir_path, itm_id)
for path in glob(id_dir + '/*' + file_extension):
yield path
if __name__ == "__main__":
dir_path = "subdir"
ids_list = ["1", "2"]
file_extension = ".txt"
names = {}
# using the generator first time
for path in files_to_process(dir_path, ids_list, file_extension):
with open(path) as f:
names[path] = sum(1 for line in f if line.strip())
glob_content = []
# using the generator the second time
for path in files_to_process(dir_path, ids_list, file_extension):
with open(path) as f:
glob_content.append(f.read())
names[path] = sum(1 for line in f if line.strip())
for path, numoflines in names.items():
print("File {} has {} lines".format(path, numoflines))
for i, content in enumerate(glob_content):
print("File # {} last 3 bytes are {}".format(i, content[-3:]))
函数files_to_process
是生成器。
调用files_to_process(dir_path, ids_list, file_extension)
即可获得生成器值。
如果迭代它,它将返回(yield)它找到的所有值到循环。
警告:生成器可能已耗尽。这意味着,一旦它产生一个值,下一次就会产生 产生另一个,直到没有更多的东西可以产生,你就得不到更多的价值。
要再次获取值,您必须再次创建生成器。
对我来说,带生成器的代码似乎更具可读性。
答案 3 :(得分:0)
当然你可以有一个方法 '读取文件(IDs_list,ext,type):' .... 'if type == get:' '在这里得到代码' '其他:' '其他代码在这里'