I can't figure out why this is wrong


15.Practice Makes Perfect 10.censor

Your function fails on censor("hey hey hey","hey"). It returns "hey hey hey" when it should return "*** *** ***".

def censor (text,word):
    for i in text_words:
        if i==word:
            i="*" *len(word)
    return " ".join(text_words)


This is not how we mutate the iteratable. We can only poll it for values. To change (mutate) we need to use integer indices, and therefore iterate over a range.

    for i in range(len(text_words)):
        if text_words[i] == word:
            text_words[i] = "*" * len(word)

That's the index side of the picture. We do have one more tool up our sleeve, enumerate which treats all iterable objects, including strings and lists, as dictionaries.

def censor (text,word):
    text_words = text.split()
    for i, x in enumerate(text_words):
        if x == word:
            text_words[i] = "*" * len(word)
    return " ".join(text_words)
print censor("I love cats", "cats")    // I love ****

Here we are able to query the value in x, and mutate it with index i (i being a key).


First ,thank you very much for the quick and detailed answer!
But i have to bother you with another question , the reason why i iterate the text_words in this way is that i think text_words is a list ,and i think it's ok to iterate a list like that .
for a example
for i in my_list:
print i

the result :1

so here is the question ,whether the return of the .split() is a list ?
and if it is ,why i can't iterate it?
ps. the code you provide works


When we write,

for i in x:

i is a value, so cannot be used as an index of a list (which must be integer). Consequently we cannot mutate that value in our loop. We need an index reference to the value.

for i in range(len(x)):

i is an integer, or index of x. Now it is the reference, not the value, and we can mutate the value that it references.


is the same as,

string.split(" ")

by default (in Python).