You can actually use a simple for loop, which iterates over the list of arguments, and applies each argument to the object, and reassign the results back to the object
for args in list_of_args:
    obj = obj.fn(*args)
For example, I can use this logic to chain string.replace as follows
obj = 'aaaccc'
list_of_args = [['a','b'], ['c','d']]
for args in list_of_args:
    obj = obj.replace(*args)
print(obj)
And the output will be
bbbddd
Which is the same as doing 'aaabbb'.replace('a','b').replace('c','d')
Or we can also perhaps use a recursive method, which takes in the object, and a counter which serves as an index of the current argument to be applied, and a number of times the function needs to run
#fn is either defined, or imported from outside
def chain_func(obj, counter, max_count):
    #If counter reaches max no of iterations, return
    if counter == max_count:
        return obj
    #Else recursively apply the function
    else:
        return chain_func(obj.fn(list_of_args[counter]), counter+1, max_count)
#To call it twice
list_of_args = [kwargs1, kwargs2]
chain_func(obj, 0, 2)
For example, I can use this logic to chain string.replace as follows
def chain_func(obj, counter, max_count):
    #If counter reaches max no of iterations, return
    if counter == max_count:
        return obj
    #Else recursively apply the function
    else:
        return chain_func(obj.replace(*list_of_args[counter]), counter+1, max_count)
list_of_args = [['a','b'], ['c','d']]
print(chain_func('aaaccc', 0, 2))
And the output will be
bbbddd
     
    
fnlooks like?fnfunction definition isproperty(name, value), which assigns a new property to that vertex in a graph. When the line of code executes, it sends the query to a Gremlin server and updates the specified vertex with a new property-value. (but all this is abstracted away)