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']