FAQ: Code Challenge: Loops - Greetings

What object are you growing from scratch? That’s the one to return.

Ok, I tried to return greetings, I got this:

[<generator object add_greetings.. at 0x7fc11d733518>]

That’s because your are returning a generator.

('Hello, ' + name for name in names)

If you wanted, you could use a list comprehension so a list is returned. It would not need to initialized, or even bound to a variable…

return ['' + _ for _ in object]
1 Like

I am completely new in this programming field. I write the following code against this exercise


#Write your function here

def add_greetings(names):

** new_list = **

** hello = "Hello, "**

** for name in names:**

** combine = str(hello) + new_list.append(name)**

** return combine**

#Uncomment the line below when your function is done

print(add_greetings([“Owen”, “Max”, “Sophie”]))


But when I am executing the code, I am getting the following error message:

Traceback (most recent call last):
File “script.py”, line 12, in
print(add_greetings([“Owen”, “Max”, “Sophie”]))
File “script.py”, line 7, in add_greetings
combine = str(hello) + new_list.append(name)
TypeError: must be str, not NoneType

Any idea what is wrong with the code?

Regards

Mani

I would start by unraveling that line.

* `hello` is defined as a str
* list.append() returns undefined

A post was split to a new topic: Only shows one value in returned list

I’ve done this and it is working

def add_greetings(names):
list =
for name in names:
string = 'Hello, ’ + name
list.append(string)
return list

It’s all about indentation. I was trying to figure out why my code didn’t worked.

def add_greetings(names):
  lst=[]
  for i in names:
    lst.append("Hello, "+i)
    return lst

Then I notice that other similar codes with list comprehension.

def greet(names):
message = [f"Hello, {name}" for name in names]
return message

Hello everyone, My Name is Lazar. I am new in Python.
I done it this way. Took a bit struggle.

#Write your function here

def add_greetings(names):

new_greetings =

for name in names:

new_greetings.append("Hello,  " + name)

return new_greetings

#Uncomment the line below when your function is done

print(add_greetings([“Owen”, “Max”, “Sophie”]))

My output is

Hello @text7972675636!

Remember that return statements exit a function once they are executed. Double-check your indentation and make sure your for loop iterates the number of times you want it to.

While I’ve found a few different solutions to this exercise, I like to challenge myself to find as many as possible to ensure I’m understanding the code. In the instructions for this exercise, they specifically ask to use the append method to find a solution, and ironically I am having trouble using append to come to an elegant solution, and most times I try, I get a similar type response which is obviously not the return value I’m looking for.

Here is an example of my most recent attempt using append to find a solution:

def add_greet(names):
greeting = ['Hello, ']
greeting.append(name for name in names)
return greeting

print(add_greet([“Owen”, “Max”, “Sophie”]))

You mentioned in this reply that it’s because a generator is being returned. What do you mean exactly? What is the generator? I’m assuming the generator must be the for loop. How would you use the append method to find an elegant solution (not repeating append several times)?


Another common “error” (not actually an error, but an unwanted response) I get from attempting to use append is:

['Hello, ', [‘Owen’, ‘Max’, ‘Sophie’]]

when I’m supposed to be getting:

[‘Hello, Owen’, ‘Hello, Max’, ‘Hello, Sophie’]

This second “error” is a lot easier to understand the syntax mistake, but I simply cannot find an elegant solution to this exercise without facing at least one of these problems. Whenever I think I’ve got it, sure enough, one of these things is outputting, if not an actual red error message.

First we need to understand, ‘what is an iterator?’ Plug both these questions into search (add ‘py’ to the search phrase) and jump to learnpython.org if it comes up. Fairly simple answers to rather difficult questions to answer in an easy way. There’s some wrapping of our heads around it involved.

Once you’re done your reading, try this example…

>>> def add_greet(names):
    for name in names:
        yield f"Hello, {name}."

        
>>> for x in add_greet(['Owen', 'Max', 'Sophie']):
	print (x)

	
Hello, Owen.
Hello, Max.
Hello, Sophie.
>>> 
1 Like

Thank you for the response, I’ve taken a chunk of my time today and dedicated it to reading and learning about iterators, iterables, and generators. I used your resources and then some other outside sources as well. I have a few more questions if you have the time:

