Turning list of lists into objects - python

I currently have a list of lists where every list consists of the same kind of information, say:
[['Planet Name', 16, 19, 27, 11], ['Planet Name 2', 12, 22, 11, 42], ....]
and I would like to use a class to make this into a list of objects with the same information, where index 0 is self.name, index 1 is self.distance and so on for every seperate list.
I know that I need to use some kind of a for loop, but have no idea how to go about and do this.
I would really appreciate some help, trying to learn Python and currently classes!

You can use namedtuple like this, to create an object dynamically, with the list of field names. *item in this code is called, unpacking of arguments list
from collections import namedtuple
Planet = namedtuple("Planet", ["name", "distance", "a", "b", "c"])
data = [['Planet Name', 16, 19, 27, 11],['Planet Name 2', 12, 22, 11, 42]]
for item in data:
planet = Planet(*item)
print planet.name, planet.distance, planet
Output
Planet Name 16 Planet(name='Planet Name', distance=16, a=19, b=27, c=11)
Planet Name 2 12 Planet(name='Planet Name 2', distance=12, a=22, b=11, c=42)
Note: namedtuple is a subclass of tuple. So, all the objects created with namedtuple are immutable. It means that, once the object is created, data in the member variables cannot be changed.

Well... To make a class like you want you can do something like this:
class Planet(object):
def __init__(self, *args, **kwargs):
self.name = args[0]
self.distance = args[1]
# ... etc ...
Or something like this:
class Planet(object):
def __init__(self, name, distance, ...):
self.name = name
self.distance = distance
# ... etc ...
And then you call it like this:
p = Planet(*['Planet Name', 16, 19, 27, 11])
In a loop that would be:
l = [['Planet Name', 16, 19, 27, 11], ['Planet Name 2', 12, 22, 11, 42], ....]
planets = [Planet(*data) for data in l]

I'm confused. Have you created the Planet constructor yet?
The code would be something like:
class Planet(object):
def __init__(self, ....):
....
planets = [['Planet Name', 16, 19, 27, 11]['Planet Name 2', 12, 22, 11, 42]....]
planet_list = [Planet(*p) for p in planets]

If you don't want to have a constructor (__init__) which knows about the specifics of your lists, you could do it like this
lists = [['Planet Name', 16, 19, 27, 11], ['Planet Name 2', 12, 22, 11, 42]]
class Planet(object):
pass
for l in lists:
planet = Planet()
setattr(planet, 'name', l[0])
setattr(planet, 'distance', l[1])
setattr(planet, 'size', l[2])
print planet.name, planet.distance, planet.size

Related

Python Binary and Regular String Confusion

