Python: .copy() for dict - python

I changed the following
sales_gross_last_7_days = self.events_sales_gross_last_7_days_incl_today.get(event.pk, {})
sales_gross_last_7_days.pop(timezone.now().date(), 0)
to that one (I added .copy()):
sales_gross_last_7_days = self.events_sales_gross_last_7_days_incl_today.copy().get(event.pk, {})
sales_gross_last_7_days.pop(timezone.now().date(), 0)
Before my change .pop() also affected the original dict. Is that normal behaviour for Python?

Yes, the pop() method removes the key that you pass from the dictionary.
Dictionaries are mutable objects, when you use the pop() method from this object, you are changing his content.

Related

Why does Python return None on list.reverse()?

Was solving an algorithms problem and had to reverse a list.
When done, this is what my code looked like:
def construct_path_using_dict(previous_nodes, end_node):
constructed_path = []
current_node = end_node
while current_node:
constructed_path.append(current_node)
current_node = previous_nodes[current_node]
constructed_path = reverse(constructed_path)
return constructed_path
But, along the way, I tried return constructed_path.reverse() and I realized it wasn't returning a list...
Why was it made this way?
Shouldn't it make sense that I should be able to return a reversed list directly, without first doing list.reverse() or list = reverse(list) ?
What I'm about to write was already said here, but I'll write it anyway because I think it will perhaps add some clarity.
You're asking why the reverse method doesn't return a (reference to the) result, and instead modifies the list in-place. In the official python tutorial, it says this on the matter:
You might have noticed that methods like insert, remove or sort that only modify the list have no return value printed – they return the default None. This is a design principle for all mutable data structures in Python.
In other words (or at least, this is the way I think about it) - python tries to mutate in-place where-ever possible (that is, when dealing with an immutable data structure), and when it mutates in-place, it doesn't also return a reference to the list - because then it would appear that it is returning a new list, when it is really returning the old list.
To be clear, this is only true for object methods, not functions that take a list, for example, because the function has no way of knowing whether or not it can mutate the iterable that was passed in. Are you passing a list or a tuple? The function has no way of knowing, unlike an object method.
list.reverse reverses in place, modifying the list it was called on. Generally, Python methods that operate in place don’t return what they operated on to avoid confusion over whether the returned value is a copy.
You can reverse and return the original list:
constructed_path.reverse()
return constructed_path
Or return a reverse iterator over the original list, which isn’t a list but doesn’t involve creating a second list just as big as the first:
return reversed(constructed_path)
Or return a new list containing the reversed elements of the original list:
return constructed_path[::-1]
# equivalent: return list(reversed(constructed_path))
If you’re not concerned about performance, just pick the option you find most readable.
methods like insert, remove or sort that only modify the list have no return value printed – they return the default None. 1 This is a design principle for all mutable data structures in Python.
PyDocs 5.1
As I understand it, you can see the distinction quickly by comparing the differences returned by modifying a list (mutable) ie using list.reverse() and mutating a list that's an element within a tuple (non-mutable), while calling
id(list)
id(tuple_with_list)
before and after the mutations. Mutable data-type mutations returning none is part allowing them to be changed/expanded/pointed-to-by-multiple references without reallocating memory.

Why there is no popitem for set in python?

Set is unordered and unindexed. Thus, there is no concept of last entered element. Thus, there is no popitem. Is this the reasoning for no popitem in set?
If this is valid reasoning then why dictionary has popitem. dictionary is also unordered like Set.
The corresponding method for sets is pop():
pop()
Remove and return an arbitrary element from the set. Raises KeyError if the set is empty.
Prior to Python 3.7 dicts were unordered and popitem() returned an arbitrary key-value pair. It's only since 3.7 that dicts have been ordered and popitem() defined to return items in LIFO order.
It's called popitem() for dicts because there's already a pop(key) method that removes the item with the specified key.
Python set has pop(), to return an arbitrary item. You don't know which one it turn, though.
There is no method to remove the last-entered element from a set because set is unordered in Python.
If you want an easy way to emulate an ordered set using the standard library you can use collections.OrderedDict instead:
from collections import OrderedDict
s = OrderedDict.fromkeys((2,5,2,6,7))
s.popitem()
From the example above, s.keys() would become:
odict_keys([2, 5, 6])

Understanding setdefault in Python

