简体   繁体   English

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

[英]Return value in a quite nested for-loop

I want nested loops to test whether all elements match the condition and then to return True. 我希望嵌套循环测试所有元素是否都符合条件,然后返回True。 Example: 例:

There's a given text file: file.txt, which includes lines of this pattern: 有一个给定的文本文件:file.txt,其中包含此模式的行:

aaa:bb3:3 AAA:BB3:3

fff:cc3:4 FFF:CC3:4

Letters, colon, alphanumeric, colon, integer, newline. 字母,冒号,字母数字,冒号,整数,换行符。

Generally, I want to test whether all lines matches this pattern. 通常,我想测试所有行是否都与此模式匹配。 However, in this function I would like to check whether the first column includes only letters. 但是,在此功能中,我想检查第一列是否仅包含字母。

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

However, the function returns False even if all characters in the first column are letters. 但是,即使第一列中的所有字符均为字母,该函数也会返回False。 I would like to ask you for the explanation, too. 我也想请您解释一下。

Your code evaluates the empty line after your code - hence False : 您的代码在代码之后评估空行-因此为False

Your file contains a newline after its last line, hence your code checks the line after your last data which does not fullfill your test- that is why you get False no matter the input: 您的文件在最后一行之后包含一个换行符,因此您的代码将在最后一个数据之后检查该行,这并不能完全满足您的测试要求,这就是无论输入内容为何都为False原因:

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

You can fix it if you "spezial treat" empty lines if they occur at the end. 如果您“空头对待”空行(如果它们出现在末尾),则可以对其进行修复。 If you have an empty line in between filled ones you return False as well: 如果在填充的行之间有一个空行,则也会返回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"))

Output: 输出:

True

If you use 如果您使用

# 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
""") 

or 要么

# 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


""") 

you get: False 您得到: False

Colonoscopy 结肠镜检查

  1. ASCII, and UNICODE, both define character 0x3A as COLON . ASCII和UNICODE都将字符0x3A定义为COLON This character looks like two dots, one over the other: : 这个字符看起来像两个点,一个在另一个上

  2. ASCII, and UNICODE, both define character 0x3B as SEMICOLON . ASCII和UNICODE都将字符0x3B定义为SEMICOLON This character looks like a dot over a comma: ; 这个字符看起来像逗号上的点: ;

You were consistent in your use of the colon in your example: fff:cc3:4 and you were consistent in your use of the word semicolon in your descriptive text: Letters, semicolon, alphanumeric, semicolon, integer, newline. 在示例中,您对冒号的使用是一致的: fff:cc3:4并且在描述性文本中对分号一词的使用也一致: Letters, semicolon, alphanumeric, semicolon, integer, newline.

I'm going to assume you meant colon (':') since that is the character you typed. 我假设您的意思是冒号 (':'),因为这是您键入的字符。 If not, you should change it to a semicolon (';') everywhere necessary. 如果不是,则应在需要的任何地方将其更改为分号(';')。

Your Code 您的密码

Here is your code, for reference: 这是您的代码,以供参考:

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

Your Problem 你的问题

The problem you asked about was the function always returning false. 您询问的问题是该函数始终返回false。 The example you gave included a blank line between the first example and the second. 您给出的示例在第一个示例和第二个示例之间包含一个空白行。 I would caution you to watch out for spaces or tabs in those blank lines. 我会提醒您注意那些空白行中的空格或制表符。 You can fix this by explicitly catching blank lines and skipping over them: 您可以通过显式捕获空白行并跳过它们来解决此问题:

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

Some Other Problems 其他一些问题

Now here are some other things you might not have noticed: 现在,您可能还没有注意到其他一些事情:

  1. You provided a nice comment in your function. 您在函数中提供了一个很好的注释。 That should have been a docstring: 那应该是一个文档字符串:

     def opener(file): """ Opens a file and creates a list of lines. """ 
  2. You import string in the middle of your function. 您可以在函数中间import string Don't do that. 不要那样做 Move the import up to the top of the module: 将导入移动到模块顶部:

     import string # at top of file def opener(file): # Not at top of file 
  3. You opened the file with open() and never closed it. 您使用open()打开了文件,但从未关闭它。 This is exactly why the with keyword was added to python: 这也正是为什么with关键字加入到Python:

     with open(file) as infile: fi = infile.read().splitlines() 
  4. You opened the file, read its entire contents into memory, then split it into lines discarding the newlines at the end. 您打开了文件,将其全部内容读取到内存中,然后将其拆分为几行,最后丢弃了换行符。 All so that you could split it by colons and ignore everything but the first field. 所有这些使您可以用冒号分隔它,而忽略除第一个字段以外的所有内容。

    It would have been simpler to just call readlines() on the file: 仅在文件上调用readlines()会更简单:

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

    It would have been even easier and even simpler to just iterate on the file directly: 直接对文件进行迭代将更加容易甚至更加简单

     with open(file) as infile: res = True for i in infile: 
  5. It seems like you are building up towards checking the entire format you gave at the beginning. 看来您正在逐步检查开始时给出的整个格式。 I suspect a regular expression would be (1) easier to write and maintain; 我怀疑正则表达式会(1)易于编写和维护; (2) easier to understand later; (2)以后比较容易理解; and (3) faster to execute. (3)执行速度更快。 Both now, for this simple case, and later when you have more rules in place: 现在,对于这种简单的情况,以及稍后您有更多规则时:

     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. Your names are bad. 你的名字不好。 Your function includes the names file , fi , i , j , and res . 您的函数包括名称file fiijres The only one that barely makes sense is file. 唯一几乎没有意义的是file.

    Considering that you are asking people to read your code and help you find a problem, please, please use better names. 考虑到您正在要求人们阅读您的代码并帮助您发现问题, 使用更好的名称。 If you just replaced those names with file (same), infile , line , ch , and result the code gets more readable. 如果你只是更换那些名称与file (下同), infilelinech ,并result代码变得更具可读性。 If you restructured the code using standard Python best practices, like with , it gets even more readable. 如果您使用标准的Python最佳实践(例如with来重组代码,那么它的可读性会更高。 (And has fewer bugs!) (而且错误更少!)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM