Python 如何读取文件或列表?
假设您有一段接受列表或文件名的代码,并且必须应用相同的条件筛选其中任何一项的每一项:Python 如何读取文件或列表?,python,python-2.7,Python,Python 2.7,假设您有一段接受列表或文件名的代码,并且必须应用相同的条件筛选其中任何一项的每一项: import argparse parser=argparse.ArgumentParser() 组=解析器。添加互斥组(必需=True) add_参数('-n','-name',help='single name',action='append')) add_参数('-N','-names',help='text file of names') args=parser.parse_args() 结果=[] 如
import argparse
parser=argparse.ArgumentParser()
组=解析器。添加互斥组(必需=True)
add_参数('-n','-name',help='single name',action='append'))
add_参数('-N','-names',help='text file of names')
args=parser.parse_args()
结果=[]
如果args.name:
#我们正在处理一份清单。
对于args.name中的名称:
name=name.strip().lower()
如果名称不在结果中且len(name)>6:results.append(name)
其他:
#我们正在处理一个文件名。
将open(args.names)作为f:
对于f中的名称:
name=name.strip().lower()
如果名称不在结果中且len(name)>6:results.append(name)
我想在上面的代码中删除尽可能多的冗余。我尝试为strip
和lower
创建以下函数,但没有删除太多重复代码:
def getFilteredName(名称):
返回名称.strip().lower()
有没有办法在同一个函数中对列表和文件进行迭代?我应该如何尽可能地减少代码?子类
列表
并使子类成为一个:
然后条件可以决定迭代什么
if args.name:
# We are dealing with a list.
thing = F(args.name)
else:
# We are dealing with a file name.
thing = open(args.names)
迭代代码可以分解出来
results = []
with thing as f:
for name in f:
name = name.strip().lower()
if name not in results and len(name) > 6: results.append(name)
下面是一个类似的解决方案,它从文件或列表中生成一个
io.StringIO
对象,然后使用一组指令来处理它们
import io
if args.name:
# We are dealing with a list.
f = io.StringIO('\n'.join(args.name))
else:
# We are dealing with a file name.
with open(args.names) as fileobj:
f = io.StringIO(fileobj.read())
results = []
for name in f:
name = name.strip().lower()
if name not in results and len(name) > 6: results.append(name)
如果文件很大而内存不足,这样做的缺点是将整个文件读入内存。您有可以简化的重复代码:
列表
和文件对象
都是可编辑的-如果您创建的方法采用可编辑的
并返回正确的输出,则代码重复(DRY)更少
数据结构的选择:
您不需要重复项,这意味着set()
或dict()
更适合收集您要分析的数据-它们通过设计消除重复项,这比查看列表中是否已存在项更快:
- 如果名称的顺序很重要,请使用
- 在python 3.6或更低版本上时,从
collections
订购的orderedict
- 3.7或更高版本的正常
dict
(dicts担保输入顺序)
- 更多信息:
- 如果名称顺序不重要,请使用
set()
上述任一选项都会为您删除重复项
import argparse
from collections import OrderedDict # use normal dict on 3.7+ it hasinput order
def get_names(args):
"""Takes an iterable and returns a list of all unique lower cased elements, that
have at least length 6."""
seen = OrderedDict() # or dict or set
def add_names(iterable):
"""Takes care of adding the stuff to your return collection."""
k = [n.strip().lower() for n in iterable] # do the strip().split()ing only once
# using generator comp to update - use .add() for set()
seen.update( ((n,None) for n in k if len(n)>6))
if args.name:
# We are dealing with a list:
add_names(args.name)
elif args.names:
# We are dealing with a file name:
with open(args.names) as f:
add_names(f)
# return as list
return list(seen)
测试代码:
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group(required = True)
group.add_argument('-n', '--name', help = 'single name', action = 'append')
group.add_argument('-N', '--names', help = 'text file of names')
args = parser.parse_args()
results = get_names(args)
print(results)
-n Joh3333n-n Ji3333m-n Joh3333n-n Bo3333b-n Bo3333b-n jim的输出
:
['joh3333n', 'ji3333m', 'bo3333b']
输入文件:
with open("names.txt","w") as names:
for n in ["a"*k for k in range(1,10)]:
names.write( f"{n}\n")
-N names.txt的输出:
['aaaaaaa', 'aaaaaaaa', 'aaaaaaaaa']
我认为您的思路是正确的,为什么不将name=…
中的所有内容都放在def
中呢?上下文管理器不会添加任何内容。将循环移到函数中将是一种改进。@cco列表
不是上下文管理器-它们没有\uuuuuuuuuuu进入
或\uuuuuuu退出
方法;子类允许列表与语句一起使用,该语句使两个对象之间的代码部分成为公共的-这是OP所希望的,减少了代码重复。如果没有它,代码将为列表抛出AttributeError。没有子类的情况下你试过吗?事实上,我用函数中的最后一位测试了它,但不知道OP的程序是如何构造的,我只是想展示一种处理重复代码的方法。或者我误解了OP的问题。这个解决方案有效,代码比公认的答案少,但似乎太粗糙了。不过,谢谢你对它的创造性观点!这是一个“跳出框框思考”的解决方案,dv不是我的,但我会告诉你!这是一个很好的解决方案。我只会稍微调整它,使其更适合我的代码,并编辑add_names
,这样只有一次迭代iterable
(而不是迭代iterable
,然后进一步迭代k
),这会剥离s,降低s,检查len
,并一次添加到所看到的
。@Hank如果你做{n.strip().lower(),w在iterable中如果len(n.strip())>6}
(使用一个集合),它将为每个n剥离()两次-python在优化列表comps方面不好-这就是我拆分它的原因-但它是较短的代码。如果你给它提供了一个有一百万个名字的文件,这可能很重要——如果你提供了5到10个名字,那就不重要了。
['aaaaaaa', 'aaaaaaaa', 'aaaaaaaaa']