Python3: Edit dictionary class instance variable - python-3.x

class myClass:
def __init__(self):
self.myClassDict = {}
def ADD_DictPair(self, Value, Key):
#Per ShadowRanger's Solution (Solved)
#self.myClassDict[Value] = Key #Wrong Code
self.myClassDict[Key] = Value #Correct Code
def get_myDict(self):
return self.myClassDict
InstanceOfmyClass = myClass()
InstanceOfmyClass.ADD_DictPair("Value1","Key1")
InstanceOfmyClass.ADD_DictPair("Value2","Key3")
InstanceOfmyClass.ADD_DictPair("Value3","Key3")
print(InstanceOfmyClass.get_myDict()["Key1"])
Desired Output: "Value1"
Error: print(InstanceOfmyClass.get_myDict()["Key1"])
KeyError: 'Key1'
Python3 in Windows // Sublime Text 3
My goal is to interact with the dictionary through it's class method to Add, Call, and Edit values.

def ADD_DictPair(self, Value, Key):
#Per ShadowRanger's Solution (Solved)
#self.myClassDict[Value] = Key #Wrong Code
self.myClassDict[Key] = Value #Correct Code

Related

parameters inside f-string in a dictionary cannot update later

I encounter this issue, when I instantiate an Test object and call the main() method, it prints out
https://bunch/of/urls/with/None/
Although I am expecting to have
https://bunch/of/urls/with/1234/
It cannot update the self.id inside the dictionary f-string later inside the main function.
My expectation is when the dictionary value retrieves given the key, it will update the self.id as well while returning the value.
The reason I am expecting that because I call self.b_func(1234) before I call self.a_func() so it updates the self.id.
However, it is not updating the self.id inside the f-string. This behavior I don't understand why. What concept am I missing? How can I fix this?
class Test():
def __init__(self,id=None):
self.id = id
# Problem happens here
self.a_dict = {'a' : f'https://bunch/of/urls/with/{self.id}/'}
def a_func(self):
val = self.a_dict['a']
print(val)
# It prints
# https://bunch/of/urls/with/None/
# Not
# https://bunch/of/urls/with/1234/
def b_func(self, id):
self.id = id
return True
def main(self):
self.b_func(1234)
self.a_func()
if __name__ == '__main__':
a = Test()
a.main()
f-strings are evaluated right where they are defined. They do not magically update themselves when the values of the expressions inside change afterwards.
You can consider making a_dict a property instead so that its value would be dynamically generated:
class Test():
def __init__(self,id=None):
self.id = id
#property
def a_dict(self):
return {'a' : f'https://bunch/of/urls/with/{self.id}/'}
Demo: https://replit.com/#blhsing/UnnaturalElasticClasslibrary

PYTHON: How to access class object's members if the object is a key in a dictionary

