The itertools module provides a number of useful functions for manipulating collections of elements through iterators.

The combinations_with_replacement() function returns the combinations of the given iterable with replacement allowed, meaning that the same element can appear multiple times in the same combination. This is in contrast to the combinations() function, which only includes each element from the iterable once.

combinations_with_replacement(iterable, r)
iterable Required. The iterable whose combinations we want.
r Required.  Indicates the length of of each of the combinations to be returned.

The function returns an iterator of successive r-length tuples where each tuple represents a possible r-length combination of the input iterable.

from itertools import combinations_with_replacement


data = ['A', 'B', 'C']

for i in combinations_with_replacement(data, 3):
    print(i)

In the following example we use nested for loops to get  a list of all the possible combinations.

from itertools import combinations_with_replacement


data = ['A', 'B', 'C']

combs = []
for i in  range(len(data)):
    for comb in combinations_with_replacement(data, i + 1):
        combs.append(comb)

print(*combs, sep = '\n')