I am having a hard time understanding whats going on in the my code. So if I have the following line:
d = {}
d.setdefault("key",[]).append("item")
This returns
{'key': ['item']}
So I get what setdefault does. It checks for "key" in the d, a dictionary, and if it doesn't exist it creates it otherwise if it does exist then it returns the value. This returns a copy which can be manipulated and will be updated in the original dictionary. This is a new idea to me. Does this mean that setdefault returns a deep copy, as opposed to a shallow copy? Trying to get wrap my head around this shallow copy vs. deep copy.
No Python operation does implicit copying. Ever. Implicit copying is evil, as far as Python is concerned.
It's literals that create objects. Every time setdefault is called, it evaluates both its arguments. When it evaluates its second argument ([]), a new list is created. It's completely the same as a = [].
If you write el = [] and then try .setdefaulting el into some dict more than one time, you'll see that no copies are being made.
it is equivelent to
item = d.get(key,default)
d[key] = item
d[key].action #in this case append
From the holy docs:
setdefault(key[, default])
If key is in the dictionary, return its
value. If not, insert key with a value of default and return default.
default defaults to None.
The behaviour is easily explicable once you drop the idea that it is a copy. It is not; it is the actual object.

Will dict __getitem__ create a copy of the corresponding object?

I saw following code from here.
d[key] = data # store data at key (overwrites old data if
# using an existing key)
data = d[key] # retrieve a COPY of data at key (raise KeyError if no
# such key)
I don't understand the meaning of doing so. It is said retrieve a COPY of data at key. Seems dict lookup (getitem, or indexing, which one is the proper term?) will make a cope of the object? Right?
You're seeing shelve module documentation.
shelve.open returns a dictionary-like object, not a dictionary. It does not load all key-value pair at once; so comments in the example make sense.
Ordinarily, dict lookup returns the value stored at the key, not a copy of the value. This is important for mutable objects. For instance:
A = dict()
A["a"] = ["Hello", "world"] # Stores a 2-element list in the dict, at key "a"
B = A["a"] # Gets the list that was just stored
B[0] = "Goodbye" # Changes the first element of the list
print(A["a"][0]) # Prints "Goodbye"
In contrast, shelve will return a copy of the value stored with the key, so changing the returned value will not change the shelved value.
You are confusing implementation (i.e. what __getitem__ does for one specific type of object) for a specification (i.e. a prescription for what __getitem__ should do all the time).
__getitem__ just implements syntactic sugar around x[i] - it places no demands on how that is actually done. x[i] could just return the value associated with i in a dictionary. It could return a copy. It could cause way more side effects - i.e. it could cause files to be created/deleted, databases to be connected/disconnected, objects to be created/deleted, etc.
For dict, __getitem__ is defined to return the original object. But you shouldn't assume those semantics will apply for all other objects that implement it - you will be disappointed. When in doubt, you are doing the right thing - check the docs.

Python: Does a dict value pointer store its key?

I'm wondering if there is a built-in way to do this... Take this simple code for example:
D = {'one': objectA(), 'two': objectB(), 'three': objectC()}
object_a = D['one']
I believe object_a is just pointing at the objectA() created on the first line, and knows nothing about the dictionary D, but my question is, does Python store the Key of the dictionary value? Is there a way to get the Key 'one' if all you have is the variable object_a (without looping over the dictionary, of course)?
If not, I can store the value 'one' inside objectA(), but I'm just curious if Python already stores that info.
I think no.
Consider the case of adding a single object to a (large) number of different dictionaries. It would become quite expensive for Python to track that for you, it would cost a lot for a feature not used by most.
The dict mapping is not trivially "reversible" as you describe.
The key must be immutable. It must be immutable so that it can be hashed for lookup and not suffer spontaneous changes.
The value does not have to be immutable, it is not hashed for quick lookup.
You cannot simply go from value back to key without (1) creating an immutable value and (2) populating some other kind of mapping with the "reversed" value -> key mapping.
Is there a way to get the Key 'one' if
all you have is the variable object_a
(without looping over the dictionary,
of course)?
No, Python imposes no such near-useless redundancy on you. If objA is a factory callable:
d = {'zap': objA()}
a = d['zap']
and
b = objA()
just as well as
L = [objA()]
c = L[0]
all result in exactly the same kind of references in a, b and c, to exactly equivalent objects (if that's what objA gives you in the first place), without one bit wasted (neither in said objects nor in any redundant and totally hypothetical auxiliary structure) to record "this is/was a value in list L and/or dict d at these index/key" ((or indices/keys since of cource there could be many)).
Like others have said, there is no built-in way to do this, since it takes up memory and is not usually needed.
If not, I can store the value 'one' inside objectA(), but I'm just curious if Python already stores that info.
Just wanted to add that it should be pretty easy to add a more general solution which does this automatically. For example:
def MakeDictReversible(dict):
for k, v in dict.iteritems():
v.dict_key = k
This function just embeds every object in the dictionary with a member "dict_key", which is the dictionary key used to store the object.
Of course, this code can only work once (i.e., run this on two different dictionaries which share an object, and the object's "dict_key" member will be overwritten by the second dictionary).

Categories