Build a Pin Extractor - Step 19

Tell us what’s happening:

The terminal says

Traceback (most recent call last):
File “main.py”, line 31, in
File “main.py”, line 21, in pin_extractor
AttributeError: ‘list’ object has no attribute ‘split’

and the objective says

The function should return secret_codes at the end.

Also I’m confused how a specific poem can be called poem and the loop variable in the function can also be called poem. It didn’t like it when I tried to rename the first poem poem1.

Your code so far


# User Editable Region

poem = """Stars and the moon
shine in the sky
white and
until the end of the night"""

poem2 = """The grass is green
here and there
hoping for rain
before it turns yellow"""

poem3 = """There
once
was
a
dragon"""

def pin_extractor(poem):
    secret_codes = []
    for poem in [poem, poem2, poem3]:
        secret_code = ""
        lines = poem.split("\n")
        for line_index, line in enumerate(lines):
            words = line.split()
            if len(words) > line_index:
                secret_code += str(len(words[line_index]))
            else:
                secret_code += "0"
        secret_codes.append(secret_code)
    return secret_codes

print(pin_extractor([poem, poem2, poem3]))

# User Editable Region


Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36

Challenge Information:

Build a Pin Extractor - Step 19

Yes, using the same variable name in multiple places can be confusing. Depending of their scope and order in which they are defined, it might be okay, but it’s easy to overlook something.

With the above code:

    for poem in [poem, poem2, poem3]:

When it’s run, the second part will be evaluated first - [poem, poem2, poem3]. poem2 and poem3 are not yet defined in the function, so they will be looked for in the global scope. However the poem is already defined, as the parameter, so that value will be taken.

So that line can be roughly considered as:

#    for poem in [poem, actual_poem2, actual_poem3]:

Keep in mind, in reality there’s no name changing. I’m doing it to explicitly differentiate naming.

Since pin_extractor is called with list having actual poems:

pin_extractor([poem, poem2, poem3])

# pin_extractor([actual_poem, actual_poem2, actual_poem3])

Therefore when executing the loop would roughly look like this:

    for poem in [[actual_poem, actual_poem2, actual_poem3], actual_poem2, actual_poem3]:

Each item from the outer list is then assigned to the poem variable, which is scoped in the function - it does not affect the global variable, but it will affect poem function parameter. After that point, the poem inside of the function will no longer point to the list which was passed to the function.

All this means for the first iteration, poem will point point to the list with actual poems, what in the end causes the exception.


You might want to reset the step, as there are some changes in the code to the parts that shouldn’t be changed. In this step no changes inside of the function are expected.

1 Like

the argument of the function is the value the function is called it, please restore the other places that had poems to poems (loop, function definition…)

1 Like