Python 3.6 sleep() different sleep times within same string depending on character

Question:

In python 3.6, I’m trying to get a string to print with a delay between characters and a longer delay for punctuation at the end of sentences to pseudo-simulate spoken English. Here is my code. My problem is that I get the delay between characters, but I don’t get the longer delay between sentences.

import time
import sys


def delay_print(s):
    for c in s:
        if c != "!" or "." or "?":
            sys.stdout.write(c)
            # If I comment out this flush, I get each line to print
            # with the longer delay, but I don't get a char-by char 
            # delay
            # for the rest of the sentence.
            sys.stdout.flush()
            time.sleep(0.05)
        elif c == "!" or "." or "?":
            sys.stdout.write(c)
            sys.stdout.flush()
            time.sleep(3)


delay_print( """
    Hello.
    I want this to have an added delay after sentence-ending 
    punctuation?
    But I also want it to have a shorter delay after each character 
    that isn't one of those chars.
    This is supposed to mimic speech patterns. Like if you've ever 
    played SNES Zelda: A Link to the Past.
    Why isn't this code doing what I want it to?.
    What I've written is broken and I don't know why!
""")
Asked By: sr71shark

||

Answers:

Your or clause isn’t doing what you think it’s doing. The first one checks if any of these three things is True:

  1. character != "!"
  2. bool(".")
  3. bool("?")

Note that 2 and 3 are always true.

If statements short circuit evaluate. If the character input were ., it would check condition 1 and find it false. Then it would include condition 2 in the evaluation False or ".". Since "." is always true, it short circuits and returns "." which evaluates to true. Try it yourself, type False or "." into the interpreter, you’ll find it returns ".".

Personally, I would do this with a set implementation like this:

if c not in {"!", ".", "?"}:
Answered By: sage88

Both of the conditions that you are testing will always evaluate to True no matter what the value of c:

>>> letter == "!" or "." or "?"
'.'
>>> letter = "a"
>>> if letter != "!" or "." or "?":
    print("not punctuation")


not punctuation
>>> if letter == "!" or "." or "?":
    print("punctuation")


punctuation

As another user suggest it may make more sense for you to change your tests to:

>>> letter in "!.?"
False
>>> letter not in "!.?"
True

Also, on a more stylistic note I would consider using a random delay between letters to make it even more organic feeling.

import random

...

delay = random.random() + 2.5
sleep(delay)
Answered By: lvrf

Give this a shot! Your first if statement needs to use ‘and’ instead of ‘or’, because it was always True.

def delay_print(s):
    for c in s:
        if c != "!" and c != "." and c != "?":
            sys.stdout.write(c)
            sys.stdout.flush()
            time.sleep(0.05)
        else:
            sys.stdout.write(c)
            sys.stdout.flush()
            time.sleep(3)
Answered By: Kurt
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.