在完全嵌套的for循环中返回值

时间:2019-02-17 15:19:47

标签: python python-3.x for-loop

我希望嵌套循环测试所有元素是否都符合条件,然后返回True。示例:

有一个给定的文本文件:file.txt,其中包含此模式的行:

  

aaa:bb3:3

     

fff:cc3:4

字母,冒号,字母数字,冒号,整数,换行符。

通常,我想测试是否所有行都与此模式匹配。但是,在此功能中,我想检查第一列是否仅包含字母。

def opener(file):
    #Opens a file and creates a list of lines
    fi=open(file).read().splitlines()
    import string
    res = True
    for i in fi:
        #Checks whether any characters in the first column is not a letter
        if any(j not in string.ascii_letters for j in i.split(':')[0]):
             res = False
        else:
            continue
    return res

但是,即使第一列中的所有字符均为字母,该函数也会返回False。我也想问你一个解释。

2 个答案:

答案 0 :(得分:1)

您的代码在代码后评估空行-因此False

您的文件在最后一行之后包含换行符,因此您的代码将在最后一个数据之后检查该行,这并不能完全满足您的测试-这就是无论输入如何,您都得到False的原因:

aaa:bb3:3
fff:cc3:4
                    empty line that does not start with only letters

如果您“特殊对待”空行(如果它们出现在末尾),则可以对其进行修复。如果在填充的行之间有一个空行,则也会返回False

with open("t.txt","w") as f:
    f.write("""aaa:bb3:3
fff:cc3:4
""") 

import string 
def opener(file):
    letters = string.ascii_letters
    # Opens a file and creates a list of lines
    with open(file) as fi:
        res = True
        empty_line_found = False
        for i in fi:
            if i.strip(): # only check line if not empty
                if empty_line_found:  # we had an empty line and now a filled line: error
                    return False
            #Checks whether any characters in the first column is not a letter
                if any(j not in letters for j in i.strip().split(':')[0]):
                    return False   # immediately exit - no need to test the rest of the file
            else:
                empty_line_found = True

    return res # or True


print (opener("t.txt"))

输出:

True

如果您使用

# example with a file that contains an empty line between data lines - NOT ok
with open("t.txt","w") as f:
    f.write("""aaa:bb3:3

fff:cc3:4
""") 

# example for file that contains empty line after data - which is ok
with open("t.txt","w") as f:
    f.write("""aaa:bb3:3
ff2f:cc3:4


""") 

您得到:False

答案 1 :(得分:1)

结肠镜检查

  1. ASCII和UNICODE都将字符0x3A定义为COLON。此字符看起来像两个点,一个接一个:

  2. ASCII和UNICODE都将字符0x3B定义为SEMICOLON。此字符看起来像逗号上的点:;

您在示例中使用{em> 的情况是一致的:fff:cc3:4,并且在描述性文本中使用了分号的情况也一致:Letters, semicolon, alphanumeric, semicolon, integer, newline.

我要假设您的意思是冒号(':'),因为这是您键入的字符。如果没有,则应在需要的任何地方将其更改为分号(';')。

您的代码

这是您的代码,以供参考:

def opener(file):
    #Opens a file and creates a list of lines
    fi=open(file).read().splitlines()
    import string
    res = True
    for i in fi:
        #Checks whether any characters in the first column is not a letter
        if any(j not in string.ascii_letters for j in i.split(':')[0]):
             res = False
        else:
            continue
    return res

您的问题

您询问的问题是该函数始终返回false。您给出的示例在第一个示例和第二个示例之间包含一个空白行。我会提醒您注意那些空白行中的空格或制表符。您可以通过显式捕获空白行并跳过它们来解决此问题:

for i in fi:
    if i.isspace():
        # skip blank lines
        continue

其他一些问题

现在,您可能还没有注意到其他一些事情:

  1. 您在函数中提供了一个很好的注释。那应该是一个文档字符串:

    def opener(file):
        """ Opens a file and creates a list of lines.
        """
    
  2. import string位于函数中间。不要那样做移动导入 到模块顶部:

    import string # at top of file
    
    def opener(file):   # Not at top of file
    
  3. 您使用open()打开了文件,但从未关闭过。这正是确切为何将with关键字添加到python的原因:

    with open(file) as infile:
        fi = infile.read().splitlines()
    
  4. 您打开了文件,将其全部内容读取到内存中,然后将其拆分为几行 最后丢弃换行符。所有这些使您可以将其用冒号分开并忽略 除了第一个字段之外的所有内容。

    只调用文件上的readlines()会更简单:

    with open(file) as infile:
        fi = infile.readlines()
    
        res = True
    
        for i in fi:
    

    直接遍历文件本来会更容易 和更简单

    with open(file) as infile:
        res = True
        for i in infile:
    
  5. 似乎您正在逐步检查开始时给出的整个格式。我怀疑正则表达式会(1)易于编写和维护; (2)以后比较容易理解; (3)执行速度更快。现在,对于这种简单的情况,以及稍后您有更多规则时,都如此:

    import logging
    import re
    
    bad_lines = 0
    for line in infile:
        if line.isspace():
            continue
        if re.match(valid_line, line):
            continue
        logging.warn(f"Bad line: {line}")
        bad_lines += 1
    return bad_lines == 0
    
  6. 您的名字不好。您的函数包括名称filefiijres。唯一没有道理的是file.

    考虑到您正在要求人们阅读代码并帮助您发现问题,请使用更好的名称。如果您仅用file(相同),infilelinechresult替换这些名称,则代码将更具可读性。如果您使用with之类的标准Python最佳实践来重组代码,它的可读性将更高。 (而且错误更少!)