Reputation: 732
I have a school assignment, and therefore we're required to use PyCharm and follow the PEP8 and Google standards regarding Python3. While my code works perfectly, PyCharm claims the index of rows[0] is of an unexpected value.
def create_matrix():
"""
Function made to create a matrix of who wins or who loses based on the number of figures in a game.
Keep in mind the order of the figures tuple. first element wins over second element, last element wins over
first element. an element also wins against the element two steps before it, in the case of five elements.
i haven't researched what relationships exist in higher dimensions, but there will always be an equal amount of
elements who beat you, as elements you beat. the missing element will be a draw.
"""
figures = ("Scissors", "Paper", "Rock", "Lizard", "Spock") # caution with order of elements
number_of_figures = len(figures) # expected to be an odd number
half_set = number_of_figures // 2 # half_set = int((n-1)/2)
win_and_lose = [+1, -1] # negative: row (player_b), positive: column (player_a), zero: draw
rows = [[None]*number_of_figures]*number_of_figures # uses same size in memory as a "full" set
rows[0] = [0] + win_and_lose*half_set # [0, -1, +1, -1, +1...]
for row in range(1, number_of_figures):
rows[row] = rotate(rows[row-1], 1)
# for row in range(0, len(rows)):
# print(rows[row])
return figures, rows
I have tested changing the specific line which is giving me a lint warning to
rows[0][0], rows[0][1], rows[0][2], rows[0][3], rows[0][4] = [0] + win_and_lose*half_set # [0, -1, +1, -1, +1...]
and the code works without any lint warning. The problem I have is that I want the tuple to be expandable in size. I know I can do this with a for loop along the lines of
for column in range(0, number_of_figures):
if column == 0:
rows[0][column] = 0
elif column % 2 == 0:
rows[0][column] = +1
elif column % 2 == 1:
rows[0][column] = -1
else:
raise Exception("Unexpected column value")
but I have some issues with this:
1) It isn't readable at all for someone who wants to look at the code.
2) When I try to print the list now, it has set all rows to [0, -1, +1, +1, -1], and not only the first element, as I expect it to do. This doesn't cause any runtime errors, but it's not what I want.
My questions is how I can write this piece code in a pythonic and easy to read manner, without breaking any Python standard.
Bonus question: I want to minify the amount of memory usage of my code, and I've seen through __sizeof__() that if rows contains five elements with value None, it uses 80 bytes of memory. Same size is used if I have five elements with value [None, None, None, None, None]. The size remains unchanged once I set some values to the matrix. Any tips regarding this? I've set up the rotate() function so that I can rotate the list n positions at a time, so I could skip to any given row having the first row defined.
Upvotes: 0
Views: 853
Reputation: 1225
Assuming the comment by DYZ above isn't existent in the first solution, you can use type hinting to help the linter understand the type of rows. In my code this eliminates the linter warning.
rows = [[None]*number_of_figures]*number_of_figures # type: list #uses same size in memory as a "full" set
This syntax is also available for python 3:
rows:list = [[None]*number_of_figures]*number_of_figures
Upvotes: 0
Reputation: 54163
PyCharm is complaining because you initialize rows
as a list of list of None
s, then re-assign it to be a list of list of int
s. Regardless it's a linter warning you are safe to ignore, since dynamic typing is something Python is supposed to do (if you want static typing, go write in a static language).
You could fix it by simply initializing as:
rows = [[0 for _ in range(number_of_figures)] for _ in range(number_of_figures)]
# this is identical to `[[0] * number_of_figures] * number_of_figures` except it
# avoids the duplication of references issue you were experiencing that DYZ
# pointed out in the comments above.
Upvotes: 2