Or instead of doing it in a single grep, use one grep to find files with 3-or-more 7s and another to filter out 4-or-more 7s.
ls -f | egrep '7.*7.*7' | grep -v '7.*7.*7.*7'
You could move some of the work into the shell glob with the shorter
ls -f *7*7*7* | grep -v '7.*7.*7.*7'
though if there are a large number of files which match that pattern then the latter won't work because of built-in limits to the glob size.
The '-f' in the 'ls' is to prevent 'ls' from sorting the results. If there is a huge number of files in the directory then the sort time can be quite noticeable.
This two-step filter process is, I think, more understandable than using the [^7] patterns.
Also, here's the solution as a Python script, since you asked for that as an option.
import os
for filename in os.listdir("."):
if filename.count("7") == 4:
print filename
This will handle a few cases that the shell commands won't, like (evil) filenames which contain a newline character. Though even here the output in that case would likely still be wrong, or at least unprepared for by downstream programs.