简体   繁体   中英

How can I tell what value my function is returning in Python?

I'm trying to debug this program I wrote. How can I tell if, for a given word , hand , and word_list , it returns True or False? I tried initializing a variable failure and then modifying it and printing it's value. It isn't printing, so I don't know if it is behaving like it's supposed to. Any help is appreciated.

I have a function load_words() that returns a list of words. I know word is in word_list (I checked), so just trying to see if word is composed entirely of letters from the keys in the dictionary hand , which in this case it isn't, so it should return False.

Also, what is the difference between .keys() and .iterrkeys(), and is there a better way of looping through hand , perhaps with letter, value in hand.iteritems() ?

word = 'axel'

hand2 = {'b':1, 'x':2, 'l':3, 'e':1}

def is_valid_word(word, hand, word_list):
    """
    Returns True if word is in the word_list and is entirely
    composed of letters in the hand. Otherwise, returns False.
    Does not mutate hand or word_list.

    word: string
    hand: dictionary (string -> int)
    word_list: list of lowercase strings
    """
    failure = False
    if word in word_list:
        print hand
        print [list(i) for i in word.split('\n')][0]
        for letter in [list(i) for i in word.split('\n')][0]:
            print letter
            if letter in hand.keys():
                print letter
                return True
                failure = True
                print failure
            else:
                return False
                failure = False
                print failure
    else:
        return False
        failure = False
    print failure

is_valid_word(word,hand2,load_words())

UPDATE I wish to use this function in my function, but it gives a key error, even though it works fine on its own.

def update_hand(hand, word):
    """
    Assumes that 'hand' has all the letters in word.
    In other words, this assumes that however many times
    a letter appears in 'word', 'hand' has at least as
    many of that letter in it. 

    Updates the hand: uses up the letters in the given word
    and returns the new hand, without those letters in it.

    Has no side effects: does not modify hand.

    word: string
    hand: dictionary (string -> int)    
    returns: dictionary (string -> int)
    """
    for letter in [list(i) for i in word.split('\n')][0]:
        if letter in hand.keys():
            hand[letter] = hand[letter]-1
        if hand[letter] <= 0:
            del hand[letter]
    display_hand(hand)
    return hand

The reason why it is not printing out is because you are returning the function before it print s. This means that the program stops before it reaches the print statement. For example:

def foo(x):
    return x
    print x

foo("asdf")

Will return nothing while:

def foo(x):
    print x
    return x

foo("asdf")

Will print :

asdf

So, all your statements before return . If not, it will not execute.

For your second clarification, this post already has your answer https://stackoverflow.com/a/3617008 :

In Python 2, iter(d.keys()) and d.iterkeys() are not quite equivalent, although they will behave the same. In the first, keys() will return a copy of the dictionary's list of keys and iter will then return an iterator object over this list, with the second a copy of the full list of keys is never built.

Note that Python 3 does not have .iterkeys() too. Python 3 uses the previous .iterkeys() as the new .keys() .

Lastly , I will review what is generally wrong with your code and what you want to achieve in descending order of severity.

  1. Your code only checks one letter
  2. [list(i) for i in word.split('\\n')][0] is not how you get all the letters from a word.
  3. You should make short code return first so that you would not have big indent blocks.

Your code only checks one letter

In your for loop, you return True immediately after the first word is checked. You should return True after the loop is completed instead.

for letter in word:
    if letter not in hand.keys():
        return False
return True

List comprehension

Your list comprehension is not needed (I'll tell you why later) and need not be so complex just to get the letters from a word. Eg

[list(i) for i in word.split('\n')][0]

Actually only does this:

list(word)

In fact, you should just iterate through the word directly (as I did above), it will return the letters one by one:

for letter in word:
    # code...

Make short code return first

Usually I dislike big chunks of highly indented code. What you can do is make the short code return first. For example:

if word in word_list:
    for letter in word:
        if letter in hand.keys():
            return True
        else:
            return False
else:
    return False

Can be simply be written as:

if word not in word_list:
    return False

for letter in word:
    if letter in hand.keys():
        return True
    else:
        return False

However, this is just my opinion. Some others may prefer the else statement so that they know when the code is executed.

Your final code would look like:

def is_valid_word(word, hand, word_list):
    if word not in word_list:
        return False

    for letter in word:
        if letter not in hand.keys():
            return False
    return True

Clean right? However, I assume that you are making something like a scrabble game, so you would count if the words in your hand can for the word you chose. What you can add is something to count if the number of letters in the word is less than or equal to the number of letters in your hand:

def is_valid_word(word, hand, word_list):
    if word not in word_list:
        return False
    # This makes the word into a "unique list"
    letters = set(word)
    for letter in letters:
        if hand[letter] < word.count(letter):
            return False

    return True

EDIT There was a problem with the code. It does not check if the letter is in hand in the if statement: if hand[letter] < word.count(letter): .

def is_valid_word(word, hand, word_list):
    if word not in word_list and word not in hand.keys():
        return False
    letters = set(word)
    for letter in letters:
        # Add this extra clause
        if letter in hand.keys() or hand[letter] < word.count(letter):
            return False

    return True

您可以直接print is_valid_word(word,hand2,load_words())结果print is_valid_word(word,hand2,load_words())

You have some indentation issues, and doing something after a return statement is futile.

You don't need to use keys or iterkeys the in operator will check for you, and will work with lists, set, dicts (keys), tuples, strings, ...

The in operator invokes __contains__ which is supported by most python collections.

Also have look at https://docs.python.org/2/reference/expressions.html#membership-test-details .

He is a minimized example of what you want to do with 3 tests.

def is_valid_word(word, hand, word_list):
    """
    Returns True if word is in the word_list and is entirely composed
    of letters in the hand. Otherwise, returns False.  Does not mutate
    hand or word_list.

    word: string
    hand: dictionary (string -> int)
    word_list: list of lowercase strings

    """

    if word not in word_list:
        return False

    for letter in word:
        if letter not in hand:
            return False

    return True

print(is_valid_word('bxel',
                    {'b': 1, 'x': 2, 'l': 3, 'e': 1},
                    ['foo', 'bar', 'bxel']))
print(is_valid_word('axel',
                    {'b': 1, 'x': 2, 'l': 3, 'e': 1},
                    ['foo', 'bar', 'axel']))
print(is_valid_word('axel',
                    {'a': 1, 'x': 2, 'l': 3, 'e': 1},
                    ['foo', 'bar', 'axel']))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM