-3

I've created a function (izanamiPressureLevel_1) that makes a random list (pressure) following a certain set of rules. I'm trying to make while loop that iterates until it returns a list of a specified length, but it always loops printing suitable lists indefinitely until I get an error. Can someone explain to me why or offer a solution? I tried to include a minimal example, but I'm not sure if its too long.

This is the error I'm getting.

[Previous line repeated 993 more times]
  File "D:\Folu\Documents\code\PythonScripts\Getting_Started.py", line 14, in izanamiPressureLevel_1
    pressure.append(random.choice(reset))
  File "C:\Users\ridor\AppData\Local\Programs\Python\Python310\lib\random.py", line 378, in choice
    return seq[self._randbelow(len(seq))]
  File "C:\Users\ridor\AppData\Local\Programs\Python\Python310\lib\random.py", line 245, in _randbelow_with_getrandbits
    k = n.bit_length()  # don't use (n-1) here because n can be 1
RecursionError: maximum recursion depth exceeded while calling a Python object

Code:

import random
pressure = []

kuzushi = ["6B","6C(2),214A","6C(2),214B(GIMMICK)","CT"]
sixB = ["63214C","214214C","Throw", "Fuzzy7.j5b","CT","6B","2A"]

def izanamiPressureLevel_1():
    twoA = ["2A,2B,5B,5C,214A","2A,2B,5B,5C,2CC","2A,2B,5B,5C"]
    reset = ["63214C","ZA WAARUDO","2A"]

    pressure = ["2A,2B,5B,5C,2CC"]
    while pressure[-1] == "2A,2B,5B,5C,2CC":
        if pressure[-1] == "2A,2B,5B,5C,2CC":
            pressure.append(random.choice(reset))
        if "2A" in pressure:
            pressure.remove("2A")
            pressure.append(random.choice(twoA))
        if "2A,2B,5B,5C" in pressure:
            pressure.append(random.choice(kuzushi))
        if "6B" in pressure:
            pressure.append("xxRCxx")
            pressure.append(random.choice(sixB))
        while pressure[-1] == "2A":
            if pressure[-1] == "2A,2B,5B,5C,2CC":
                pressure.append(random.choice(reset))
            if "2A" in pressure:
                pressure.remove("2A")
                pressure.append(random.choice(twoA))
            if "2A,2B,5B,5C" in pressure:
                pressure.append(random.choice(kuzushi))
            if "6B" in pressure:
                pressure.append("xxRCxx")
                pressure.append(random.choice(sixB))
    while len(pressure) != 5:
        izanamiPressureLevel_1()
    print (pressure)
izanamiPressureLevel_1()

folufolu
  • 1
  • 1
  • Well, is that last bit the code? Is that *inside* the `izanamiPressureLevel_1` function? So, that's a recursive call. You intend to use recursion, yes? But you intend for the recursion to stop at some point? What is supposed to cause it to stop? – Karl Knechtel Jan 09 '22 at 00:55
  • 1
    Welcome to Stack Overflow. Please read [ask] and https://stackoverflow.com/help/minimal-reproducible-example and show us *enough code that we can actually reproduce the problem*. – Karl Knechtel Jan 09 '22 at 00:56
  • The code shown does not include the call to `random.choice()` referenced in the traceback. In fact is shows no calls to the `random` module at all — so we can only guess at what the problem is… Please provide a runnable [mre]. – martineau Jan 09 '22 at 00:57
  • That is the last bit of code inside the `izanamiPressureLevel_1` function. I intended for the recursion to stop when the list length was equal to 5. Thank you for pointing me toward the How to Ask. I'll make sure to give that a read through @Karl Knechtel – folufolu Jan 09 '22 at 01:24

2 Answers2

0

pressure is never updated because you never assign the return value of izanamiPressureLevel_1() to it.

Assuming izanamiPressureLevel_1() returns a list that can potentially be of length 5, you can change the bottom of the function to be:

while len(pressure) != 5:
    pressure = izanamiPressureLevel_1()