Please correct me if I’m wrong, but as I understand it, lists, tuples, sets, etc. are all iterable. A ‘string’ that could be pulled from a [list] for example would be an iterator. However, strings are also iterable. So it’s possible for something to be both iterable and an iterator, is this correct? If so great, I think I’m getting it. If not, I gotta dig back in to some further reading.

As for generators, it seems as though I was right in that the for loop inside my append method is the generator. Since there is no yield or return command is that why the output is the generator rather than my desired output? Does the append method not act as a return/yield itself, but something different? How would I fix this? Is there a way to include one of those commands to get the desired output from the generator without adding another variable, or would I need to rework my code entirely and not use the append method at all? Again I have found other solutions to this exercise, but challenging myself in this way has proved to be fruitful for my knowledge and understanding, and the exercise did ask to use the append method specifically, which I cannot find an elegant solution using.


With your second example, I noticed how the f in front of yield gets rid of the brackets that were haunting my second solution. I haven’t learned what this f command does yet, nor have I learned about yield until outside reading of generators, but perhaps it comes up later in the course. Hopefully–I know codeacademy isn’t the end all be all for my learning and education purposes, but I do appreciate the structure.

Anyway, again with your second example, it does work when you call it with the for loop you used, but the exercise asks us to write a function that works with the following call:

print(function([ ‘Owen’, ‘Max’, ‘Sophie’]))

When I tested your examples with the given call above it produced a similar generator object output that I do not want.

While I feel like I’ve furthered my understanding of the terminology, I’m unsure if I’ve learned anything that I could apply in practice yet, but I’m almost there. Thank you so much for your response and all your other responses, over the last few days of me starting this course I’ve seen so many of your responses over the years that have helped me and so many others grasp these concepts.


I’m going to keep at it for a while longer before continuing with the course, but I still cannot find a suitable elegant solution to this exercise using the append method, and skimming thru the forums it seems neither has anyone else. There are solutions using append, but they all seem much more complicated than the other solutions I’ve found and I’m sure there must be a better way of doing it.

For reference, here are my other two solutions to this exercise (using the given call exercise above), so you can see where my level of understanding is at:

