Search code examples
pythonpointersdictionaryreferencemutability

Python: updating reference values


The following works how I believe it should:

dictionary = {'k1': {'a': 'b'}, 'k2': [0, 1]}  
pointer = dictionary['k1']  
print pointer  
>>> {'a': 'b'}  
pointer.update({'a': 'c'})  
print dictionary  
>>> {'k1': {'a': 'c'}, 'k2': [0, 1]} 

The following frustrates me:

pointer = dictionary['k2']
print pointer
>>> [0, 1]
pointer.update([2, 3])
>>> AttributeError: 'list' object has no attribute 'update'  

I am aware list has no update function and understand I could do something like:

pointer[0] = 2

... but I would like a more universal option to update a reference value, so the object still belongs to the dictionary but the value has changed.

The reason for this being I have a nested dictionary that looks something like:

dictionary['key']['key']['key']['key'] 

My question is not aimed around if list has an update function - rather I'm asking if there's a cleaner way to reference and change a value inside of a deeply nested dictionary so it would be nicer on the eyes to store that in a reference value rather than type it all out every time I want to assign something to it.

Thanks!

EDIT: Fixed syntax in first example
EDIT2: Let me be clear: I'm aware list does not have an update function, rather I'm asking about a universal reference value update
EDIT3: simplified question


Solution

  • There is no such thing. References point at objects, not at places inside objects. Period. This is a fundamental part of the Python object model.

    You can, if you are so inclined, write a class that represents such a location:

    class AttributeReference:
        def __init__(self, obj, attr):
            self.obj = obj
            self.attr = attr
    
        def set(self, value):
            setattr(self.obj, self.attr, value)
    
        # add get() and del() and other methods to your heart's content 
    
    
    class ElementReference:
        def __init__(self, obj, key):
            self.obj = obj
            self.key = key
    
        def set(self, value):
            self.obj[self.key] = value
    
        # add get() and del() and other methods to your heart's content
    

    Then you can use such an object instead of a Python reference. However, it's rather unwieldy to use, so the bar for using it is rather higher. On the bright side, the depth of nesting is completely irrelevant. If you want a "reference" to dictionary['k1']['k2']['k3']['k4'], this will do: ElementReference(dictionary['k1']['k2']['k3'], 'k4').