I am sure this is a fairly noob question, I have googled, and cannot find a straight answer, but I may be asking the wrong thing... I am trying to make an Out Of Box Configuration script, and all the questions that need answered are stored in a file called pass.ini. When i get user input from getstr (using curses) when it populates my files, they all have b'variable string' as their values. when I try to do a strip command, I get b'riable strin'. when I do a str(variable) it gets the same issue. I saw where b'<variable_string>' can be a sign that it was in bytecode instead of decoded. so I tried a decode command and that failed as 'str object has no attribute 'decode' I have it writing out via ConfigParser, and to a separate file just as a file.write. Right now everything is commented out, I am out of ideas.
Here is the info gathering module:
wrapper(CommitChanges)
curses.echo()
stdscr.addstr( 8, 19, config.CIP , curses.color_pair(3) )
config.CIP = stdscr.getstr( 8, 19, 15)
stdscr.addstr( 9, 19, config.CSM , curses.color_pair(3) )
config.CSM = stdscr.getstr( 9, 19, 15)
stdscr.addstr( 10, 19, config.CGW , curses.color_pair(3) )
config.CGW = stdscr.getstr(10, 19, 15)
stdscr.addstr( 11, 19, config.CD1 , curses.color_pair(3) )
config.CD1 = stdscr.getstr(11, 19, 15)
stdscr.addstr( 12, 19, config.CD2 , curses.color_pair(3) )
config.CD2 = stdscr.getstr(12, 19, 15)
stdscr.addstr( 13, 19, config.CNTP, curses.color_pair(3) )
config.CNTP = stdscr.getstr(13, 19, 15)
stdscr.addstr( 16, 19, config.CHN , curses.color_pair(3) )
config.CHN = stdscr.getstr(16, 19, 15)
stdscr.addstr( 14, 19, config.CID , curses.color_pair(3) )
config.CID = stdscr.getstr(14, 19, 15)
stdscr.addstr( 15, 19, config.CS , curses.color_pair(3) )
config.CS = stdscr.getstr(15, 19, 15)
This is the file output module
def CommitChanges():
MOP = "X"
Config['Array=all']['PTLIP'] = a
Config['Array=all']['PTLSM'] = config.CSM.decode('utf-8')
Config['Array=all']['PTLGW'] = config.CGW.decode('utf-8')
Config['Array=all']['PTLD1'] = config.CD1.decode('utf-8')
Config['Array=all']['PTLD2'] = config.CD2.decode('utf-8')
Config['Array=all']['PTLNTP'] = config.CNTP.decode('utf-8')
Config['Array=all']['PTLIF'] = config.CIFN.decode('utf-8')
Config['Array=all']['PTLHSTNM'] = config.CHN.decode('utf-8')
Config['Array=all']['PTLMOB'] = config.CMOB.decode('utf-8')
Config['Array=all']['customerid'] = config.CID.decode('utf-8')
Config['Array=all']['site'] = config.CS.decode('utf-8')
with open('/opt/passp/pass.ini', 'w') as passini:
Config.write(passini, space_around_delimiters=False)
tpass= open('./pass.b', 'w')
tpass.write("[Array=All]"+ "\n")
tpass.write("ptlip="+ a + "\n")
tpass.write("ptlsm="+ config.CSM.decode('utf-8') +"\n")
tpass.write("ptlgw="+ config.CGW.decode('utf-8') + "\n")
tpass.write("ptld1="+ config.CD1.decode('utf-8') + "\n")
tpass.write("ptld2="+ config.CD2.decode('utf-8') + "\n")
tpass.write("ptlntp="+ config.CNTPdecode('utf-8') + "\n")
tpass.write("ptlif="+ config.CIFNdecode('utf-8') + "\n")
tpass.write("ptldhstnm="+ config.CHNdecode('utf-8') + "\n")
tpass.write("ptlmob="+ config.CMOBdecode('utf-8') + "\n")
tpass.write("customerid="+ config.CIDdecode('utf-8') + "\n")
tpass.write("site="+ config.CSdecode('utf-8') + "\n")
#if Backupfiles():
textchanges()
return
Here is the file save output created by ConfigParser
[Array=all]
ptlip=b'123'
ptlsm=b'321'
ptlgw=b'111'
ptld1=b'222'
ptld2=b'333'
ptlntp=b'444'
ptlif=s19
ptlhstnm=b'555'
ptlmob=
customerid=b'666'
site=b'777'
It perfectly matches when I do a direct write (they were from two different runs, but even with empty data it has the wrapper.
Interesting notice here, 'ptlif' is gathered from finding the interface name, it isn't handled by user input, so it has to be how the config.XXXX variables are stored.
[Array=All]
ptlip=b''
ptlsm=b''
ptlgw=b''
ptld1=b''
ptld2=b''
ptlntp=b''
ptlif=s19
ptldhstnm=b''
ptlmob=
customerid=b''
site=b''
Ok, so I figured out what my problem was.
ncurses getstr returns a binary value, and I was sending it to a string literal variable.
I created a new set of variables, set them up as
cipb = b'foo'
cipb = stdscr.getstr( y, x, len )
config.CIP = cipb.decode()
That fixed it. Hopefully this might help someone else out with a similar issue.

inherit a function from one class to another in python?

I have a class calling two functions and two instance methods.
class MyClass(object):
def df1(self):
raw_data = {'preTestScore': [4, 24, '', 2, 3],'postTestScore': [25, 94, 57, 62, 70]}
df1 = pd.DataFrame(raw_data, columns = ['preTestScore', 'postTestScore'])
return df1
def df2(self):
raw_data = {'preTestScore': [14, 4, 15, 12, 13],'postTestScore': ['', 4, 7, 2, 7]}
df2 = pd.DataFrame(raw_data, columns = ['preTestScore', 'postTestScore'])
return df2
def df1_and_df2(self):
return (self.df1(), self.df2())
And how to inherit those two dfs from another class
class MySecond():
#call df1 and df2 from MyClass
#work on from those two dfs
Inside the class you could do
obj = MyClass()
obj.dfl()
obj.df2()
You could also have MySecond inherit MyClass by doing
class MySecond(MyClass):
#code
Your MyClass.df1 and MyClass.df2 methods are not depending on a MyClass object, meaning that they could be declared as static methods:
class MyClass(object):
#staticmethod
def df1():
raw_data = {'preTestScore': [4, 24, '', 2, 3],'postTestScore': [25, 94, 57, 62, 70]}
df1 = pd.DataFrame(raw_data, columns = ['preTestScore', 'postTestScore'])
return df1
#staticmethod
def df2():
raw_data = {'preTestScore': [14, 4, 15, 12, 13],'postTestScore': ['', 4, 7, 2, 7]}
df2 = pd.DataFrame(raw_data, columns = ['preTestScore', 'postTestScore'])
return df2
From there they could be called directly from the class anywhere without requiring an instantiated object:
MyClass.df1()
MyClass.df2()
EDIT: To inherit from MyClass, you would do the following:
class MySecond(MyClass):
pass
Now instantiating MySecond would inherits MyClass methods. E.g.
instance = MySecond()
instance.df1_and_df2()
More info about inheritance: https://docs.python.org/3/tutorial/classes.html#inheritance

Add a timestamp to data simulator

I am simulating time series data using Python TestData and trying to add a new key value (event_time) that includes a time stamp when the record is generated. The issue is that the field is not incrementing as the script runs, just at first execution. Is there a simple way to do this?
import testdata
import datetime
EVENT_TYPES = ["USER_DISCONNECT", "USER_CONNECTED", "USER_LOGIN", "USER_LOGOUT"]
class EventsFactory(testdata.DictFactory):
event_time = testdata.DateIntervalFactory(datetime.datetime.now(), datetime.timedelta(minutes=0))
start_time = testdata.DateIntervalFactory(datetime.datetime.now(), datetime.timedelta(minutes=12))
end_time = testdata.RelativeToDatetimeField("start_time", datetime.timedelta(minutes=20))
event_code = testdata.RandomSelection(EVENT_TYPES)
for event in EventsFactory().generate(100):
print event
Outputs:
{'start_time': datetime.datetime(2016, 6, 21, 17, 47, 50, 422020), 'event_code': 'USER_CONNECTED', 'event_time': datetime.datetime(2016, 6, 21, 17, 47, 50, 422006), 'end_time': datetime.datetime(2016, 6, 21, 18, 7, 50, 422020)}
{'start_time': datetime.datetime(2016, 6, 21, 17, 59, 50, 422020), 'event_code': 'USER_CONNECTED', 'event_time': datetime.datetime(2016, 6, 21, 17, 47, 50, 422006), 'end_time': datetime.datetime(2016, 6, 21, 18, 19, 50, 422020)}
{'start_time': datetime.datetime(2016, 6, 21, 18, 11, 50, 422020), 'event_code': 'USER_LOGOUT', 'event_time': datetime.datetime(2016, 6, 21, 17, 47, 50, 422006), 'end_time': datetime.datetime(2016, 6, 21, 18, 31, 50, 422020)}
So the timedelta() is how much into the future you want the event to happen. Notice that the timedelta(minutes=12) causes the time between each start_time generated to be 12 minutes from datetime.datetime.now() from the previous iteration of the for-loop (not the execution of the script). Similarly, the end_time is a relative timedelta(minutes=20) to start_time so it will always be 20 minutes in front of start_time. Your event_time is not incrementing because it has no delta (change) value for any time the code is run, and it will always use the datetime.datetime.now() from the time the script is run.
It if is test data, I think you would be looking for something like
import testdata
import datetime
EVENT_TYPES = ["USER_DISCONNECT", "USER_CONNECTED", "USER_LOGIN", "USER_LOGOUT"]
class EventsFactory(testdata.DictFactory):
start_time = testdata.DateIntervalFactory(datetime.datetime.now(), datetime.timedelta(minutes=12))
event_time = testdata.RelativeToDatetimeField("start_time", datetime.timedelta(minutes=10))
end_time = testdata.RelativeToDatetimeField("start_time", datetime.timedelta(minutes=20))
event_code = testdata.RandomSelection(EVENT_TYPES)
for event in EventsFactory().generate(100):
print event
Edit: if it doesn't have to do with the data provided:
So the testdata.DictFactory that you are passing in just creates a dictionary based on the instance variables you create as far as I can see.
You want an event_time instance variable that gets the time for every iteration of the for-loop, to do that it would look like:
import testdata
import datetime
EVENT_TYPES = ["USER_DISCONNECT", "USER_CONNECTED", "USER_LOGIN", "USER_LOGOUT"]
class EventsFactory(testdata.DictFactory):
start_time = testdata.DateIntervalFactory(datetime.datetime.now(), datetime.timedelta(minutes=12))
end_time = testdata.RelativeToDatetimeField("start_time", datetime.timedelta(minutes=20))
event_time = datetime.datetime.now()
event_code = testdata.RandomSelection(EVENT_TYPES)
for event in EventsFactory().generate(100):
print event
If I am understanding what you are wanting correctly, this should achieve it in the output.
Edit 2:
After looking at this again this may not achieve what you are wanting because EventsFactory().generate(100) seems to instantiate all 100 at the same time, and to get a dictionary key of event_time you would have to use the testdata.RelativeToDatetimeField() method to change the time
for event in EventsFactory().generate(10):
event["event_time"] = datetime.datetime.now()
print event

Extract lists from a list in dictionary

Suppose I have this dictionary:
self.dict = {'A':[[10, 20],[23,76,76],[23,655,54]], 'B':[30, 40, 50], 'C':[60, 100]}
Where the key 'A' is a list of lists. I want to get only the first 2 lists of 'A', i.e. [10, 20],[23,76,76]. I tried the idea of looping but it does not work well. :
class T(object):
def __init__(self):
self.dict = {'A':[[10, 20],[23,76,76],[23,655,54]], 'B':[30, 40, 50], 'C':[60, 100]}
def output(self):
for i in self.dict:
for j in self.dict[i]:
first_two_lists = j
print ("%s" % (first_two_lists))
if __name__ == '__main__':
T().output()
How can I get that ?
>>> d = {'A':[[10, 20],[23,76,76],[23,655,54]], 'B':[30, 40, 50], 'C':[60, 100]}
>>> d['A'][:2]
[[10, 20], [23, 76, 76]]
Using list slicing:
>>> d = {'A':[[10, 20],[23,76,76],[23,655,54]], 'B':[30, 40, 50], 'C':[60, 100]}
>>> d.get('A')[:2]
[[10, 20], [23, 76, 76]]

how to store and access datetime(s) in a Python object that needs to be converted into JSON?

I'm working on my first python script, which creates and updates and object with different datetime entries.
I'm setting up the object like this:
# Date conversion
import datetime
import time
# 0:01:00 and 0:00:00 threshold and totalseconds
threshold = time.strptime('00:01:00,000'.split(',')[0],'%H:%M:%S')
tick = datetime.timedelta(hours=threshold.tm_hour,minutes=threshold.tm_min,seconds=threshold.tm_sec).total_seconds()
zero_time = datetime.timedelta(hours=0,minutes=0,seconds=0)
zero_tick = zero_time.total_seconds()
format_date = '%d/%b/%Y:%H:%M:%S'
from datetime import datetime
# Response object
class ResponseObject(object):
def __init__(self, dict):
self.__dict__ = dict
# JSON encoding
from json import JSONEncoder
class MyEncoder(JSONEncoder):
def default(self, o):
return o.__dict__
# > check for JSON response object
try:
obj
except NameError:
obj = ResponseObject({})
...
entry = "14/Nov/2012:09:32:31 +0100"
entry_tz = str.join(' ', entry.split(None)[1:6])
entry_notz = entry.replace(' '+entry_tz,'')
this_time = datetime.strptime(entry_notz, format_date)
# > add machine to object if not there, add init time
if not hasattr(obj, "SOFTINST"):
#line-breaks for readability
setattr(obj, "SOFTINST", {
"init":this_time,
"last":this_time,
"downtime":zero_time,
"totaltime":"",
"percentile":100
})
...
print this_time
print MyEncoder().encode({"hello":"bar"})
print getattr(obj, "SOFTINST")
My last 'print' returns this:
{
'totaltime': datetime.timedelta(0),
'uptime': '',
'last': datetime.datetime(2012, 11, 14, 9, 32, 31),
'init': datetime.datetime(2012, 11, 14, 9, 32, 31),
'percentile': 100,
'downtime': 0
}
Which I cannot convert into JSON...
I don't understand why this:
print this_time #2012-11-14 09:32:31
but inside the object, it's stored as
datetime.datetime(2012, 11, 14, 9, 32, 31)
Question:
How do I store datetime objects in "string format" and still have them easily accessible (and modifyable) in Python?
Thanks!
Use the isoformat method on the datetime object. (see reference: http://docs.python.org/release/2.5.2/lib/datetime-datetime.html)

Categories

Resources