How to assign a new material for each object using Python?
Run this with your objects selected:
import bpy

# I separated the creation of nodes to a function so it's easier 
# to edit later if needed
def create_nodes(mat): 
    mat.use_nodes = True
    nodes = mat.node_tree.nodes
    for every_node in nodes: # this removes all existing nodes
        nodes.remove(every_node)

    # creating Principled node and moving it:
    node = nodes.new('ShaderNodeBsdfPrincipled')
    node.location = (-190,100)

    # creating Output node and moving it:
    output_node = nodes.new('ShaderNodeOutputMaterial')
    output_node.location = (40,100)

    # creating the link between the two nodes:
    links = mat.node_tree.links
    link = links.new(node.outputs[0], output_node.inputs[0])

# this saves the currently active object so it can be restored later
active = bpy.context.object 

# let's loop through all selected objects
for every_object in bpy.context.selected_objects: 
    # I only want to work with objects capable of having a material
    if every_object.type in {'MESH','CURVE', 'SURFACE','META', 'FONT'}: 
        if every_object.name not in bpy.data.materials:
        # if there is no material named after the object yet let's make one
            mat = bpy.data.materials.new(every_object.name)
            # and let's create the nodes for it
            create_nodes(mat)
        else:
            # if the material already exists let's just use it
            mat = bpy.data.materials.get(every_object.name)
        if len(every_object.material_slots) == 0: # if there are no material slots
            every_object.data.materials.append(mat)

        # The only thing left now is to assign the material to 
        # all material slots. We probably do not want to loose the info
        # about how the object is divided into separate materials
        for every_slot in every_object.material_slots:
            every_slot.material = mat