# 1. Annotate the following python expressions with the specific types of each literal, as well as the overall return value: # i = 3 # f = 3.0 # c = 3+3j # b = b'abcdefg' # s = 'abcdefg' # s = "abcdefg" i = 3 f = 3.0 c = 3+3j b = b'abcdefg' s1 = 'abcdefg' s2 = "abcdefg" def check_the_datatype(): print() print('This is the answer for Q1:') print() variable_names = ['i', 'f', 'c', 'b', 's1', 's2'] data_list = [i, f, c, b, s1, s2] for variable, data in zip(variable_names, data_list): print("The type of this assigned value {} = {} is: {}".format(variable, data, type(data).__name__)) # 2. For each of the types string, bytestring, integer, floating point, and imaginary literals, # construct a 5x5 table showing what happens when the character "0" or number 0 is compared to each other type from tabulate import tabulate from termcolor import colored from tabulate import tabulate from termcolor import colored def tablesQ2(): print() print('-' * 20) print() print('This is the answer for Q2:') print() types = ["String", "Byte String", "Integer", "Floating Point", "Imaginary"] literals = ['"0"', 'b"0"', '0', '0.0', '0j'] table_data = [] for type_ in types: row = [type_] for literal in literals: if type_ == "String": result = literal == '"0"' elif type_ == "Byte String": result = literal.encode() == b"0" elif type_ == "Integer": try: result = int(literal) == 0 except ValueError: result = False elif type_ == "Floating Point": try: result = float(literal) == 0.0 except ValueError: result = False elif type_ == "Imaginary": result = literal.replace('j', 'j0') == "0j" color = 'green' if result else 'red' colored_result = colored(result, color) row.append(colored_result) table_data.append(row) table = tabulate(table_data, headers=["Type"] + literals, tablefmt="pipe") print(table) # 3. Now do the same thing for the + and == operators for each pair of types in two other 5x5 tables. def tablesQ3(): print() print('-' * 20) print() print('This is the answer for Q3:') print() operators = ["+", "=="] types = ["str", "bytes", "int", "float", "complex"] literals = ['"0"', 'b"0"', '0', '0.0', '0+0j'] for operator in operators: print(f"Table for {operator} Operator:") table_data = [] for type_ in types: row = [type_] for literal in literals: try: result = eval(f"{literal} {operator} {type_}({literal})") color = 'green' except TypeError: result = False color = 'red' colored_result = colored(result, color) row.append(colored_result) table_data.append(row) table = tabulate(table_data, headers=["Type"] + literals, tablefmt="pipe") print(table) print() # Write a small program that uses the AST module to open the lexer/parser example, and dumps the resulting AST. # See if there are any arguments to the parse method which make the output easier to read. # By default, ast.dump() prints the AST in a compact format. # However, there are two optional arguments that can enhance the readability: # indent: Specifies the number of spaces to use for indentation. Setting it to a positive integer (e.g., 4) indents each level of the AST by that amount. # annotate_fields: When set to True, adds field names as comments to the output, making it easier to identify each part of the AST. import ast def dump_ast(filename): with open(filename, 'r') as file: source_code = file.read() try: tree = ast.parse(source_code) ast_dump = ast.dump(tree, indent=4, annotate_fields=True) print(ast_dump) except SyntaxError as e: print(f"Syntax error in {filename}: {e}") if __name__ == "__main__": check_the_datatype() tablesQ2() tablesQ3() print()