TypeError: 'str' object is not callable

I am playing with Codewars to further show me just how much I don’t know LOL.

I’m pretty sure I have the basic structure ok, but I’m getting an error that doesn’t make sense when I’m looking the error up on google:

The task:

You probably know the “like” system from Facebook and other pages. People can “like” blog posts, pictures or other items. We want to create the text that should be displayed next to such an item.

Implement the function which takes an array containing the names of people that like an item. It must return the display text as shown in the examples:

[]                                -->  "no one likes this"
["Peter"]                         -->  "Peter likes this"
["Jacob", "Alex"]                 -->  "Jacob and Alex like this"
["Max", "John", "Mark"]           -->  "Max, John and Mark like this"
["Alex", "Jacob", "Mark", "Max"]  -->  "Alex, Jacob and 2 others like this"

My code:

def likes(names):
    if names == []:
        print('no one likes this')
    elif len(names) == 1:
        print((0), 'likes this')
    elif len(names) == 2:
        print((0), 'and' (1),'like this')
    elif len(names) == 3:
        print((0), ',' (1), 'and', (2), 'like this')
    elif len(names) > 3:
        print((0), ',' (1), 'and', len(names)[2:], 'others like this')
    pass

The results:

Test Results:
Basic tests
Log
no one likes this
None should equal ‘no one likes this’
Log
0 likes this
None should equal ‘Peter likes this’
Unexpected exception raised
Traceback (most recent call last):
File “/workspace/default/.venv/lib/python3.10/site-packages/codewars_test/test_framework.py”, line 112, in wrapper
func()
File “/workspace/default/tests.py”, line 8, in _
test.assert_equals(likes([‘Jacob’, ‘Alex’]), ‘Jacob and Alex like this’)
File “/workspace/default/solution.py”, line 7, in likes
print((0), ‘and’ (1),‘like this’)
TypeError: ‘str’ object is not callable

I don’t see a string that could be confused with a variable that might this error.

