5
\$\begingroup\$

It's a (simple) guesser for game where you need to find words of a given length only using given letters. I'd like to know if there's a more pythonic way to do things here.

#!/usr/bin/env python3
import sys

if len(sys.argv) < 3:
    sys.exit("Usage: " + sys.argv[0] + " letters number_of_letters [dictionnaryfile]")

letters = sys.argv[1].upper()
wordsize = int(sys.argv[2])
dictionnary_name =  "dict.txt" if len(sys.argv) < 4 else sys.argv[3]

try:
    wordlist = open(dictionnary_name).read().split('\n')
except FileNotFoundError:
    sys.exit("Couldn't find dictionnary file \"" + dictionnary_name + "\"")

good = []
for w in wordlist:
    if len(w) == wordsize:
        up = w.upper()
        ok = True
        for c in up:
            if not c in letters:
                ok = False
                break
        if ok:
            good.append(w)

print("Found " + str(len(good)) + " results:")      
print(good)
\$\endgroup\$
1
  • 1
    \$\begingroup\$ checkout argparse. It's awesome! Also, it's worth avoiding making the wordlist upfront and instead iterating over the file object so the whole dictionary isn't read into memory, and is read from line by line instead. \$\endgroup\$
    – GP89
    Jun 6 '13 at 10:08
8
\$\begingroup\$

The following code shows I would have done what you asked in Python 2.7. Other readers will tell you the ways in which it is a) not Pythonic and b) wrong.

  • Start with a module comment describing what the code is intended to do. (This is available to the code as __doc__.)

  • Use the various Python string delimiters to avoid escaping.

  • Name variables consistently.

  • strip() text strings read from a text file.

  • Make letters a set to reflect its usage.

  • Create the list of matching words with a list comprehension.

Here is the code.

"""
    Find all the words in a reference dictionary with a specified number of letters
    that contain all the letters in a specified list of letters.

    The number of letters and the list of letters must be specified on the command line.

    The reference dictionary may be specified on the command line. If is not then 
    dict.txt is used.

    The matching of letters is case-insensitive. 
"""
import sys

if len(sys.argv) < 3:
    print >> sys.stderr, __doc__
    sys.exit('Usage: %s letters number_of_letters [dictionary_file]' % sys.argv[0])

letters = set(sys.argv[1].upper())
wordsize = int(sys.argv[2])
dictname = 'dict.txt' if len(sys.argv) <= 3 else sys.argv[3]

try:
    wordlist = [w.strip() for w in open(dictname).readlines()]
except IOError:
    sys.exit('''Couldn't find dictionary file "%s"''' % dictname)

matches = [w for w in wordlist 
             if len(w) == wordsize 
                and all(c in letters for c in w.upper())]

print 'Found %d results:' % len(matches)      
print matches
\$\endgroup\$
2
  • \$\begingroup\$ BTW, any reason to remove the shebang? \$\endgroup\$ Jun 1 '13 at 15:53
  • \$\begingroup\$ I forgot to add it. \$\endgroup\$ Jun 2 '13 at 4:34
2
\$\begingroup\$

One thing others have missed is the style of opening files. Use the with statement to have it automatically closed once it's no longer needed.

try:
    with open(dictname) as f:
        wordlist = [w.strip() for w in f]
except IOError as e:
    sys.exit('Error opening file "{0}", errno {1}'.format(e.filename, e.errno))

You can't assume it's because the file doesn't exist. Other errors result in an IOError as well. You'd need to check its errno.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.