Machine Learning Rock Paper Scissors Project


In this project, the file shows an example function . The example function is defined with two arguments.

def player(prev_play, opponent_history = ):

Could anyone help me to understand why the function variable “opponent_history” managed to continue tracking the history when it has been called with in the for loop? I would expecting it to be an empty list every time when the function is called. But it almost acted as a global variable which continue append between each for loop!

def player(prev_play, opponent_history=[]):

    guess = "R"
    if len(opponent_history) > 2:
        guess = opponent_history[-2]

    return guess

By adding print('opponent_history:', opponent_history) to the function we can see the list continue to expand between each call.

the first time player(prev_play) is called it uses p?_prev_play as the argument

at the end of every loop in play() in RPS_game, the new result of the last player() call is stored by rewriting p?_prev_play

so the next time player() is called, it takes the previously stored p?_prev_play and appends it to opponent_history in the newly called function

…um, i think that makes sense. let me know if it doesnt

Thank you alkapwn3d . I was thinking the same way as well. However this is not the case!
As you can see the screenshot, this is the 4th call within the for loop, the prev_play just capture the last result, not the history.

ugh…youre right. that makes no sense

From this screenshot you can clear see, the variable has never been destroyed within the for loop!

So, this is a bit counter-intuitive at first, and it took me some reading to figure out what is going on.

In Python, functions are first class objects. What this means is that a function can hold data, just like any other object. The default parameter is a piece of data held by its function, and this data is mutable in certain cases.

Here is a smaller example you can play around with:


Thank you JeremyLT! Really appreciate the example. Do you know why the following example, the s variable doesn’t behave the same way as the default list parameter?

def foo(x, history=[]):

In [27]: foo("c")
['a', 'b', 'c']

In [28]: foo
Out[28]: <function, history=['a', 'b', 'c'])>

In [29]: def bar(x, s=""):
    ...:     s +=x
    ...:     print(s)

In [30]: bar("a")

In [31]: bar("sdfs")

In [32]: bar
Out[32]: <function, s='')>

I think here is the answer!

Python’s default arguments are evaluated once when the function is defined, not each time the function is called (like it is in say, Ruby). This means that if you use a mutable default argument and mutate it, you will and have mutated that object for all future calls to the function as well.


After reading your answer again, it financially make sense now. The list argument is mutable and it evaluated when the function was defined. This is why it didn’t work with the bar func when the argument is string. Thank you!


I learned a lot from your question and your experience working through the problem. IT was a great read.

Thanks for sharing