Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Counter in range() not recognized as integer

I am trying to step through a list of lists operating on each element of each list using nested for loops. I am getting a warning from PyCharm that the type of the counter in the second for loop is not certain to be an integer, despite it is derived from a range value. The code executes correctly, by why the warning?

def get_vote_fraction(cl_count, ag_vector):
    v_f_vector = [[0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0, 0]]
    for b in range(0, len(v_f_vector)):
        for c in range(0, len(v_f_vector[b])):
            v_f_vector[b][c] = f"{(ag_vector[b][c] / cl_count): .2F}"
    return v_f_vector


aggregated_vector = [[0, 8, 0, 6], [0, 1, 0, 0, 0, 0, 9, 0], [0, 0, 10, 0], [0, 10, 0, 0, 0]]
class_count = 10
vote_fraction = get_vote_fraction(class_count, aggregated_vector)
print(vote_fraction)

As expected the output is [[' 0.00', ' 0.80', ' 0.00', ' 0.60'], [' 0.00', ' 0.10', ' 0.00', ' 0.00', ' 0.00', ' 0.00', ' 0.90', ' 0.00'], [' 0.00', ' 0.00', ' 1.00', ' 0.00'], [' 0.00', ' 1.00', ' 0.00', ' 0.00', ' 0.00']]

I get a warning that c in v_f_vector[b][c] can be of Unexpected type(s) (int, str) which says c is not sufficiently defined as an integer. I hesitate to raise an issue with PyCharm since I may be missing something simple. Anyone see what I am missing?

like image 460
Pmason Avatar asked Mar 26 '19 20:03

Pmason


People also ask

How do you fix str object Cannot be interpreted as an integer?

The “TypeError: 'str' object cannot be interpreted as an integer” error is raised when you pass a string as an argument into a range() statement. To fix this error, make sure all the values you use in a range() statement are integers.

How do you read a list as an integer in Python?

The Python "TypeError: 'list' object cannot be interpreted as an integer" occurs when we pass a list to a function that expects an integer argument, e.g. range() . To solve the error, either pass the length of the list, e.g. len(my_list) or pass an integer to the function.

How do you check if a number is not between two values in Python?

You can check if a number is present or not present in a Python range() object. To check if given number is in a range, use Python if statement with in keyword as shown below. number in range() expression returns a boolean value: True if number is present in the range(), False if number is not present in the range.


2 Answers

Regarding the PyCharm warning (that the question is all about)

Although the 2nd index (c) is highlighted, making users think it is the problem, it's not about that, at all.

Generally, lists are homogeneous containers, meaning that they contain elements of the same type.
PyCharm evaluated v_f_vector as being a list of lists of ints (and thus v_f_vector[b][c] as an int). Trying to assign a string to it, would kind of break the list homogeneity, hence the warning.
Try assigning dummy values (e.g. 0.01f, (), [], ...) to it, and the warning text will change, like in the image below:

Img0

As a quick (and dirty) workaround, if the lists are going to contain strings, you could do something like:

v_f_vector = [["", "", "", ""], ["", "", "", "", "", "", "", ""], ["", "", "", ""], ["", "", "", "", ""]]

Regarding the code that lead to this

Declaring a list with a certain content, and then coming back and changing that content (based on another (similar structural) list) is counter-intuitive.

Your (end) goal, can be achieved in one line of code (the most Pythonic form), consisting of a list comprehension (check [Python 3.Docs]: List Comprehensions). Since your list nesting level is 2, so will be the comprehension:

>>> aggregated_vector = [[0, 8, 0, 6], [0, 1, 0, 0, 0, 0, 9, 0], [0, 0, 10, 0], [0, 10, 0, 0, 0]]
>>> class_count = 10
>>>
>>> vote_fraction = [[f"{(item1 / class_count): .2F}" for item1 in item0] for item0 in aggregated_vector]
>>> print(vote_fraction)
[[' 0.00', ' 0.80', ' 0.00', ' 0.60'], [' 0.00', ' 0.10', ' 0.00', ' 0.00', ' 0.00', ' 0.00', ' 0.90', ' 0.00'], [' 0.00', ' 0.00', ' 1.00', ' 0.00'], [' 0.00', ' 1.00', ' 0.00', ' 0.00', ' 0.00']]
>>>
>>> # Or, if you REALLY need to have a function
...
>>> def get_vote_fraction(cl_count, ag_vector):
...     return [[f"{(item1 / cl_count): .2F}" for item1 in item0] for item0 in ag_vector]
...
>>>
>>> print(get_vote_fraction(class_count, aggregated_vector))
[[' 0.00', ' 0.80', ' 0.00', ' 0.60'], [' 0.00', ' 0.10', ' 0.00', ' 0.00', ' 0.00', ' 0.00', ' 0.90', ' 0.00'], [' 0.00', ' 0.00', ' 1.00', ' 0.00'], [' 0.00', ' 1.00', ' 0.00', ' 0.00', ' 0.00']]

Note: your code could be adapted as well, but I'd suggest to go with the recommended variant(s).

like image 97
CristiFati Avatar answered Oct 03 '22 22:10

CristiFati


I think that the warning comes from the fact that you are replacing integer values with strings. When I tried to instanciate v_f_vector with '0' instead of 0, PyCharm didn't show any warning:

v_f_vector = [['0', '0', '0', '0'], ['0', '0', '0', '0', '0', '0', '0', '0'], ['0', '0', '0', '0'], ['0', '0', '0', '0', '0']]

However, it may be not the best way to fix the problem. I would suggest such a refactoring of your code:

def get_vote_fraction(cl_count, ag_vector):
    v_f_vector = []
    for b in range(0, len(ag_vector)):
        v_f_vector.append([])
        for c in range(0, len(ag_vector[b])):
            v_f_vector[b].append(f"{(ag_vector[b][c] / cl_count): .2F}")
    return v_f_vector


aggregated_vector = [[0, 8, 0, 6], [0, 1, 0, 0, 0, 0, 9, 0], [0, 0, 10, 0], [0, 10, 0, 0, 0]]
class_count = 10
vote_fraction = get_vote_fraction(class_count, aggregated_vector)
print(vote_fraction)

It will allow you to change aggregated_vector without reflecting these changes to instanciated v_f_vector.

like image 26
sanyassh Avatar answered Oct 03 '22 22:10

sanyassh