I’m thinking this is because I’m trying to index a string? Do I have to include the word “index” before the (#)?

You missed a comma. Line 7 should be print((0), ‘and’, (1),‘like this’)

3 Likes

As pointed out above, the specific error is coming from a missing comma, but you have deeper problems. If you’re trying to index a list, that’s not how to do it. For example:

print((0), 'likes this')

would literally print out 0 likes this. The parentheses around the zero aren’t doing anything. If you want the first element (the element at index 0) in names, you need to do

print(names[0], 'likes this')

and so on for your other prints.

2 Likes

Thank you. So basically it was trying to pull a variable that didn’t exist.

I fixed the other missing commas as well. My last concern is this part:

elif len(names) > 3:
        print((0), ',', (1), 'and', len(names)[2:], 'others like this')

I’m trying to get it to input the number of items greater than 2 if there are 3 or more names for the last requirement of “Alex, Jacob and 2 others like this”.

Since this could be any number greater than three people, I’m having that section of the syntax call the len (length) of entries in the (names) variable from a slice of index 2 or greater [2:0].

I’m getting this error: TypeError: ‘int’ object is not subscriptable

Is this because the “len” function is generating an "int"eger which can’t be scriptable?

Edit:

would literally print out 0 likes this .

So the zero is the integer it’s trying to call

Yes. len returns an integer, which you can’t subscript.

You don’t want to slice the integer. You want to slice the list. Similar to how your (0) should be names[0], len(names)[2:] should be names[2:].

Edit: I looked at your example, and if you actually want the number, as in Alex, Jacob and 2 others like this, you don’t need to slice it. You just need len(names) - 2.

But if four names appear in the list, I don’t want it to say 4 names, only the first two names and then add up how many names are in the list from index point [2] and give me that number in the printout.

it isn’t adding the string from the index, it’s just returning the index itself:

Basic tests

Log

no one likes this

None should equal ‘no one likes this’

Log

[0] likes this

None should equal ‘Peter likes this’

Log

[0] and [1] like this

None should equal ‘Jacob and Alex like this’

Log

[0] , [1] and [2] like this

None should equal ‘Max, John and Mark like this’

Log

[0] , [1] and [‘Mark’, ‘Max’] others like this

len(names) - 2 is computing the number you want. If you have a list of length 4, len(thatlist) - 2 is 2; the number of values excluding the first two.

>>> names = ["Alex", "Jacob", "Mark", "Max"]
>>> print(names[0], ',', names[1], 'and', len(names) - 2, 'others like this')
Alex , Jacob and 2 others like this

Also, with that error message, since it is pointing out None, I would highly suggest you double check what the question is asking for. Based on that, I suspect that it wants you to return a string, not print a string.

3 Likes

I was missing the variable to attach the index to “names[0]” so I fixed that but it is printing commas which don’t normally print in the “console” so now I’m trying to find if the rules for “return” are different for comma separators?

Rather than describe it, can you just paste the current code and the output and describe the part that is unexpected?

I actually solved it with everyone’s help. the final touch was using string concantenation instead of the separating commas since it was being returned instead of printed:

def likes(names):
    if names==[]:
        return "no one likes this"
    elif len(names)==1:
        return names[0]+" likes this"
    elif len(names)==2:
        return names[0]+ " and "+names[1]+" like this"
    elif len(names)==3:
        return names[0]+", "+names[1]+" and "+names[2]+" like this"
    elif len(names)>3:
        return names[0]+", "+names[1]+" and "+ str(len(names)-2)+" others like this"
    pass

By Brad Westermann via Discussions on Python.org at 17Aug2022 19:17:

I was missing the variable to attach the index to “names[0]” so I fixed
that but it is printing commas which don’t normally print in the
“console” so now I’m trying to find if the rules for “return” are
different for comma separators?

Please show the code.

print and return are very different.

print is a function, and it writes str(something) to the output,
separated by a space, for each something in its argument list.

return is a control statement, exiting the current function with
whatever value (yes, singular) you supply after return. No value means
return None. It does not do any output.

So: return 1 returns the value 1.

return names returns your names list.

return 2, 3 returns a single 2-tuple with the value (2,3).

On the receiving end, you can save the value returned from a function in
a variable (or use it in an expression). Suppose this function:

def f():
    return 2, 3

You might call it like this:

result = f()

Now result refers to the 2-tuple (2,3). You can see that it is a
tuple by printing it:

result = f()
print("got result", result)

You could extract values from that:

a = result[0]
b = result[1]

and conveniently, Python has an “unpacking assignment” like this:

a, b = result

When there’s more than one variable on the left, Python iterates over
the value on the right to obtain values to store on the left. So a
gets the first value from result (result[0]) and b gets the second
value (result[1]).

And of course the thing on the right can be any expression, so you can
do this directly:

a, b = f()

It looks like returning multiple values, but it just returns a single
thing (the 2-tuple) and then unpacks it to store in a and b. So
the function returns one value, but that value is a data structure.

Cheers,
Cameron Simpson cs@cskk.id.au

You’ve solved the problem at hand, but a few notes:

  1. as nifty as sites like codewars are, you will really be better off learning by writing and running code on your own computer, with a decent text editor (or IDE). It is MUCH easier to see what’s going on that way

Once you have a solution, then paste it into the site to see if it’s correct.

  1. For this problem, it’s a really great idea to look into ways to build up strings – look for “string formatting” and f-strings.

now on to some line by line code review:

def likes(names):
    if names==[]:
        return "no one likes this"

Python has this nifty feature where an empty contianer is false, so this can be:

if not names:
    return "no one likes this"

this has the real benefit of working with any sequence (e.g. a tuple) rather than only a list.

    elif len(names)==1:
        return names[0]+" likes this"
    elif len(names)==2:
        return names[0]+ " and "+names[1]+" like this"

note the similarity on the code here – maybe you can remove some duplication? hint – the string .join() method could be helpful here.

    elif len(names)==3:
        return names[0]+", "+names[1]+" and "+names[2]+" like this"

and here’s more chance for duplication removal – and join() again …

    elif len(names)>3:
        return names[0]+", "+names[1]+" and "+ str(len(names)-2)+" others like this"

the length has alrady been checked for 0, 1, 2, 3 – it has to be greater that three now. so an simple else: will do.

    pass

no reason for a pass here.

NOTE: there is nothing wrong with you code for, say, a quick script to get something done – but if you want to learn Python, it pays to work out how to make these fairly simple problems as clean and “pythonic” as you can.

1 Like
  1. as nifty as sites like codewars are, you will really be better off learning by writing and running code on your own computer, with a decent text editor (or IDE). It is MUCH easier to see what’s going on that way

I have an 8 hour python for beginners video that I’ve been working on for 6 months because I get 30 minutes to work on it every 3 days if I’m lucky with family demands, which means I have to relearn everything I forgot since the last time. And then I fail the quiz because one offhanded comment the instructor made isn’t remembered etc. Having a problem to try and solve helps me research and learn and retain what I’m learning better than my other approach. Codewars also has the cool feature to show you how others have solved the problem which allows me to dive deeper into why theirs worked.

Thank you, that is great to know. I’m always confused about empty parenthesis and empty brackets thinking they mean “whatever would go in here” like variable.join(). I’m a very visual learner so having a flowchart of where things should be placed in the syntax would be a godsend.

I’ve only used to the print command, rather than return so that was a learning experience. With that in mind I assumed each test needed its own section in the code. I read somewhere that you shouldn’t have 15 returns in your code, you only need one but my brain couldn’t figure out how to lay that out yet. :smiley:

I really appreciate the breakdown and the insight, thank you!

By Brad Westermann via Discussions on Python.org at 18Aug2022 17:08:

  1. as nifty as sites like codewars are, you will really be better off
    learning by writing and running code on your own computer, with a
    decent text editor (or IDE). It is MUCH easier to see what’s going on
    that way

I have an 8 hour python for beginners video that I’ve been working on for 6 months because I get 30 minutes to work on it every 3 days if I’m lucky with family demands, which means I have to relearn everything I forgot since the last time.

I feel your pain. I don’t even try to learn from video sources.

[quote=“Christopher H.Barker, PhD, post:13, topic:18278,
username:PythonCHB”]
Python has this nifty feature where an empty contianer is false,
[/quote]

Thank you, that is great to know. I’m always confused about empty parenthesis and empty brackets thinking they mean “whatever would go in here” like variable.join(). I’m a very visual learner so having a flowchart of where things should be placed in the syntax would be a godsend.

Round brackets in Python serve exactly 2 purposes:

  • function calls: function_name(arguments,go,here)
  • grouping: 2 + 3 * 5 == 17 by default arithmetic precedence, while
    (2 + 3) * 5 == 25 if you group 2+3 together using brackets

The square brackets [] denote a list and curly brackets denote a
dict (or a set if you only uses keys). If you want an empty list or
an empty dict you still need the brackets to indicate the list or
dict.

And that is about it.

You need the empty bracket in a function call regardless because
variable is an expression representing that variable, variable.join
is an expression representing the join method of that variable. Only
by adding the brackets is a function actually called:
variable.join(). So you need them even if there are no parameters.

Final note: a tuple (essentially an unmodifiable list) like (2,3) is
often written that way, with brackets, but it is just “grouping” -
either to make it easy to see or to avoid default precedence as in the
arithmetic example above. Technically, the brackets are not part of the
tuple syntax.

So you might see:

coordinates = (2, 3)    # x-coordinate 2, y-coordinate 3

but it can be written:

coordinates = 2, 3    # x-coordinate 2, y-coordinate 3

It is still a 2-tuple.

[…]

I read somewhere that you shouldn’t have 15 returns in your code, you
only need one but my brain couldn’t figure out how to lay that out yet.
:smiley:

Functions like your (if this return A elif that return B elif …) are
the commonest use of multiple returns. But many functions just have
one return, at the bottom:

def f(a):
    if a == 1:
        result = "choice 1"
    elif a == 2:
        result = "choice 2"
    elif a * 5 > 25:
        result = "choice 3"
    else:
        result = "choice 5"
    return result

The reason multiple returns are usually discouraged is that this style
(“early return”, meaning not at the bottom of the function) can make
understanding a function difficult. If the function looks like:

def f(......):
    ... lots
    ... of logic
    ... in here, probably nested
    ... if something: return 3
    ... more logic
    ... more
    return 4

the return in the middle can be hard to see. There’s variations on
this, but basicly it is often recommended to compute some result for the
functions and only return it at the bottom. That way you can see it
clearly, and just have to look at how it is computed.

Cheers,
Cameron Simpson cs@cskk.id.au

1 Like

Yes – these are great features – my suggestion was not that you don’t use codewars, and similar sites (I still like the now ancient “coding bat” site [CodingBat Python]) – rather that you develop your solution on your own computer, and when you think you have it right, then past it into the site to be tested.