pacman042
pacman042

Reputation: 11

Python3 Recursively Calling a Function with Indenting Each New Call and Unexpected Output When Calling the Function Recursively

So I'm making this function to tell me what the type of a variable is along with the variable because of random curiosity and I have it so it indents lines for each item that is contained within a list/dictionary/tuple after telling you it's a list/dictionary/tuple like

list:
    string: words
    integer: 123

and since Python lets you put other lists inside lists and stuff I wanna be able to call the function recursively to make it so inside lists get an additional indent like

list: string: words list: string: more words integer 456 integer 123 but when I call the function recursively it messes that up. I was thinking I might be able to do it using end="stuff" after the strings but haven't figured out a way to get that to work right.

Also when I call the function within a dictionary item using a for loop it weirdly loses the string text I had around it that was supposed to specify if the part being printed there was a key or value and I have no idea why since it's inside a for loop so for every new key-value pair it should do the print statement all over, instead, it only puts the print statement with that follows this for key 'None' : value 'None' where the None doesn't actually belong to anything in the dictionary.

Here's my code Heres my code

def print_type_and_value_for_variable(i):
    if type(i) is str:
        print(f"string: {i}")
    elif type(i) is int:
        print(f"integer: {i}")
    elif type(i) is float:
        print(f"float: {i}")
    elif type(i) is list:
        print("list:")
        for j in i:
            print(f"    {j}")
    elif type(i) is dict:
        print("dictionary:")
        for key, value in i.items():
            # print(f"    key '{key}' : value"
            #       f" '{value}'")
            print(f"    key '{print_type_and_value_for_variable(key)}' : value"
                  f" '{print_type_and_value_for_variable(value)}'")
    elif type(i) is tuple:
        print("tuple:")
        for j in i:
            print(f"    {j}")
    elif type(i) is bool:
        print(f"boolean: {i}")
    elif type(i) is set:
        print("set:")
        for j in i:
            print(f"    {j}")
    elif type(i) is frozenset:
        print("frozen set:")
        for j in i:
            print(f"    {j}")
    elif type(i) is complex:
        print(f"complex: {i}")
    elif type(i) is range:
        print(f"range: {i}")
    elif type(i) is None:
        print(f"none {i}")
    elif type(i) is bytes:
        print(f"bytes: {i}")
    elif type(i) is bytearray:
        print(f"byte array: {i}")
    elif type(i) is memoryview:
        print(f"memory view: {i}")
    else:
        print(f"unknown variable type {type(i)}: {i}")
    # print()


list_of_stuff = [1,
                 2,
                 "words",
                 ["inner",
                  "list"
                  ],
                 {1: "one",
                  2: "two",
                  "3": [3.1, 3.2, 3.3]
                  },
                 "words 2",
                 0.314
                 ]

for item in list_of_stuff:
    print_type_and_value_for_variable(item)

and here's the output I get from it

integer: 1
integer: 2
string: words
list:
    inner
    list
dictionary:
integer: 1
string: one
    key 'None' : value 'None'
integer: 2
string: two
    key 'None' : value 'None'
string: 3
list:
    3.1
    3.2
    3.3
    key 'None' : value 'None'
string: words 2
float: 0.314

Everything under dictionary: and above string: words 2 should be indented one more time. Please help.

Upvotes: 1

Views: 52

Answers (1)

Henry Ecker
Henry Ecker

Reputation: 35636

You can pass an additional parameter to your function called indent which defaults to 0. Each time you recur you can increase this variable by 1. Since a default is provided, you don't need to pass any parameter at all, which allows you to use the function as you have been without modification, or you can specify a starting indent.

Then at the beginning of each call print out the necessary spacing. 0 * '\t' will be the empty string and not affect the indentation of any calls where indent is 0.

def print_type_and_value_for_variable(i, indent=0):
    print(indent * '\t', end='')
    if type(i) is str:
        print(f"string: {i}")
    elif type(i) is int:
        print(f"integer: {i}")
    elif type(i) is float:
        print(f"float: {i}")
    elif type(i) is list:
        print("list:")
        for j in i:
            print_type_and_value_for_variable(j, indent + 1)
    elif type(i) is dict:
        print("dictionary:")
        for key, value in i.items():
            print(f"    key '{print_type_and_value_for_variable(key, indent + 1)}' : value"
                  f" '{print_type_and_value_for_variable(value, indent + 1)}'")
    elif type(i) is tuple:
        print("tuple:")
        for j in i:
            print(f"    {j}")
    elif type(i) is bool:
        print(f"boolean: {i}")
    elif type(i) is set:
        print("set:")
        for j in i:
            print(f"    {j}")
    elif type(i) is frozenset:
        print("frozen set:")
        for j in i:
            print(f"    {j}")
    elif type(i) is complex:
        print(f"complex: {i}")
    elif type(i) is range:
        print(f"range: {i}")
    elif type(i) is None:
        print(f"none {i}")
    elif type(i) is bytes:
        print(f"bytes: {i}")
    elif type(i) is bytearray:
        print(f"byte array: {i}")
    elif type(i) is memoryview:
        print(f"memory view: {i}")
    else:
        print(f"unknown variable type {type(i)}: {i}")


list_of_stuff = [1,
                 2,
                 "words",
                 ["inner",
                  "list"
                  ],
                 {1: "one",
                  2: "two",
                  "3": [3.1, 3.2, 3.3],
                  4: {1: "test", 2: "test2"}
                  },
                 "words 2",
                 0.314
                 ]

for item in list_of_stuff:
    print_type_and_value_for_variable(item)

You might consider grouping your data types by common behaviour.

def print_type_and_value_for_variable(i, indent=0):
    print(indent * '\t', end='')

    t = type(i)
    if t in [str, int, float, bool, complex, bytes, bytearray, memoryview]:
        # Print out type and value
        print(f'{t.__name__}: {i}')
    elif t in [list, tuple, range, set, frozenset, range]:
        # Iterate using for j in i
        print(f'{t.__name__}:')
        for j in i:
            print_type_and_value_for_variable(j, indent + 1)
    elif t is dict:
        # Iterate over items()
        print(f'{t.__name__}:')
        for key, value in i.items():
            print(f"    key '{print_type_and_value_for_variable(key, indent + 1)}' : value"
                  f" '{print_type_and_value_for_variable(value, indent + 1)}'")
    elif i is None:
        print(f'{t.__name__}: {i}')
    else:
        print(f"unknown variable type {type(i)}: {i}")


if __name__ == '__main__':
    list_of_stuff = [1, 2, "words", ["inner", "list"],
                     {1: "one", 2: "two", "3": [3.1, 3.2, 3.3], 4: {1: "test", 2: "test2"}},
                     "words 2", 0.314]

    for item in list_of_stuff:
        print_type_and_value_for_variable(item)

Upvotes: 1

Related Questions