Practice Makes Perfect, Unit 8


My code returned an error when executed

def censor(text, word):
  crushed = []
  crushed = text.split(" ")
  new_word = ""
  for x, i in enumerate(crushed):
    if crushed[x] == word:
      crushed[x] = ("*" * len(word))
    new_word = " ",new_word.join(crushed[x])
  return new_word

print (censor("I like icecreams", "icecream"))

It gave the error:

AttributeError: ‘tuple’ object has no attribute ‘join’

I’m guessing it has to do with the behaviour of "new_word = " “,new_word.join(crushed[x])”, but I can’t really think of any other ways to join it - printing this operation instead of assigning seems to work fine though.


There are a few spots in your code where you are creating a tuple. A tuple is a collection, much like a list, except that you can’t change the elements (i.e. immutable). You create a tuple when you use the parenthesis:

Get rid of the parenthesis.


The enumerate construct gives you an index and the value in that order. Therefore, your code:

for x, i in enumerate(crushed)

x is the index and i is the word. Right? Think about it.

You have a list of words (which you have in the variable crushed) and when you enumerate, it gives you a single word and its index. Try making the variable names more readable to represent the value each is holding.

Tip: Make your variables more meaning by naming them to represent what the value/data is that it’s holding.

For example:

  1. In your function definition, the parameter word is the censored word. Right? Maybe change it to be censored_word.
  2. In the enumerate, change x to be index and i to be word.

Renaming your variables give them more meaning and will help you as you layout your code.

Comparing the word

While this code works, why look up the value using the index?

if crushed[x] == word

Why not use the word that was fetched with the enumerate? Maybe this is more clear and readable:

if word == censored_word

Rejoining the words

Lastly, look at where you are rejoining the words together. Think about it. During the loop, you are comparing each word to the censored word. If they match, then you’re replacing that word with an * for each character in the word and storing it back into the crushed list.

Given that, when would you want to rejoin all of the words and return it back?

Tip: The join() construct works like this:

' '.join(crushed)

where ' ' is the separator (or delimiter) that goes in between the words.

Try to rework your code and get it working.


The second line yields a list so the first line is not needed.

That line is also not needed, and neither is the variable since we can just return the joined sting.

return " ".join(crushed)

The join statement should not be inside the loop.

This will return the original string, uncensored. icecreams and icecream are not identical so do not match.

>>> def censor(text, word):
  crushed = text.split(" ")
  for x, i in enumerate(crushed):
    if i == word:
      crushed[x] = ("*" * len(word))
  return " ".join(crushed)

>>> print (censor("I like icecream", "icecream"))
I like ********

As we can see, there is no issue with the tuples.

  1. I don’t think getting rid of the parenthesis would do any changes, I need to place the parenthesis there anyways since the code was being executed by python3, which required parenthesis between a “print()” statement.
  2. According to the python textbook, the three single words: “k”,“i”,“y” is one of the most common conventional variables to use in loops, hence I use these words - besides, I get to choose how I name my variable however I want right? - as long as I am able to understand it, changing the name would make no difference.
  3. To compare words, I was taught this way before I used python - to think codes in listing that is. I tried what you suggested and replaced the “crushed[x]” with “words”, apparently - the code failed to make any changes to the censored word. It looks like you have to specifically state the index list in order to change it.
  4. I already know how the join function worked - this should’ve been clearly shown in my code by now. I did take up on your suggestion and moved by join() function one indention back - it did work, but it always returns the result in list


This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.