return pressure
BrokenBenchmark
  • 18,126
  • 7
  • 21
  • 33
  • Thank you! It works. It gave me only one list this time along with an error since "object of type 'NoneType' has no len()" Do you think you could explain why is it necessary to update the list `pressure`? I don't really understand the reasoning why it needs to be updated. @BrokenBenchmark – folufolu Jan 09 '22 at 01:19
  • I wrote this before the post was edited. The only way for `len(pressure)` to change would be to reassign to `pressure`, which is why I thought that the update is necessary. – BrokenBenchmark Jan 09 '22 at 01:37
  • To fix the `NoneType` issue, you can make the function return `pressure`. Right now, it returns `None` since you don't have a return statement anywhere in the function. (I've also edited this into the original answer.) – BrokenBenchmark Jan 09 '22 at 01:37
0

To understand and talk about the problem more easily, it will be best to make a helper function first:

def unchecked_pressure_level():
    twoA = ["2A,2B,5B,5C,214A","2A,2B,5B,5C,2CC","2A,2B,5B,5C"]
    reset = ["63214C","ZA WAARUDO","2A"]

    pressure = ["2A,2B,5B,5C,2CC"]
    while pressure[-1] == "2A,2B,5B,5C,2CC":
        if pressure[-1] == "2A,2B,5B,5C,2CC":
            pressure.append(random.choice(reset))
        if "2A" in pressure:
            pressure.remove("2A")
            pressure.append(random.choice(twoA))
        if "2A,2B,5B,5C" in pressure:
            pressure.append(random.choice(kuzushi))
        if "6B" in pressure:
            pressure.append("xxRCxx")
            pressure.append(random.choice(sixB))
        while pressure[-1] == "2A":
            if pressure[-1] == "2A,2B,5B,5C,2CC":
                pressure.append(random.choice(reset))
            if "2A" in pressure:
                pressure.remove("2A")
                pressure.append(random.choice(twoA))
            if "2A,2B,5B,5C" in pressure:
                pressure.append(random.choice(kuzushi))
            if "6B" in pressure:
                pressure.append("xxRCxx")
                pressure.append(random.choice(sixB))
    return pressure

There are two key differences here:

  1. We don't make any attempt to constrain the length of pressure.
  2. We return the pressure result, rather than displaying it. If you want calling code to use that value, then the calling code has to have access to it. return is the way that you get information back from a function call.

Now then, our goal is to implement that constraint. If you want to loop with while until you get an appropriate result, then that is indeed the simplest, most straightforward, and obvious way:

def izanamiPressureLevel_1():
    pressure = unchecked_pressure_level()
    while len(pressure) != 5:
        pressure = unchecked_pressure_level()
    print(pressure)

Notice how we use the return value from our helper function, giving it a local name (which happens to be the same). When we are done, we can just print the result, because nothing else will need information back from this function.

If you want, for some reason, to use recursion, then the important thing to understand is that recursion is not special; it is the same as calling any other function that happens to give you the appropriate result. That means:

  1. If you want to get a result back from the recursive call, it must be returned; simply calling it will not affect the pressure variable for the current call (unless you use mutable data in a very careful way, and also explicitly pass it in as a parameter - please do not try to do this; it is very difficult to get right). Just like if you called any other function - like I said above, return is how you get information back from a function call.

  2. The recursion will already potentially make many calls, because that call will have its own recursive call to make, etc. You need to have a condition that stops the recursion. Just like if you called any other function: one function can call another, which calls another... which can produce a deep call stack. The calls nest until they start returning back to the call sites. If you nested them enough times, you would get the same exception.

  3. Because the recursion is already doing that repetition, you do not want to use a while loop. You want to use a simple if condition. If you have the result you need - if you can figure that out locally - simply return it; otherwise, use recursion to get the correct value to return. Just like if you called any other function: if you don't need to call other functions to get the result, then don't; if you do, then do.

Using the same wrapper function to bundle up the boring part, the recursive structure looks like:

def izanamiPressureLevel_1():
    pressure = unchecked_pressure_level()
    if len(pressure) == 5:
        print(pressure) # we were able to handle it locally.
    else:
        # we need to recurse to get the right result.
        izanamiPressureLevel_1()

(The next step, of course, is to make sure that the actual "raw" calculation works.)

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
  • Thanks a lot. Your post was very informative and I had lots of "aha!" moments reading over it several times to understand. @Karl Knechtel – folufolu Jan 10 '22 at 03:16