I looked at this example and tried to write a class which holds the header information.
From another class, I would call this class and get the dictionary to use.
# -*- coding: utf-8 -*-
import binascii
import codecs
from datetime import datetime
from collections import defaultdict
class HeaderInfo(dict, object):
def __init__(self):
header_dict = defaultdict(list) # This shall hold all the issues in the parsed file
# super(HeaderInfo, self).__init__(file)
self._object = "C:\Sample.log"
file = open(self._object, "rb")
self._dict = {}
byte = file.read(4)
logFileSize = int.from_bytes(byte, "little")
header_dict = self.add('logFileSize', logFileSize)
dict = self.add('logFileSize', logFileSize)
# print((dict))
byte = file.read(20)
hexadecimal = binascii.hexlify(byte)
header_dict = self.add('fileType', codecs.decode(hexadecimal, "hex").decode('ascii'))
dict = self.add('fileType', codecs.decode(hexadecimal, "hex").decode('ascii'))
# print((dict))
byte = file.read(5)
hexadecimal = binascii.hexlify(byte)
header_dict = self.add('fileVersion', codecs.decode(hexadecimal, "hex").decode('ascii'))
dict = self.add('fileVersion', codecs.decode(hexadecimal, "hex").decode('ascii'))
# print((dict))
byte = file.read(10)
hexadecimal = binascii.hexlify(byte)
header_dict = self.add('fileNumber', codecs.decode(hexadecimal, "hex").decode('ascii'))
dict = self.add('fileNumber', codecs.decode(hexadecimal, "hex").decode('ascii'))
def add(self, id, val):
self._dict[id] = val
return self._dict
# print the data
hi = HeaderInfo()
print(hi)
when I tried with print statements,the data is printed, but
hi = HeaderInfo()
, doesn't return anyvalue in "hi".
any idea to return the dict value if HeaderInfo() is called?
hi is a variable pointing to an instance of your class HeaderInfo - it is not the internal dictionary self._dict of your class.
You essentially have a class thats a dict that also has a member that is a dict - you fill the member - not the class itself.
Printing hi won't show whats in your self._dict, unless you overwrite the def __str__(self) and maybe def __repl__(self) methods of your class to customize how your class is printed (by itself/inside lists).
To print the member, add
def Get_Data(self): # or some other name
return self._dict
to your class and use
print(hi.Get_Data())
to view whats inside your members dictionary.
If you want to store stuff in you class itself, change your add method
def add(self, id, val):
self[id] = val # store it inside yourself, not your member
return self # this is questionalbe - as is the whole method
# if you do not want to make it part of your public api
Related
In the code below as you can see I have a test class that inherits from the sqliteDict class. There is also a get_term() method that returns the keys for the dictionary. In the main part, first I make an instance of the class and try to make a new sqliteDict file and assign simple data to it through a context manager block. Until now everything works great but when I try to read the data through the second context manager block from the same file, it seems the data is not saved in the file.
from collections import defaultdict
from sqlitedict import SqliteDict
class test(SqliteDict):
def __init__(self, filename: str = "inverted_index.sqlite", new = False):
super().__init__(filename, flag="n" if new else "c")
self._index = defaultdict(list) if new else self
def get_terms(self):
"""Returns all unique terms in the index."""
return self._index.keys()
if __name__ == "__main__":
with test("test.sqlite",new=True) as d:
d._index["test"]= ["ok"]
print("first attempt: ", [t for t in d.get_terms()])
d.commit()
with test("test.sqlite", new=False) as f:
print("second attempt: ",[t for t in f.get_terms()])
and the result is:
first attempt: ['test']
second attempt: []
Instead of using a dict to store and pass data we are going completely OOPS approach of storing the data as class attributes and call the get methods defined according to need.
In Java i was able to achieve this but having some trouble in Python. Any Solution would be helpful.
import json
class InputModel:
def __init__(self, input_payload):
self.id1 = input_payload["id1"]
self.route = RouteModel(input_payload["route"])
self.id2 = input_payload["id2"]
self.id3 = input_payload["id3"]
self.id4 = input_payload["id4"]
self.id5 = input_payload["id5"]
def get_id1(self):
return self.id1
#similar for other ids
class RouteModel:
def __init__(self, input_payload_route):
self.id6 = input_payload_route["id6"]
self.id7 = input_payload_route["id7"]
def get_id6(self):
return self.id6
#similar for other ids
json_str = '{"id1":"string","route":{"id6":"string","id7":"string"},"id2": "string","id3": "string","id4": "string","id5": "string"}'
json_dict = json.loads(json_str)
im = InputModel(json_dict)
print(im.get_id1())
print(im.get_id6())
not able to access the nested class attributes
Seems like you went for 1 extra indent in your class methods, thus you couldn't reach them.
Also, to reach id6 of RouteModel, you had to refer to 'route' first:
import json
class InputModel:
def __init__(self, input_payload):
self.id1 = input_payload["id1"]
self.route = RouteModel(input_payload["route"])
self.id2 = input_payload["id2"]
self.id3 = input_payload["id3"]
self.id4 = input_payload["id4"]
self.id5 = input_payload["id5"]
def get_id1(self):
return self.id1
#similar for other ids
class RouteModel:
def __init__(self, input_payload_route):
self.id6 = input_payload_route["id6"]
self.id7 = input_payload_route["id7"]
def get_id6(self):
return self.id6
#similar for other ids
json_str = '{"id1":"string","route":{"id6":"string","id7":"string"},"id2": "string","id3": "string","id4": "string","id5": "string"}'
json_dict = json.loads(json_str)
im = InputModel(json_dict)
print(im.get_id1())
print(im.route.get_id6())
Output:
string
string
The problem is that you are only defining get_id* in your local scope, you need to assign it to the instance if you insist on defining it inside the __init__ method.
I minimized your code example to isolate your issue.
class RouteModel:
def __init__(self):
self.id6 = "foo"
def get_id6(self_=self):
return self_.id6
self.get_id6 = get_id6
rm = RouteModel()
print(rm.get_id6())
>>> "foo"
If I understand your question correctly, you want to be able to access the ids directly as attributes, no matter how deep they are nested in the dictionary.
This solution creates the attributes recursively:
import json
class InputModel:
def __init__(self, payload):
self.create_attrs(payload)
def create_attrs(self, d):
for key, value in d.items():
# if the value is a dict, call create_attrs recursively
if isinstance(value, dict):
self.create_attrs(value)
else:
# create an attribute key=value, e.g. id1="string"
setattr(self, key, value)
json_str = '{"id1":"string","route":{"id6":"string","id7":"string"},"id2": "string","id3": "string","id4": "string","id5": "string"}'
json_dict = json.loads(json_str)
im = InputModel(json_dict)
print(im.id1)
print(im.id6)
After going through answers provided, mostly have defined instance attributes and not class attributes.
Correct me if I'm wrong here but I think this is how class attributes are defined right?
import json
class InputModel:
def __init__(self, input_payload):
InputModel.id1 = input_payload["id1"]
InputModel.route = RouteModel(input_payload["route"])
InputModel.id2 = input_payload["id2"]
InputModel.id3 = input_payload["id3"]
InputModel.id4 = input_payload["id4"]
InputModel.id5 = input_payload["id5"]
def get_id1():
return InputModel.id1
#OR
##classmethod
#def get_id1(cls):
# return cls.id1
#similar for other ids
class RouteModel:
def __init__(self, input_payload_route):
RouteModel.id6 = input_payload_route["id6"]
RouteModel.id7 = input_payload_route["id7"]
def get_id6():
return RouteModel.id6
#similar for other ids
json_str = '{"id1":"string","route":{"id6":"string","id7":"string"},"id2": "string","id3": "string","id4": "string","id5": "string"}'
json_dict = json.loads(json_str)
InputModel(json_dict)
print(InputModel.get_id1())
print(InputModel.route.get_id6())
print(RouteModel.get_id6())
I'm need to read different datasets, and all of them have some equal properties (e.g. ID and name) and some unique properties. I know that I can build a different function to read each dataset, but I was wondering if it is possible to build a generic dataset reader if I use something like this
My class:
def MyClass():
def __init(self):
self.default_prop1 = ''
self.default_prop2 = ''
My main file:
def main():
keys = ['default_prop1', 'default_prop2', 'not_default_prop1', 'not_default_prop2' ]
obj_myclass = MyClass()
for i in keys:
#Here
obj_myclass[i] = file.readline()
Is there a way to do something like this?
I'll update your class a little bit:
def Car(): #an example of a car class
def __init(self, props):
self.props = ({}, {})
Now you can iterate over the default properties and the extra ones:
def main()
new_car = Car(({"year": 1998}, {"sports_car_type": "countach"}))
# Now, you can go through the keys in both dictionaries of this new object
print("defaults:")
for key, val in new_car.props[0].items():
print(key, val)
print("~~~~~~~~~\extras:")
for key, val in new_car.props[1].items():
print(key, val)
main()
You can use the vars() mechanism. Fixing two typos in your sample code, to give
class MyClass(): # not def
def __init__(self): # not __init
self.default_prop1 = ''
self.default_prop2 = ''
you can do
>>> mc = MyClass()
>>> vars(mc)
{'default_prop1': '', 'default_prop2': ''}
The object returned by vars() is a proper dict (it returns the __dict__ attribute) and can be updated the way you want.
>>> vars(mc)["new_prop"] = "Fred"
>>> mc.new_prop
'Fred'
Or, if you want to do it in a loop:
>>> for i in (v := vars(mc)):
v[i] = file.readline()
I need to be able to build my buildObject using data extracted from csv file columns
class BuildObject(ObjectID):
def __init__(self, ObjectID, ObjectName, ObjectPrice, ObjectLocation, ObjectColour, ObjectAge, ObjectTag):
self.ObjectID= ObjectID
self.ObjectName= ObjectName
def main():
with open(filename1, "r") as csv1, open(filename2, "r") as csv2:
csvReader1 = csv.DictReader(csv1)
csvReader2 = csv.DictReader(csv2)
csvList = []
for row1, row2 in zip(csvReader1, csvReader2):
csvList.append((row2["ObjectName"], row1["ObjectId"], row1["ObjectPrice"]))
return csvList
Comment: My concern is with this answer that it will work fine provided the csv files have the exact same objectID and in the same order - but will happen if a objectID/Object is missing only in one of the csv files?
Therefore, you can't use zip(csvReader1, csvReader2), you
need random access to a Date_Record using the ObjectID as key/index.
As you mentinioned large amounts of data I would recommend go with SQL.
If you want to do it using Python objects change the following:
def __init__(self):
self._data_store = {}
#data_store.setter
def data_store(self, data):
...
self._data_store[record['ObjectID'] = record
Question: The one topic would be the create a BuildObject for every unique itemID using the data from the csv files and sql query
Checking your code, got the following Error:
class BuildObject(ObjectID):
NameError: name 'ObjectID' is not defined
Why do you inherit from ObjectID?
Where are these class defined?
Consider the following:
class Data_Record():
"""
This class object hold all data for ONE Record
"""
def __init__(self, ObjectID, ObjectName):
self.ObjectID= ObjectID
self.ObjectName= ObjectName
# ... (omitted for brevity)
class Data_Store():
"""
This class object handels Data_Record, reading from csv or sql or anywhere
"""
def __init__(self):
# List to hold all Data_Record objects
self._data_store = []
# Access read only the Data_Record objects
#property
def data_store(self):
return self._data_store
# Add ONE Data_Record from either csv or sql or anywhere
#data_store.setter
def data_store(self, data):
# Condition type(data)
if isinstance(data, dict):
record = Data_Record(**data)
elif isinstance(data, list):
record = Data_Record(**tuple(data))
else:
raise(ValueError, "Data of type({}) are not supported!".format(type(data)))
self._data_store.append(record)
# Method to read from csv
def read_csv(self, fname1, fname2):
# ... (omitted for brevity)
csvReader1, csvReader2 = ([], [])
for csv1, csv2 in zip(csvReader1, csvReader2):
self.data_store = (csv2["ObjectName"], csv1["ObjectId"])
# Method to read from sql
def read_sql(self, sql, query):
result = sql.query(query)
for record in result:
self.data_store = record
Alternative: Without #property/getter/setter.
Here the read(... functions have to know how to add a new Date_Record object to self.data_store. Note: self.data_store is now a public attribute.
If you decide, later on, to store not in memory, you have to rewrite both read(... functions.
class Data_Record():
def __init__(self, data=None):
# Condition type(data)
if isinstance(data, dict):
self.ObjectID = data['ObjectID']
self.ObjectName = data['ObjectName']
elif isinstance(data, list):
# List have to be in predefined order
# e.g ObjectID == Index 0 ObjectName == Index 1 etc.
self.ObjectID = data[0]
self.ObjectName = data[1]
else:
self.ObjectID = None
self.ObjectName = None
class Data_Store():
def __init__(self):
self.data_store = []
def read_csv(self, fname1, fname2):
for csv1, csv2 in zip(csvReader1, csvReader2):
self.data_store.append(Data_Record((csv2["ObjectName"], csv1["ObjectId"])))
def read_sql(self, query):
for record in SQL.query(query):
self.data_store.append(Data_Record(record))
I have this dictionary:
{"id":3,"name":"MySQL","description":"MySQL Database Server - Fedora 21 - medium","image":"","flavor":""}
And I have this object:
class Record():
id = None
name = None
description = None
image = None
flavor = None
How can I assign values from the dictionary to their corresponding class fields?
Take a dict object as the parameter of init function:
class Record(object):
def __init__(self,record_dict):
try:
self.id = record_dict['id']
self.name = record_dict['name']
self.description = record_dict['description']
self.image = record_dict['image']
self.flavor = record_dict['flavor']
except KeyError:
print 'KeyError'
def get_name(self):
return self.name
adict = {"id":3,"name":"MySQL","description":"MySQL Database Server - Fedora 21 - medium","image":"","flavor":""}
one_obj = Record(adict)
print one_obj
print one_obj.get_name()
output:
<__main__.Record object at 0x022E4C90>
MySQL
works for me...
You probably want something like this:
class Record:
def __init__(self, myDict):
self.id = myDict[“id”]
self.name = myDict[“name”]
self.description = myDict[“description”]
self.image = myDict[“image”]
self.flavor = myDict[“flavor”]
And call it:
rec = Record(myDict)
See here to understand the difference between class and instance variables.
Long story short, class variables have a single value for every instance of the class while instance variables values are unique to each instance.
A class variable is defined like this:
class myClass:
Classvar = ‘something’
An instance variable is defined like this:
class myClass:
def __init__():
Self.instanceVar = ‘something else’
This has already been answered here:
Convert Python dict to object?
My favorite method is this one: x.__dict__.update(d)
You can assign them as follows, assuming your dictionary name is input
id = input['id']
name = input['name']
description = input['description']
image = input['image']
flavor = input['flavor']
Try this method in which you grab the attributes of the object:
r = Record()
attributes = [i for i in dir(r) if not i.startswith('_')]
Basically, there are a bunch of background attributes that contain a bunch of underscores. The dir method gets all the attributes and we create a list of the ones that we want. At this point:
# attributes = ['count', 'description', 'flavor', 'id', 'image', 'index', 'name']
So now we use __setattr__ to set the attributes we just grabbed according to the my_dict
for i in attributes:
r.__setattr__(i, my_dict[i])
See the code run online here.
When you create the Record, pass in the dictionary. Then map the key to the value.
Another simple method, see the code here
r = Record()
for k, v in my_dict.items():
exec('r.' + k + '="' + str(v) + '"')