0

I have two lists of integers that I plan to modify repeatedly. I'd like to be able to retrieve these from a single object, indexing the lists with -1 and 1 respectively. I tried creating two lists and storing them in a dictionary with keys -1 and 1, but after assigning to one of the lists, changes are not reflected in the dictionary.

foo = [1,2,3]
bar = [4,5,6]

mydict = {-1:foo,1:bar}

foo.append(0)
foo = [2,3,4] 
mydict[-1] # this is [1,2,3,0], but I'd like it to be [2,3,4]

I realize I could just assign to mydict[-1] directly, but I am concerned that this would be inefficient given that a python dict is a hash table, and foo and bar will change size repeatedly (possibly requiring re-hashing -- ??).

Is there a Pythonic way to do this?

kwc
  • 63
  • 1
  • 6
  • 3
    Python *does not have pointers*. Assignment to names merely says "the name on the left hand side now refers to the object on the right hand side". See https://nedbatchelder.com/text/names.html . You can keep references to the object in the dict and then *mutate* that object just fine, so `foo.append(0)` would have worked. Assignment statements will never work the way you want them to here. – juanpa.arrivillaga Feb 28 '19 at 23:55
  • 2
    Anyway, your concerns about hashing are unfounded. The value is not hashed. It's the key that is hashed. And hashing integers is a negligible overhead (or if you are worried about that sort of thing, then Python is not for you, since *ever global name reference is literally a `dict` lookup*. Anyway, all containers essentially store references to objects (what is under the hood a pointer, but again *python itself does not have pointers*). So it doesn't matter of the object changes size, the `dict` won't care and won't even know – juanpa.arrivillaga Feb 28 '19 at 23:57
  • Note, the following betrays a fundamental misunderstanding: "but after assigning to one of the lists..." You don't *assign to a list*. You assign to a *variable/name*. Saying "assigning to a list" doesn't make sense. you are assigning a list object to a name that happens to be referring to another list object. Details that don't matter to the semantics of assignment. – juanpa.arrivillaga Mar 01 '19 at 00:04
  • Thanks for the insight regarding pointers. As for the other two points, you seemed to interpret my question rather uncharitably. – kwc Mar 01 '19 at 03:46
  • 1. I understand the basic concept of a hash table. My concern has to do with how the dictionary handles the scenario where the size of a value changes so it no longer fits in the memory allocated to it in the key -> memory address mapping defined by the hash. If this is not an issue, then I'm not clear on how Python implements the dictionary (or possibly hash tables in general). 2. I chose an unfortunate shorthand by referring to the variable corresponding to the list as a "list." Of course one can't assign to a list. – kwc Mar 01 '19 at 03:53
  • 1
    The underlying hash table *only contains a PyObject pointer*. Again, it neither knows nor cares that the object that it holds a pointer to changes size. It will always require a machine word (8 bytes usually nowadays). That's why it can hold heterogeneous object types to begin with. This is the way *all built-in* containers work in Python. So, a `list` object doens't need to re-size because an object it contains changed size, for example. [Here's](https://stackoverflow.com/questions/327311/how-are-pythons-built-in-dictionaries-implemented) a good question regarding the implementation. – juanpa.arrivillaga Mar 01 '19 at 03:56
  • 1
    [This answer in particular](https://stackoverflow.com/a/44509302/5014455). – juanpa.arrivillaga Mar 01 '19 at 04:00

1 Answers1

2

By assigning a new list to foo with the statement foo = [2,3,4], the foo variable would no longer hold the reference that was given to the -1 key of the mydict dict.

You should use the slice notation instead to update foo with [2,3,4] in-place.

Change:

foo = [2,3,4]

to:

foo[:] = [2,3,4]

Demo: https://repl.it/repls/SaddlebrownGranularBit

blhsing
  • 91,368
  • 6
  • 71
  • 106
  • But there is no point to all this rigamarole just to avoid doing `my_dict[-1] = [2,3,4]` for no good reason – juanpa.arrivillaga Mar 01 '19 at 00:19
  • A typical use case would be to iteratively traverse a nested dict/list data structure for updates, where `mydict` represents the root of the data structure and `foo` is a node of the data structure in the current iteration for updates. But yes, in the very example in the OP's question the use of `foo` is rather pointless, but it could be just a minimal example of what the OP really wants to do, where `foo` could serve a meaningful purpose. – blhsing Mar 01 '19 at 00:47