pythonprintingformatfrozenset

Improve print readability of nested Frozenset


The output of the code example below has terrible readability. The data I'd like to analyse is hidden within numerous frozenset({}) prints.

A = frozenset(["A1", "A2"])
B = frozenset(["B1", "B2"])
C = frozenset(["C1", "C2"])

foo = {A, B, C}

print(foo)
# {frozenset({'B1', 'B2'}), frozenset({'C1', 'C2'}), frozenset({'A1', 'A2'})}

print(*foo)
# frozenset({'B1', 'B2'}) frozenset({'C1', 'C2'}) frozenset({'A1', 'A2'})

Is there an easy way to neglect the printouts of the data collection type? I'm only interested in the grouping of the entries.

A more readable output would be:

({'B1', 'B2'}, {'C1', 'C2'}, {'A1', 'A2'})

TLD
I stumbled upon this issue when trying to find to optimal way to group a large number of items in pairs. The grouping had to comply to a lot of boundary conditions and I need a quick check if the solution found makes sense.

items = {'B1', 'B2', 'C1', 'C2', 'A1', 'A2'}
pairs = get_best_grouping(items) # Outputs a set containing frozensets
print(pairs)

Change the str function of frozenset (or any other native type) is a related question, but seems like a big intervention for this problem.


Solution

  • As you mentioned in the question, writing your own __str__ or __repr__ function would be the propper way to go, if that sounds too much hassle, how about you modify the string after the fact?

    print(str(frozenset({1,2,3})).replace('frozenset',''))

    ({1, 2, 3})

    Assuming of course your set does not contain the word "frozenset".

    But it is really not much more effort to make a new _frozenset class follwing the same logic as above (note the 1 in replace to make sure that we only replace the first occurence of the str '_frozenset'.):

    
    class _frozenset(frozenset):
        def __repr__(self):
            return (frozenset.__repr__(self)).replace('_frozenset','',1)
    
    print(_frozenset([1, 2, '_frozenset']))
    
    

    ({1, 2, '_frozenset'})

    Imho, key is here to simply reuse the definition of __repr__ of the builtin frozenset so we don't have to worry too much about the logic behind how to represent an iterable. Against first intuition, frozenset.__repr__() seems to (I have not looked into it) inspect the name of the class it is in and prepend that so it is not 'frozenset' but '_frozenset' one needs to replace.