Python: modify variable stored as a value in a dictionary - python

I have the following situation:
>>> a = 1
>>> d = {"a": a}
>>> d
{'a': 1}
>>> d["a"] = 2
>>> d
{'a': 2}
>>> a
1
Of course this is the desired behaviour. However, when I assign 2 to the key "a" of the dictionary d, I would like to know if I can access the variable a instead of its value to modify the value of the variable a directly, accessing it through the dictionary. I.e. my expected last output would be
>>> a
2
Is there any way of doing this?

I suppose you know the idea of mutable and immutable objects. Immutable objects (str, int, float, etc) are passed by value. That's why your desired behaviour can't work. When you do:
a = 1
d["a"] = a
you just pass the value of a variable to your dict key 'a'. d['a'] knows nothing about variable a. They just both point to same primitive value in memory.
I don't know your case and why you need this behaviour, but you can try to use mutable object.
For example:
class A:
def __init__(self, a: int):
self._value = a
#property
def value(self) -> int:
return self._value
#value.setter
def value(self, a: int):
# you can put some additional logic for setting new value
self._value = a
def __int__(self) -> int:
return self._value
And then you can use it in this way:
>>> a = A(1)
>>> d = {"a": a}
>>> d['a'].value
1
>>> d["a"].value = 2
>>> d['a'].value
2
>>> a.value
2
>>> int(a)
2
But it still seems like an overhead and you should rethink whether you really need this behaviour.

When you do
>>> a
, you are calling the value of the variable, a that you set on the first line. You have not changed the value of that variable, hence the output of 1. If you did
>>> d["a"]
, your output would be
>>> 2
. If you want this value to be the variable a's value too, set the value of a to the value of d["a"].
Example-
>>> a = 1
>>> d = {"a": a}
>>> d
{'a': 1}
>>> d["a"] = 2
>>> d
{'a': 2}
>>> a = d["a"]
>>> a
2

Related

Can you replace a dictionary value with one key lookup?

I would like to know whether there is a more efficient way of replacing a particular value in a dictionary. By "more efficient" I mean to avoid looking up the same key twice. I don't expect it would make a big difference, but I find myself doing the following alot:
foo = {'a': 0, 'b': 1}
foo['b'] = bar(foo['b'])
Update
I think the assignment above is "looking up the same key twice" because the following prints "Hashing b" three times.
class LoudKey:
def __init__(self, key):
self.key = key
def __hash__(self):
print(f'Hashing {self.key}')
return self.key.__hash__()
b = LoudKey('b')
foo = {'a': 0, b: 1}
# first "Hashing b"
foo[b] = float(foo[b])
# next two "Hashing b"s
If dict.__getitem__ and dict.__setitem__ are really not duplicating effort somehow, an elaboration on that would also be accepted as an answer.
You can do it by making the dictionary items a mutable type, then mutating it. The simplest is a list with a single element.
>>> b = LoudKey('b')
>>> foo = {'a': [0], b: [1]}
Hashing b
>>> ref = foo[b]
Hashing b
>>> ref[0] = float(ref[0])
>>> foo
{'a': [0], <__main__.LoudKey object at 0x0000000014C66F40>: [1.0]}
You're right that it wouldn't make much difference in practice, though.

Python: How to only pass needed arguments into function from a dictionary?

Assume now I have a well-defined function
def f1(a):
...
and i can not change its definition. Now I want to call it with a argument from a dictionary
D={ 'a':1 , 'b':2}
If I call it like
f1(**D)
there will be a syntax error (because b is not defined in f1). My question is if I can find a smart way to let the function to find the argument it needed only?
You can use inspect.getargspec:
d = {'a': 5, 'b': 6, 'c': 7}
def f(a,b):
return a + b
f(*[d[arg] for arg in inspect.getargspec(f).args])
which gives 11.
Thanks Eugene, getargspec is legacy, instead you should use getfullargspec which has the same usage in this case.
You could get the argument names from the function's code object, then lookup the values for them in the dictionary:
>>> def f(a):
... b = 2
... return a + b
...
>>> D = {'a': 1, 'b': 2, 'c': 3}
>>> nargs = f.__code__.co_argcount
>>> varnames = f.__code__.co_varnames
>>> f(*(D[arg] for arg in varnames[:nargs]))
3
Here is an example of function that got a dictionary and use only the 'b' key :
In [14]: def f1(mydict):
...: return mydict['b']
...:
In [15]: x={'a': 1, 'b':2}
In [16]: f1(x)
Out[16]: 2