I have the following class:
class car_class(object):
def __init__(self, mileage=11, tyre_size=11):
self.mileage = mileage
self.tyre_size = tyre_size
self.default_val = ''
def __hash__(self):
return hash((self.mileage, self.tyre_size))
def __getitem__(self, default_val):
return self.default_val
def __setitem__(self, default_val, mileage, tyre_size):
self[default_val] = str(mileage) + '_' + str(tyre_size)
def __eq__(self, other):
return (self.mileage, self.tyre_size) == (other.mileage, other.tyre_size)
def __str__(self):
return ('dict_cl: (tyre_size=\'%d\', mileage=\'%d\'' % (int(self.tyre_size), int(self.mileage)))
def __repr__(self):
return ('dict_cl: (tyre_size=\'%d\', mileage=\'%d\'' % (int(self.tyre_size), int(self.mileage)))
def __ne__(self, other):
# Not strictly necessary, but to avoid having both x==y and x!=y
# True at the same time
return not(self == other)
I also have a dictionary which takes the object of this class as the Key against a value as follows-
my_dict = dict()
dict_value_list = list()
mm_dict_cl = car_class()
mm_dict_cl.mileage = 29
mm_dict_cl.tyre_size = 265
dict_value_list.extend(['car_color'])
my_dict.update(mm_dict_cl = dict_value_list)
So the dictionary(my_dict)key has the class object(mm_dict_cl) as key and car_color as a value for this key. The Key is the class object itself having two attributes mileage and tyre_size.
Now when I print the following value of the dictionary I get the value as car_color as expected -
`>>>` print(my_dict[next(iter(my_dict))])
['car_color']
However I'm struggling to find a way to retrieve the properties of the class object.
>>>` print(next(iter(my_dict)))
mm_dict_cl
It prints the class name and the key type if printed as string.
`>>>` print(type(next(iter(my_dict))))
<type 'str'>
Query: How can then I access the object attributes of the key?
I want to check what is the value of tyre_size and mileage for a particular 'car_color' using the key of the dictionary my_dict
Please help, a novice here, trying to learn this language.
-edit: Fixed the extend call to the list for adding 'car_colour' as a list instead of a string as pointed by SorousH Bakhtiary.
The problem here is that you stored the name of the instance of your class as key in your dictionary("it is string"), so you have no control over the instance but because your object is defined in global namespace, you can retrieve it like this : (I simplified your class for the moment)
class car_class:
def __init__(self, mileage=11, tyre_size=11):
self.mileage = mileage
self.tyre_size = tyre_size
self.default_val = ''
my_dict = {}
dict_value_list = []
mm_dict_cl = car_class()
dict_value_list.append('car_color')
print(dict_value_list)
mm_dict_cl.mileage = 'temp1'
mm_dict_cl.tyre_size = 'temp2'
my_dict.update(mm_dict_cl=dict_value_list)
# here :
obj = globals().get(next(iter(my_dict)))
print(obj.mileage) # prints temp1
print(obj.tyre_size) # prints temp2
btw, you should have used append instead of extend method to add 'car_color'

Python Class, Operator Overloading

Recently while getting my hands on with Python Class concepts, I came upon this observation and was not able to understand.
When I try and create instance out of the below class interactively(Python console), I also get the Finding __len__ line in output.
class MyClass(object):
counter = 0
data = 'Class Variable'
def __init__(self):
self.counter += 1
self.value = -1
def __str__(self):
return "Instance {} is the {} instance".format(self.__class__.__name__, self.counter)
def __getattr__(self, item):
print(f'Finding {item}')
return self.__dict__.get(item, f'Attr {item} not available, {self.__dict__}')
def __setattr__(self, key, value):
if key not in self.__dict__:
self.__dict__[key] = value
def __delattr__(self, item):
print(f'Deleting attr: {item}')
if item in self.__dict__:
del self.__dict__[item]
else:
print(f'Cannot find {item} in {self.__dict__}')
if __name__ == '__main__':
inst = MyClass()
print(inst.id)
But running it as a top level module, doesn't add this additional line in output.
Can someone help me understand, why Finding __len__ output would be displayed interactively.
Below is an interactive output,
import WS1
x = WS1.MyClass()
Finding __len__
x.name = 'Yathin'
Finding __len__

Can we skip explicit object creation in Python

When I do not crate object for CP class, the operations are not captured. I am referring to the code below, Can somebody help me understand why we need obj creation in this case
from abc import ABC, abstractmethod
class P(ABC):
def __init__(self):
super().__init__()
self._pre_map = {}
self._pre_order = []
def set_pre(self, tag_value):
index = len(self._pre_map)
print(index)
self._pre_map[index] = tag_value
self._pre_order.append(index)
def execute(self):
pass
class CP(P):
def __init__(self):
super().__init__()
def execute(self):
self.prnt()
def prnt(self):
print (self._pre_map)
print (self._pre_order)
#Working
print("\n++++++++ working")
obj = CP()
obj.set_pre("test string added")
obj.execute()
#Not Working
print("\n+++++++ not working")
CP().set_pre("test string added")
CP().execute()
It produces,
++++++++working
0
{0: 'test string added'}
[0]
+++++++not working
0
{}
[]
When you call the class the second time with CP.execute(), you have created a completely new instance of the CP class. It is not going to have the text string you specified.
If you actually wanted it to print the values like the working one you can make the functions return self after each call in the P class. If you did that you could do something like this.
from abc import ABC, abstractmethod
class P(ABC):
def __init__(self):
super().__init__()
self._pre_map = {}
self._pre_order = []
def set_pre(self, tag_value):
index = len(self._pre_map)
print(index)
self._pre_map[index] = tag_value
self._pre_order.append(index)
##need to return self here
return self
def execute(self):
pass
class CP(P):
def __init__(self):
super().__init__()
def execute(self):
self.prnt()
def prnt(self):
print (self._pre_map)
print (self._pre_order)
#Working
print("\n++++++++ working")
obj = CP()
obj.set_pre("test string added")
obj.execute()
#Not Working
print("\n+++++++ not working: but now working after returning self in the P class")
CP().set_pre("test string added").execute()
++++++++ working
0
{0: 'test string added'}
[0]
+++++++ not working: but now working after returning self in the P class
0
{0: 'test string added'}
[0]
This would print the result you want.
The reason for the difference is the fact that in the first one, you are creating an instance, and using that instance the whole way through, whereas in the second one, you are using two different instances of your class.
The two different instances cannot share their attributes, so you are unable to recall what happened. If you really don't want to use a dedicated variable, change your P class to look like this:
class P(ABC):
...
def set_pre(self, tag_value):
index = len(self._pre_map)
print(index)
self._pre_map[index] = tag_value
self._pre_order.append(index)
return self
...
And use CP().set_pre("test string added").execute()

Python overriding default attribute assignment

for a specific framework i work with, i need to define object attributes as special classes, for example, instead of writing this:
class A:
def __init__(self):
self.some_int = 2
i would need to write:
class A:
def __init__(self):
self.some_int = SpecialIntWrapper(name = "some_int", value = 2)
I would like to somehow override operators/methods so that typing the first code (self.some_int = 2) will call SpecialIntWrapper behind the scenes, with the attribute name and value.
is this possible?
Basically there are two ways - via a #property decorator (preferable unless you want to affect arbitrary names)
class MyClass:
def __init__(self):
self.some_int = 2
# if you know the name of the property define it as a property - a getter
#property
def some_int(self):
return self._some_int
# and a setter
#some_int.setter
def some_int(self, value):
self._some_int = SpecialIntWrapper("some_int", value)
or overloading the __setattr__ magic method
class MyClass:
def __init__(self):
self.some_int = 2
def __setattr__(self, name, value):
# in general if you dont know the names of the properties
# beforehand you can somehow filter them here
if name == "some_int":
super().__setattr__(name, SpecialIntWrapper(name=name, value=value))
else:
# to use the setattr in a default way, just call it via super(Python 3)
super().__setattr__(name, value)
either way the some_int will be initialized to the SpecialIntWrapper instance
>>>print(MyClass().some_int)
<__main__.SpecialIntWrapper object at 0x03721810>
Something like this
class SpecialIntWrapper:
def __init__(self, name, value):
pass
class MyClass:
def __init__(self):
self.some_int = 3
def __setattr__(self, key, value):
if key == 'some_int':
self.__dict__[key] = SpecialIntWrapper(key, value)
else:
self.__dict__[key] = value
print(MyClass().some_int)
# >>> <__main__.SpecialIntWrapper object at 0x1076f1748>

Resources