Asked  7 Months ago    Answers:  5   Viewed   67 times

I am novice to Python and following a tutorial. There is an example of list in the tutorial :

example = list('easyhoss')

Now, In tutorial, example= ['e','a',...,'s']. But in my case I am getting following error:

>>> example = list('easyhoss')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'list' object is not callable

Please tell me where I am wrong. I searched SO this but it is different.



Seems like you've shadowed the builtin name list pointing at a class by the same name pointing at its instance. Here is an example:

>>> example = list('easyhoss')  # here `list` refers to the builtin class
>>> list = list('abc')  # we create a variable `list` referencing an instance of `list`
>>> example = list('easyhoss')  # here `list` refers to the instance
Traceback (most recent call last):
  File "<string>", line 1, in <module>
TypeError: 'list' object is not callable

I believe this is fairly obvious. Python stores object names (functions and classes are objects, too) in namespaces (which are implemented as dictionaries), hence you can rewrite pretty much any name in any scope. It won't show up as an error of some sort. As you might know, Python emphasizes that "special cases aren't special enough to break the rules". And there are two major rules behind the problem you've faced:

  1. Namespaces. Python supports nested namespaces. Theoretically you can endlessly nest namespaces. As I've already mentioned, namespaces are basically dictionaries of names and references to corresponding objects. Any module you create gets its own "global" namespace. In fact it's just a local namespace with respect to that particular module.

  2. Scoping. When you reference a name, the Python runtime looks it up in the local namespace (with respect to the reference) and, if such name does not exist, it repeats the attempt in a higher-level namespace. This process continues until there are no higher namespaces left. In that case you get a NameError. Builtin functions and classes reside in a special high-order namespace __builtins__. If you declare a variable named list in your module's global namespace, the interpreter will never search for that name in a higher-level namespace (that is __builtins__). Similarly, suppose you create a variable var inside a function in your module, and another variable var in the module. Then, if you reference var inside the function, you will never get the global var, because there is a var in the local namespace - the interpreter has no need to search it elsewhere.

Here is a simple illustration.

>>> example = list("abc")  # Works fine
>>> # Creating name "list" in the global namespace of the module
>>> list = list("abc")
>>> example = list("abc")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'list' object is not callable
>>> # Python looks for "list" and finds it in the global namespace,
>>> # but it's not the proper "list".
>>> # Let's remove "list" from the global namespace
>>> del list
>>> # Since there is no "list" in the global namespace of the module,
>>> # Python goes to a higher-level namespace to find the name. 
>>> example = list("abc")  # It works.

So, as you see there is nothing special about Python builtins. And your case is a mere example of universal rules. You'd better use an IDE (e.g. a free version of PyCharm, or Atom with Python plugins) that highlights name shadowing to avoid such errors.

You might as well be wondering what is a "callable", in which case you can read this post. list, being a class, is callable. Calling a class triggers instance construction and initialisation. An instance might as well be callable, but list instances are not. If you are even more puzzled by the distinction between classes and instances, then you might want to read the documentation (quite conveniently, the same page covers namespaces and scoping).

If you want to know more about builtins, please read the answer by Christian Dean.

P.S. When you start an interactive Python session, you create a temporary module.

Tuesday, June 1, 2021
answered 7 Months ago

When you write [x]*3 you get, essentially, the list [x, x, x]. That is, a list with 3 references to the same x. When you then modify this single x it is visible via all three references to it:

x = [1] * 4
l = [x] * 3
print(f"id(x): {id(x)}")
# id(x): 140560897920048
    f"id(l[0]): {id(l[0])}n"
    f"id(l[1]): {id(l[1])}n"
    f"id(l[2]): {id(l[2])}"
# id(l[0]): 140560897920048
# id(l[1]): 140560897920048
# id(l[2]): 140560897920048

x[0] = 42
print(f"x: {x}")
# x: [42, 1, 1, 1]
print(f"l: {l}")
# l: [[42, 1, 1, 1], [42, 1, 1, 1], [42, 1, 1, 1]]

To fix it, you need to make sure that you create a new list at each position. One way to do it is

[[1]*4 for _ in range(3)]

which will reevaluate [1]*4 each time instead of evaluating it once and making 3 references to 1 list.

You might wonder why * can't make independent objects the way the list comprehension does. That's because the multiplication operator * operates on objects, without seeing expressions. When you use * to multiply [[1] * 4] by 3, * only sees the 1-element list [[1] * 4] evaluates to, not the [[1] * 4 expression text. * has no idea how to make copies of that element, no idea how to reevaluate [[1] * 4], and no idea you even want copies, and in general, there might not even be a way to copy the element.

The only option * has is to make new references to the existing sublist instead of trying to make new sublists. Anything else would be inconsistent or require major redesigning of fundamental language design decisions.

In contrast, a list comprehension reevaluates the element expression on every iteration. [[1] * 4 for n in range(3)] reevaluates [1] * 4 every time for the same reason [x**2 for x in range(3)] reevaluates x**2 every time. Every evaluation of [1] * 4 generates a new list, so the list comprehension does what you wanted.

Incidentally, [1] * 4 also doesn't copy the elements of [1], but that doesn't matter, since integers are immutable. You can't do something like 1.value = 2 and turn a 1 into a 2.

Tuesday, June 1, 2021
answered 7 Months ago

The problem is that your endpoint is returning a list. Flask only likes certain return types. The two that are probably the most common are

  • a Response object
  • a str (along with unicode in Python 2.x)

You can also return any callable, such as a function.

If you want to return a list of devices you have a couple of options. You can return the list as a string

def status():
    return ','.join(app.statusOfDevices())

or you if you want to be able to treat each device as a separate value, you can return a JSON response

from flask.json import jsonify

def status():
    return jsonify({'devices': app.statusOfDevices()})
    # an alternative with a complete Response object
    # return flask.Response(jsonify({'devices': app.statusOfDevices()}), mimetype='application/json')
Friday, June 25, 2021
answered 6 Months ago

Just use a containment test:

if redList in totalList:

This returns True for your sample data:

>>> totalList = [ [[0,1], [2,7], [6,3]], [[2,3], [6,1], [4,1]] ]
>>> redList = [ [0,1], [2,7], [6,3] ]
>>> redList in totalList
Thursday, August 5, 2021
answered 5 Months ago

that happens when you redefine list as zip() (which is probably what you did but didn't show us):

>>> list = zip()

now list is a zip object (not the zip class)

>>> list(z)

now you're attempting to call a zip object

Traceback (most recent call last):
  File "<string>", line 301, in runcode
  File "<interactive input>", line 1, in <module>
TypeError: 'zip' object is not callable


del list

(or start from a fresh interpreter)

and everything's back to normal

Monday, August 16, 2021
answered 4 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :