f-string and multiprocessing.Manager dict and list

83 Views Asked by At

I am writing this question, because it does not seem like what I am experiencing should be the desired behavior:

The following code is pretty much lifted from the 3.9.16 documentation on multiprocessing.Manager

from multiprocessing import Process, Manager

def f(d, l):
    d[1] = '1'
    d['2'] = 2
    d[0.25] = None
    l.reverse()

def multi_foo():
    with Manager() as manager:
        d = manager.dict()
        l = manager.list(range(10))
        jobs = []
        for _ in range(1):
            p = Process(target=f, args=(d, l))
            jobs.append(p)
            p.start()
        for _j in jobs:
            _j.join()

        print(f"{d=}")
        print(d)
        print(f"{l=}")
        print(l)
        ell = l[:]
        print(f"{ell=}")

if __name__ == '__main__':
    multi_foo()

This is the output that running the above code yields:

d=<DictProxy object, typeid 'dict' at 0x100cf2550>
{1: '1', '2': 2, 0.25: None}
l=<ListProxy object, typeid 'list' at 0x100f82790>
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
ell=[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

It seems to me that the 3rd line should be more like the 5th line. So it does not feel like the f-string outputs on lines 1 and 3 should be expected.

I am looking for an explanation for why I should expect what I get in the 1st and 3rd line of the output.

1

There are 1 best solutions below

3
chepner On

f'{...=}' uses the value's __repr__ method, not its __str__ method, to print the value. From the documentation:

By default, the '=' causes the repr() of the expression to be provided, unless there is a format specified.

In the case of DictProxy and ListProxy objects, __str__ and __repr__ return very different strings. For list objects, list.__str__ is not even defined, and so object.__str__ is used (which just calls an object's __repr__ method).

Consider:

class A:
    def __str__(self):
        return "string"
    def __repr__(self):
        return "repr"

a = A()
print(a)  # outputs string, as print calls str() on each argument
assert f'{a}' == "string"  # uses a.__str__()
assert f'{a=}' == "a=repr"  # uses a.__repr__()
assert f'{a=!s}' == "a=string"  # !s forces use of __str__