def add_greetings(names):
greeting = ['Hello, ’ + name for name in names]
return greeting

def add_greeting(names):
return ['Hello, ’ + name for name in names]

As far as I understand it, the first solution would be better if I wanted to keep that list stored as variable greeting, so that I might reference it somewhere else in the function, correct? But if I were to try and call it outside of the function, it’s only defined in the local scope so it would still result in None. Whereas the second solution obviously doesn’t store it in any variable and thus the list would purely be an output and not saved anywhere for further reference.


EDIT: I have found a decent solution using the append method:

def hello(names):
greeting =
for name in names:
greeting.append('Hello, ’ + name)
return greeting

Brief reply, not having read more than the first couple paragraphs. Iterable means it can be enumerated. Regardless the structure, there are fixed data points, either keys or indices.

Being iterable does not make an object and iterator. An object that can iterate an iterable would be an iterator, or at least that much closer to being one. Iterables are not iterators since they are relatively static, some perhaps mutable. They have methods that can iterate them, one common to them all being, __iter__(). Iterables don’t get consumed. They are not a one-time access object. Iterators are all in, one go. Once they’re consumed they’re done.

Think in terms of sequences. One and then another one, and then another one, … That’s what defines an iterable. An iterator sees, next one, next one, next one, …

They will come up, but for now be able to distinguish subscriptable from unsubscriptable. Learn to recognize a sequence and all the methods we have to access and manipulate them (if possible).

The code structure produced a generator owing that it incorporated a for loop where an expression is expected. Since that syntax is recognized as an expression, it passes as an argument. Only problem is, .append() doesn’t know how to turn on the iterator.

What does .append() do?

1 Like

The assignment never asks for a generator, so no matter that the example works as expected it is not what the lesson checker expected, a list. Generators are not lists.

Sometimes, or most times it is best to go right back to basics and construct a basic loop to iterate over our object.

>>> def add_greet(names):
    temp = []
    for name in names:
        temp.append(f"Hello, {name}.")
    return temp

>>> for x in add_greet(['Owen', 'Max', 'Sophie']):
	print (x)

	
Hello, Owen.
Hello, Max.
Hello, Sophie.
>>>

Apt description, thank you for the concise definition. Is my understanding correct in that anything that can be indexed is iterable then, since they can all be enumerated via the indexing?

Iterators can be pulled from iterables, meaning a string an iterator, and strings are also enumerated, which means they are iterables as well.

I also read that all iterators are iterable, but not every iterable is an iterator. If that is true, then if you were to pull (or iterate) a character out of a string, (using .pop() lets say) that would make that character an iterator, yes? Which means it’s also iterable… but what could you iterate out of a character? And if you were to have a variable which is a list of lists, if you were to pull a single list out of that list of lists, wouldn’t that list you pulled also be an iterator? But lists are not supposed to be iterators… Maybe I’m not wrapping my mind around this correctly, I thought I had it understood but after thinking deeper it’s not all adding up it seems.

I’ve done a lot of reading on this subject now, subscriptable means it’s a container of some sort, such as a list, or even a string, since a string contains characters. Whereas unsubscriptable doesn’t contain anything, I would imagine a character in a string would be unsubscriptable, which means it can’t be enumerated, which means it shouldn’t be iterable… but again it all iterators are iterable… that’s my biggest hang up now. I seem to be “getting” everything else.

I also understand a list is subscriptable, so it contains objects, and is iterable. Whereas an iterator yields objects (maybe even from that list), but doesn’t store or save them, they are “consumable”, as you said.

.append() is a method that is used to save yielded (or are they returned?) objects to the end of the subscriptable it was applied to.

I want to say that makes .append() an iterator, since it yields an object, and the list the saves the yielded object. A .method() is similar to a function() and generators are both iterators and functions, so please tell me because I can’t make up my mind on which logic makes sense:

Is .append() a generator? And the for loop is also a generator? Or are one of these just iterators?
Can other methods be considered iterators or generators?


As for your second response, I didn’t understand the difference between a generator and a list until this discussion, so thank you for enlightening me. While the generator might’ve provided the correct response, that response isn’t saved and ready to be referenced later like it would be in a list, but rather displayed and then deleted, or consumed.

I understand the distinction now, however, our code in my edit and your second response look near identical–the only difference being some syntax in our append line. You use the f command which I haven’t had time to look up yet (been trying to wrap my head around iterables, iterators, and generators), but I’m guessing allows you to put a variable inside the ‘string’ without using + concatenation. But aside from the minor syntax difference they seem identical, as does the matching output if it were called with the same line as in the exercise.


Thank you again! Sorry for taking up so much of your time with these lengthy responses, I am very eager to learn and I’m trying to do my due diligence before wasting your time with these questions, and your replies sharing your knowledge and wisdom on the subject are very much appreciated! I aspire to have an understanding like yours someday.

1 Like

New coder here. Apologies if this has already been asked and answered, but I’m wondering if there’s something I’m missing conceptually here or if this is an SCT interpretation problem. In my first attempt, I tried using .append() as the exercise indicated:

def add_greetings(names):
  mssgs = []
  greetings = ["Hello, " + person for person in names]
  mssgs.append(greetings)
  return mssgs 

which returned:

[['Hello, Owen', 'Hello, Max', 'Hello, Sophie']]

This was marked as incorrect, even though my code run as expected.

On my second try, I updated the append line, so my code read:

def add_greetings(names):
  mssgs = []
  greetings = ["Hello, " + person for person in names]
  mssgs += greetings
  return mssgs

which returned the “correct” answer:

['Hello, Owen', 'Hello, Max', 'Hello, Sophie']

Am I correct in assuming that the first output was marked “incorrect” because my code returned a list inside of a list rather than a single list of strings? And if so, is there a rule of thumb or best practice for when to use .append() rather than the += operator when working with loops?

No rule, just design. We are the architects of how our data is stored. If we want a list of lists, then use append(), else if we wish to insert into a list, use += or its equivalent, extend().

a = [1, 2, 3]
a.append([4, 5, 6])
a
[1, 2, 3, [4, 5, 6]]
a.extend([7, 8, 9])
a
[1, 2, 3, [4, 5, 6], 7, 8, 9]

Note the subtle difference.

a += 10, 11, 12
a
[1, 2, 3, [4, 5, 6], 7, 8, 9, 10, 11, 12]

Notice how when we use += it treats the assignment as a sequence so behaves the same as extend([…]).

1 Like

This is really helpful, thanks!

1 Like