I have a Device class like so, that I pass data from a websocket to. The data from the websocket isn't always the same, so what I want to do is only update the value of each item in the class, if it is not None.
As an example, the message_data
might be the below on the first message
{
"ssdp": "foo",
"ip": "bar"
}
and then the following on the second:
{
"ssdp": "foo",
}
My code is below:
Script
if self._device is None:
self._device = Device(message_data)
device = self._device.update_from_dict(message_data)
Class
@dataclass
class Info:
ssdp: str
ip: str
@staticmethod
def from_dict(data):
return Info(
ssdp=data.get('SSDP'),
ip=data.get('ip'),
)
class Device:
def __init__(self, data):
self.info = None
self.update_from_dict(data)
def update_from_dict(self, data):
self.info = Info.from_dict(data)
return self
Unfortunately at the moment, this is returning
{'info': Info(ssdp='foo', ip='bar')}
and then
{'info': Info(ssdp='foo', ip=None)}
CodePudding user response:
@dataclass
class Info:
ssdp: str
ip: str
@staticmethod
def update(data, info):
return Info(
ssdp=data.get('SSDP', info.ssdp),
ip=data.get('ip', info.ip),
)
class Device:
def __init__(self, data):
self.info = Info(None, None)
self.update_from_dict(data)
def update_from_dict(self, data):
self.info = Info.update(data, self.info)
This is how I would go about it. I make use of the default value to the dict.get()
and then consequently pass the current info through to the update
method. It is annoying that you have to initialise the info as Info(None, None)
, but someone else might have a better approach :)
CodePudding user response:
You can try with this readapted version of your code:
from dataclasses import dataclass
@dataclass
class Info:
ssdp: str = None
ip: str = None
def from_dict(self, data):
self.ssdp = data['ssdp'] if 'ssdp' in data.keys() else self.ssdp[0],
self.ip = data['ip'] if 'ip' in data.keys() else self.ip[0],
return self
class Device:
def __init__(self, data):
self.info = Info()
self.update_from_dict(data)
def update_from_dict(self, data):
self.info.from_dict(data)
return self
For test purposes :
if __name__ == "__main__":
data = {
"ssdp": "foo",
"ip": "bar"
}
msg_data = {
"ssdp": "test",
}
device = Device(data)
print("before: ", device.info)
device = device.update_from_dict(msg_data)
print("after: ", device.info)
output :
before: Info(ssdp=('foo',), ip=('bar',))
after: Info(ssdp=('test',), ip=('bar',))
CodePudding user response:
Try with these redefined new classes:
from dataclasses import dataclass, fields, replace
from operator import attrgetter
@dataclass
class Info:
ssdp: str = None
ip: str = None
class Device:
def __init__(self, data):
self.info = Info()
self.update_from_dict(data)
def update_from_dict(self, data):
keys = set(map(attrgetter('name'), fields(self.info)))
data = {k: v for k, v in data.items() if k in keys}
self.info = replace(self.info, **data)
return self
This solution is using the replace
function, which basically creates a new object of the same type as the input object, replacing fields with values from changes.