0
def getJoke(idList):
    joke=requests.get("https://official-joke-api.appspot.com/jokes/programming/random")
    if(joke.json()[0]['id'] in idList):
        getJoke(idList)
    else:
        return joke

idList=[]
for i in range(10):
    response=getJoke(idList)
    idList.append(response.json()[0]['id'])
    print('Setup: '+response.json()[0]['setup']+'\nPunchline: '+response.json()[0]['punchline']+'\n')

On the line idList.append(response.json()[0]['id']) I am getting the error 'NoneType' object has no attribute 'json' and I do not know why.

ggorlen
  • 44,755
  • 7
  • 76
  • 106
Sam
  • 9
  • 2
  • If it is a NoneType, chances are your request may have either failed or returned nothing. – Stick-Figure Apr 11 '21 at 13:35
  • 3
    `getJoke(idList)` => `return getJoke(idList)`. This is a rather odd use case for recursion... If you can share your problem/expected output, we can probably offer a better way to do it. – ggorlen Apr 11 '21 at 13:35

1 Answers1

1

It appears you want 10 unique random jokes. Instead of recursion, I'd use a loop (to iterate until you have 10 jokes) and a set (to keep track of duplicate ids):

import requests

def get_joke(
    url="https://official-joke-api.appspot.com/jokes/programming/random"
):
    response = requests.get(url)
    response.raise_for_status()
    return response.json()[0]
    
def get_unique_random_jokes(n):
    ids_used = set()
    jokes = []

    while len(jokes) < n:
        joke = get_joke()

        if joke["id"] not in ids_used:
            ids_used.add(joke["id"])
            jokes.append(joke)

    return jokes       

if __name__ == "__main__":
    jokes = get_unique_random_jokes(n=10)

    for joke in jokes:
        print(f'Setup: {joke["setup"]}\nPunchline: {joke["punchline"]}\n')

If you do use recursion, you'll need to return the response of the recursive call, e.g. return getJoke(idList)

A couple other remarks:

  • I'd cache the result of response.json()[0] in a variable to reduce parsing and make the code prettier.

  • idList is mutated by the getJoke function, so state management is shared between client and the function. This is hard to reason about. Functions should be self-contained and stateless if possible.

  • Recursion can blow the stack, is confusing (the bug here is testament to this) and a poor fit for "try again" semantics. Stick to recursion for stuff like tree processing and divide & conquer algorithms.

  • Although it's a rather premature optimization, keep in mind that in is linear on lists and constant time on sets. Sets are generally the best way to check for membership.

  • For requests, response.raise_for_status() raises a better error to the caller than .json() would. For a not found request, you'd get

    requests.exceptions.HTTPError: 404 Client Error: Not Found for url: 
    https://official-joke-api.appspot.com/jokes/programming/asdasd
    

    instead of the irrelevant

    json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
    
  • Follow PEP-8's recommendations of snake_case instead of camelCase and spacing around operators, foo=bar => foo = bar.

  • When making multiple requests to the same domain, use requests.Session to speed things up (exercise for the reader).

ggorlen
  • 44,755
  • 7
  • 76
  • 106