Set dictionary value to a variable, not the variable's value

In [1]: a = None
In [2]: b = None
In [3]: A = {'a': a, 'b': b}
In [4]: A
Out[4]: {'a': None, 'b': None}
In [5]: a = 1
In [6]: A
Out[6]: {'a': None, 'b': None}
I am trying to assign a reference to a variable to a dictionary value. I don't want to assign the variable's value to the dictionary's value. Is there someway to do this? Basically, I would want the last line to read:
{'a': 1, 'b': None}
This is the closest you will get with python in my opinion:
class myobj:
def __init__(self):
self.mystr=""
#property
def mystr(self):
return self.mystr
#mystr.setter
def mystr(self, val):
self.mystr=val
def __repr__(self):
return str(self)
def __str__(self):
return self.mystr
a = myobj()
a.mystr = 'a'
names={'a': a}
print names
a.mystr = 'b'
print names
No, because integers are immutable in Python. See Python data model for details. You can only change the dictionary value as in:
A['a'] = 1
When you set a = 1, you are actually creating a new a, which is why it does not reflected to the dictionary. From the documentation:
Types affect almost all aspects of object behavior. Even the importance of object identity is affected in some sense: for immutable types, operations that compute new values may actually return a reference to any existing object with the same type and value, while for mutable objects this is not allowed. E.g., after a = 1; b = 1, a and b may or may not refer to the same object with the value one, depending on the implementation, but after c = []; d = [], c and d are guaranteed to refer to two different, unique, newly created empty lists. (Note that c = d = [] assigns the same object to both c and d.)
Python has no support for references. Even in functions, all method parameters are pass-by-value. You can pass a mutable data structure into a function and modify the data structure, but what you describe is impossible.
Let me explain in a little different way. Hope this will be helpful if you are new to python:
Let me use a list object(mutable) to get different id for different object.
>>> a = [1]
>>> id(a)
4405572168
>>> A = {'a': a}
>>> id(A['a'])
4405572168
>>>
So far we got the same id of the a and A['a'].
Now lets bind another object into the name a
>>>
>>> a = {1: 2}
>>> id(a)
140196067104096
>>> id(A['a'])
4405572168
>>>
In the above eg, i bind a new dict object into a and check the identity of a and A['a'] and now they are different as the name a is bind to a totally new object.
Here is another explanation with reference counting:
>>> a = [1]
>>> sys.getrefcount(a)
2
>>> A = {'a': a}
>>> sys.getrefcount(a)
3
>>>
>>> a = {1: 2}
>>> sys.getrefcount(a)
2
>>>
Can you see the decrease in reference counting after we re-bind to a new name, which means its a totally new object bind to a. So, you wont' see the changes on A.
Variable assignment in other language is Name binding in python.

getting a dictionary of class variables and values

