Let's go through it line by line.
ops1 = {
        "1": print("1"), # this value is actually the value returned by print
        "2": print("2"),
        "4": print("4")
} # when the dictionary is created, everything in it is evaluated,
# so it executes those print calls
# that's why you see all three printed
lis = [1, 2, 3]
for x in range(0, len(lis)-1): # this includes 0 and 1
    if (lis[x] in ops1.keys()): # lis[0] is 1 and lis[1] is 2
        ops1.get(x) # look for 0 and then 1 in the dictionary
Now let's fix it.
ops1 = {
        "1": lambda: print("1"), # this value is now a FUNCTION, which you can call later
        "2": lambda: print("2"),
        "4": lambda: print("4")
} # when the dictionary is created, everything in it is evaluated, but the functions are not called
lis = [1, 2, 3]
for x in range(len(lis)): # goes through 0, 1, and 2
    if lis[x] in ops1: # lis[0] is 1, lis[1] is 2, lis[2] is 3
        ops1.get(str(lis[x]), print)() # look for '1', '2', and '3',
                                       # then call their values
You could improve that last loop like this:
for x in lis:
    ops1.get(str(x), print)()
So, first we look up the key '1'. That corresponds to a function. Then we call the function. This prints the string '1\n'. Then we look up the key '2'. That corresponds to a function. Then we call the function. This prints the string '2\n'. Then we look up the key '3'. This is not present in the dictionary, so it returns a default function. Then we call this default function. This prints the string '\n'.