Search code examples
pythonpython-3.xinputuser-input

How Does sys.stdin.read() Change the Structure of a Literal Parameter?


Backstory: In my previous post, I was wondering if a certain function was valid to replace another function and it was, so, I technically don't need an answer to help with with my project but I was just wondering "had I continued using sys.stdin.read() instead of input(), how would I get through one of my roadblocks?"

My issue: For some reason, when I used sys.stdin.read() it did not work with literal strings or chars. This is a lazy but working reconstruction of my code...

print("Type p or P for a pyramid")
print("Type s or S for the sum and product of two numbers")
choice_1 = sys.stdin.read()

# edge case for inputted char being invalid
if str(choice_1) != ('p' or 'P' or 's' or 'S')
    err_test = 'z'
    while str(err_test) != ('p' or 'P' or 's' or 'S')
        print("Invalid option!)
        print("Type p or P for a pyramid")
        print("Type s or S for the sum and product of two numbers"
        err_test = sys.stdin.read()
        if err_test == ('p' or 'P' or 's' or 'S')
            break

This code is roughly what I wrote. I am not writing this question at home so I couldn't copy it word for word. If you see any problems at all, please list them out, whether it's a syntax error or frowed-upon-formatting. I want to learn as much as possible but please, if you have any idea why the line right below the comment (line 6) doesn't work, please let me know! Thanks!

**Edit: ** Thank you so much for the feedback! I forgot to mention though, at one point, I tried isolating the problem so I created a new python file and created a loop that lasted forever and tested it out with only one character. I'll make it super simplified:

char = sys.stdin.read()
if char == 'a':
    print("This works!")
if char != 'a':
    print("This failed!)

Even this code ^^^ didn't work! Please let me know why. –


Solution

  • Your test for "matches one of several accepted strings" is wrong in a similar way to this question's mistake; it's not quite the same due to the use of parentheses, but in this case, both of your tests are equivalent to testing leftside != 'p', because or chains evaluate to the first truthy value, or the last value if all are falsy, and any non-empty string is truthy, so the parenthesized grouping simplifies to just 'p'. You wanted leftside in ('p', 'P', 's', 'S') (or perhaps slightly faster on modern Python, which optimizes tests against set literals of literals to construct an equivalent frozenset at compile time and reuse it, allowing O(1) average case lookup, rather than O(n) tuple scan work, leftside in {'p', 'P', 's', 'S'}).

    Additionally, input will read one line, strip the newline, and return it, while sys.stdin.read() consumes the entirety of stdin on the first call (all lines), leaving it empty, so trying to call it again will not receive anything. If you can't use input for some reason, either of next(sys.stdin).rstrip('\n') or sys.stdin.readline().rstrip('\n') will be roughly equivalent to plain input() (input is more powerful in some ways, e.g. it has readline integration, but it's close).

    Lastly, a minor note: There's no reason to do str(choice_1) or str(err_test) (they're already str, so wrapping in str is pointless).