facehugger
facehugger

Reputation: 408

Is it possible to extract a wrapped mapping from MappingProxyType instance?

Is there any cross-platform way to get a reference to some mapping object by having a MappingProxyType instance of that mapping?

>>> class A: pass
>>> A.__dict__ # is there a way to get the wrapped dict of this proxy?
mappingproxy({'__module__': '__main__', '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None})

or

>>> import types
>>> m = {1: 2}
>>> mp = types.MappingProxyType(m) # how to extract m from mp?

Upvotes: 2

Views: 2686

Answers (2)

FamousSnake
FamousSnake

Reputation: 451

There is a way, though it is hacky (see the python bug tracker page):

from types import MappingProxyType

class _get_original_dict:
    def __eq__(self, other: MappingProxyType) -> dict:
        return other
_get_original_dict = _get_original_dict()

# https://bugs.python.org/issue43838
def get_original_dict(proxy: MappingProxyType) -> dict:
    return proxy == _get_original_dict


orig = {1: 2}
proxy = MappingProxyType(orig)
dct = get_original_dict(proxy)
dct[25] = 3

assert dct[25] == 3
assert proxy[25] == 3


T = type("T", (), {})
get_original_dict(T.__dict__)["xxxx"] = 25
assert T.xxxx == 25

Upvotes: 0

byxor
byxor

Reputation: 6359

MappingProxyType is like a dict where the __setattr__ method will always throw an error. By design, you cannot add any new key/value pairs. However, you can obtain a shallow copy of its contents in a normal dictionary.

Assuming you have a mapping proxy...

import types

# Given a normal dictionary...
dictionary = {
  "foo": 10,
  "bar": 20,
}

# That has been wrapped in a mapping proxy...
proxy = types.MappingProxyType(dictionary)

# That cannot accept new key/value pairs...
proxy["baz"] = 30 # Throws TypeError: 'mappingproxy' object does not support item assignment

You can create a shallow copy of its inner dictionary like so:

dictionary_copy = proxy.copy()

print(type(dictionary_copy))         # Prints "<class 'dict'>"
print(dictionary_copy is dictionary) # Prints "False" because it's a copy

dictionary_copy["baz"] = 30          # Doesn't throw any errors

As far as I'm aware, there's no way to extract the original dictionary, or add new key/value pairs without making a copy first.

Upvotes: 4

Related Questions