I am working on a method to return all the class variables as keys and values as values of a dictionary , for instance i have:
first.py
class A:
a = 3
b = 5
c = 6
Then in the second.py i should be able to call maybe a method or something that will return a dictionary like this
import first
dict = first.return_class_variables()
dict
then dict will be something like this:
{'a' : 3, 'b' : 5, 'c' : 6}
This is just a scenario to explain the idea, of course i don't expect it to be that easy, but i will love if there are ideas on how to handle this problem just like dict can be used to set a class variables values by passing to it a dictionary with the variable, value combination as key, value.
You need to filter out functions and built-in class attributes.
>>> class A:
... a = 3
... b = 5
... c = 6
...
>>> {key:value for key, value in A.__dict__.items() if not key.startswith('__') and not callable(key)}
{'a': 3, 'c': 6, 'b': 5}
Something like this?
class A(object):
def __init__(self):
self.a = 3
self.b = 5
self.c = 6
def return_class_variables(A):
return(A.__dict__)
if __name__ == "__main__":
a = A()
print(return_class_variables(a))
which gives
{'a': 3, 'c': 6, 'b': 5}
Use a dict comprehension on A.__dict__ and filter out keys that start and end with __:
>>> class A:
a = 3
b = 5
c = 6
...
>>> {k:v for k, v in A.__dict__.items() if not (k.startswith('__')
and k.endswith('__'))}
{'a': 3, 'c': 6, 'b': 5}
Best solution and most pythonic is to use var(class_object) or var(self) (if trying to use inside class).
This although do avoids dictionary pairs where the key is another object and not a default python type.
>>> class TheClass():
>>> def __init__(self):
>>> self.a = 2
>>> self.b = 1
>>> print(vars(self))
>>> class_object= TheClass()
{'a'=2, 'b'=1}
Or outside class
>>> vars(class_object)
{'a': 2, 'b': 1}
You can use __dict__ to get the list of a class variables. For example, if you have a class like this:
class SomeClass:
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
def to_dict(self) -> dict:
return {key: value for key, value in self.__dict__.items()}
You can get the list of variables this way:
some_class = SomeClass(1,2,3)
some_class.to_dict()
And the output will be:
{'a':1, 'b':2, 'c':3}

If in python dictionary, multiple keys are assign to a value then how to get value by using one of the key? [duplicate]

This question already has answers here:
partial match dictionary key(of tuples) in python
(4 answers)
Closed 8 years ago.
d = dict({('a','b'):1})
then how to get value by using either d.get('a') or d.get('b') instead of d.get(('a','b'))
>>> d=dict({('a','b'):1})
>>> d.get('a') // should return value as 1
>>> d.get('b') // should return value as 1
>>> d.get(('a','b'))
1
>>>
You could make a partial match function similar to, but simpler than, the one in this question.
def partial_match(d, part_key):
for key, value in d.items():
if part_key in key:
return value
>>> partial_match(d, 'a')
1
You could create a dedicated data structure derived from dict:
>>> class MyDict(dict):
... def __init__(self, *args):
... if args and type(args[0]) is dict:
... for k, v in args[0].iteritems():
... self.__setitem__(k, v)
... dict.__init__(self, *args)
... def __setitem__(self, keys, val):
... dict.__setitem__(self, keys, val)
... if type(keys) is tuple:
... for k in keys:
... self.__setitem__(k, val)
...
>>> d=MyDict({('a','b'):1})
>>> print d.get('a')
1
>>> print d.get('b')
1
>>> print d.get(('a','b'))
1
>>>
This creates new entries in the dictionary as suggested by #Thrustmaster.
The alternative is to create a 'partial match' function as #Stuart has proposed, that uses less memory as entries are not duplicated, but using more computations as it requires looping through all keys, effectively making the key hashes useless.
As pointed out in the comments, dictionary is simply a key-value mapping. You give it a single key, it will return a uniquely identifiable value against it.
To be able to get the value from the dict using any of the elements in the tuple, then you'd need to use something like the below:
>>> def updateDict(d, obj):
... for key, value in obj.items():
... for k in key:
... d[k] = value
...
>>> res = {}
>>> updateDict(res, {('a','b'):1})
>>> res
{'a': 1, 'b': 1}
>>> res['a']
1
>>> res['b']
1
Note that the code above merely inserts the values multiple time one for each element in the tuple.
You can create the dictionary you want using the original dict:
d1 = dict({('a','b'):1})
# creates {'a':1, 'b':1 }
d2 = {x:v for k, v in d1.items() for x in k}
print d2.get('a') # prints 1
print d2.get('b') # prints 1

Categories