Cleanest way to create instances of class dynamically - python

In caluclations.py I have one class called PowerPlant() with
def __init__(self, parameter1, parameter2, parameter3, ...)
and some functions belonging to the class e.g. calculate_supply(self, variable1, variable2).
I'd like to apply the calculations from calculations.py to some power plants stored in a csv file. So far i use the following way...
In simulation.py I read the data from the csv with pd.read_csv()
plant_data = pd.read_csv('plants.csv', sep = ';', index_col = False, encoding = 'latin')
Then i create a list of lists with
# Create list of lists from plant_data DataFrame
list_of_plants = [list(row) for row in plant_data.values]
Afterwards I create an instance of the Class PowerPlant with
## Outer loop: Iterate over all plants
for row in range(len(list_of_plants)):
ElectricityOut = []
Gains = []
...
# Initialise an instance of the plant
MyPowerPlant = PowerPlant(parameter1 = list_of_plants[row][0],
parameter2 = list_of_plants[row][1],
parameter3 = list_of_plants[row][2],
...)
# call some methods from calculations.py
...
Any ideas and suggetions how i could do this in a better and more professional way?
Maybe create a object for each plant?

You can iterate over a list like so, no need for range(len())
for row in list_of_plants:
ElectricityOut = []
Gains = []
...
# Initialise an instance of the plant
MyPowerPlant = PowerPlant(parameter1 = row[0],
parameter2 = row[0],
parameter3 = row[0],
...)

I'm not happy with accessing the list items with [item] e.g.
list_of_plants[row][0]
As far as i know there is no possibility to access lists via names (use dictionaries for that), but whats with namedTuples?
Is it possible to create instances of a class from namedTuples? If so i would change the list to a namedTuple...
Any suggestions?

Related

Get a dictionary from a class?

I want to:
Take a list of lists
Make a frequency table in a dictionary
Do things with the resulting dictionary
The class works, the code works, the frequency table is correct.
I want to get a class that returns a dictionary, but I actually get a class that returns a class type.
I can see that it has the right content in there, but I just can't get it out.
Can someone show me how to turn the output of the class to a dictionary type?
I am working with HN post data. Columns, a few thousand rows.
freq_pph = {}
freq_cph = {}
freq_uph = {}
# Creates a binned frequency table:
# - key is bin_minutes (size of bin in minutes).
# - value is freq_value which sums/counts the number of things in that column.
class BinFreq:
def __init__(self, dataset, bin_minutes, freq_value, dict_name):
self.dataset = dataset
self.bin_minutes = bin_minutes
self.freq_value = freq_value
self.dict_name = dict_name
def make_table(self):
# Sets bin size
# Counts how of posts in that timedelta
if (self.bin_minutes == 60) and (self.freq_value == "None"):
for post in self.dataset:
hour_dt = post[-1]
hour_str = hour_dt.strftime("%H")
if hour_str in self.dict_name:
self.dict_name[hour_str] += 1
else:
self.dict_name[hour_str] = 1
# Sets bins size
# Sums the values of a given index/column
if (self.bin_minutes == 60) and (self.freq_value != "None"):
for post in self.dataset:
hour_dt = post[-1]
hour_str = hour_dt.strftime("%H")
if hour_str in self.dict_name:
self.dict_name[hour_str] += int(row[self.freq_value])
else:
self.dict_name[hour_str] = int(row[self.freq_value])
Instantiate:
pph = BinFreq(ask_posts, 60, "None", freq_pph)
pph.make_table()
How can pph be turned into a real dictionary?
If you want the make_table function to return a dictionary, then you have to add a return statement at the end of it, for example: return self.dict_name.
If you then want to use it outside of the class, you have to assign it to a variable, so in the second snipped do: my_dict = pph.make_table().
Classes can't return things – functions in classes could. However, the function in your class doesn't; it just modifies self.dict_name (which is a misnomer; it's really just a reference to a dict, not a name (which one might imagine is a string)), which the caller then reads (or should, anyway).
In addition, there seems to be a bug; the second if block (which is never reached anyway) refers to row, an undefined name.
Anyway, your class doesn't need to be a class at all, and is easiest implemented with the built-in collections.Counter() class:
from collections import Counter
def bin_by_hour(dataset, value_key=None):
counter = Counter()
for post in dataset:
hour = post[-1].hour # assuming it's a `datetime` object
if value_key: # count using `post[value_key]`
counter[hour] += post[value_key]
else: # just count
counter[hour] += 1
return dict(counter.items()) # make the Counter a regular dict
freq_pph = bin_by_hour(ask_posts)
freq_cph = bin_by_hour(ask_posts, value_key="num_comments") # or whatever

How to create objects for a class automatically?

Is there any way to auto create objects in python
class A:
pass
a = A()
I would like to automatically create objects for a class.
I need to parse a bunch of xml and I'd like to create an object for one file (entry parse).
Or I need to create some random names?
You don't have to manually assign variable names to the object instances, simply store them in a list when you create them dynamically, like in this example where a list of objects gets created with information from a file:
class A:
def __init__(self, words):
self.words = words
a_objects = []
file = open("testfile.txt")
for line in file:
words = line.split()
a_objects.append(A(words))
If you need to access the objects directly using a key, you will have to use a dictionary instead of a list:
a_objects = {}
You can add key-value pairs to it like this:
words = line.split()
key = words[0]
a_objects[key] = A(words)

Replacing value of variable in list of named tuples

I'm loading data about phone calls into a list of namedtuples called 'records'. Each phone call has information on the length of the call in the variable 'call_duration'. However, some have the variable set to None. I would like to replace None with zero in all of the records, but the following code doesn't seem to work:
for r in records:
if r.call_duration is None:
r = r._replace(call_duration=0)
How can replace the value in the list? I guess the problem is that the new 'r' isn't stored in the list. What would be the best way to capture in the change in the list?
You can replace the old record by using its index in the records list. You can get that index using enumerate():
for i, rec in enumerate(records):
if rec.call_duration is None:
records[i] = rec._replace(call_duration=0)
I suggest you create your own class, it will benefit you in the future as far as object management goes. When you want to create methods later on for a record, you'll be able to easily do so in a class:
class Record:
def __init__(self, number = None, length = None):
self.number = number
self.length = length
def replace(self, **kwargs):
self.__dict__.update(kwargs)
Now you can easily manage your records and replace object attributes as you deem necessary.
for r in records:
if r.length is None:
r.replace(length = 0)

How to add Objects to Class with a loop in Python?

I have a class which looks like this.
class CharInStageList(object):
def __init__(self, charid, charname) :
self.charid = charid
self.charname = charname
into this class I would like to add lists that I have.
I know how to do it the normal way
charOne = CharInStageList(1,'Tim')
charTwo = CharInStageList(2,'Struppi')
that's not a problem what I actually want to do is to add them by using a loop.
I get my data in this form
((1,'Tim'),(4,'Struppi'))
or
((1,'Tim'),(4,'Struppi'),(5,'Nami'),(6,'Luffy'))
the amount of characters I have in the scene is always different.
what I imagined would be a loop like this
charlist = ((1,'Tim'),(4,'Struppi'))
for char in charlist
objname = CharInStageList(char[0],char[1])
something like this
I want the objname to change by itself for every object I add to the class.
How can I get this effect?
I can only use python 2.6.6 for this since it's the maya 2013 python
Edit:
Thx #silas-ray #chepner #theodox I looked into Dicts a bit more and that's pretty much what I need
I use a modified version of #chepner method on it.
object_dict = dict( (y, CharInStageList(x,y)) for x,y in data )
Works like a charm
My testcode looks like this
import maya.cmds as cmds
dicttest = {}
def getdata ():
global dicttest
data = ((1,'Tim'),(4,'Struppi'),(5,'Nami'),(6,'Luffy'))
dicttest = dict( (y,(x,y)) for x,y in data )
getdata()
def printtest() :
for char in dicttest:
print dicttest[char]
printtest()
dicttest.clear()
I would have liked to comment in your answers with code examples but I can't get that to work there.
Objects are not added to a class. Instead, you can create a list of objects which are all instances of the same class, using a list comprehension and taking advantage of the *args syntax:
data = ((1,'Tim'),(4,'Struppi'),(5,'Nami'),(6,'Luffy'))
object_list = [ CharInStageList(*x) for x in data ]
Perhaps you want a dictionary instead:
object_dict = dict( (y, CharInStageList(x,y)) for x,y in data )
(Note that CharInStageList is a poor name for the class, because it's not a list; it encapsulates a single character.)
If you really want CharInStateList to be a collection of characters, try something like this, which is just a thin wrapper around a dictionary:
# Your former CharInStageList
class Character(object):
def __init__(self, charid, charname) :
self.charid = charid
self.charname = char name
class OnStageCharacters(object):
def __init__(self):
self.characters = dict()
# Index on-stage characters using their charid
def add(self, character):
self.characters[character.charid] = character
on_stage = OnStageCharacters()
for id, name in data:
on_stage.add( Character(id, name) )
You can't (at least not without hacking at locals/globals, which is generally not a good idea) change the name you are assigning to dynamically like that. You can, however, insert them in to a dictionary where the keys are your dynamically generated names.
characters = {}
for char_data in char_list:
characters[char_data[1]] = CharInStageList(*char_data)
Though if all your character objects are storing is name and id, it might make more sense to simplify the whole thing and just create mapping dictionaries rather than objects.
character_names_by_id = dict(char_data)
character_ids_by_name = dict((name, id) for id, name in char_data)
#chepner's answer is a great one if you can use the *args form to fill out your class instances.
If you're just asking the most efficient way to do this from a loop, remember you can have iterate over the parts of a tuple together:
data = ((1,'Tim'),(4,'Struppi'),(5,'Nami'),(6,'Luffy'))
class_data = (CharInStageList(id, name) for id, name in data) # "for id, name" will yield two vals
You can also use map, which is very common for doing bulk data translations. A common way to do it is with a lambda so you can write it clearly:
to_char = lambda k: CharInStageList(k[0], k[1])
class_data = map(to_char, data)
If you're doing something as simple as your example, you might not want to bother with your own class. the namedtuple is a great data structure for creating tuples that are easy to work with. It also means you can use positional or named args interchangeably, just as in #chepner's *args version:
StageListChar = namedtuple('CharInStageList', ['id', 'name'])
class_data = map(StageListChar , data)

Python List of classes

I'm trying to design a "Time Tracker" device. I want to be able to define a class line like:
class line():
def __init__(self, course, weekHours, hoursTotal, comment)
self.course = course
self.weekHours = weekHours
self.hoursTotal = hoursTotal
self.comment = comment
Then be able store an array (I guess it's called a list in Python?), of these class objects. So I can print a table produced by all of these lines and save these lines to an output file and then later be able to read that back into this list to view the table or make changes. do I declare table = [class line()]? If so, how do I access each of these objects in the list? I want to be able to differentiate them so I can edit a particular "line" if necessary.
You can store class instances in a list:
lines = []
lines.append(line('Math', '3', '12', 'Hello World!'))
...
To get the i'th line, you'd just do:
lines[i]
Note that there really isn't a good reason to have a class here. a python dict would be more efficient:
lines = []
lines.append({'course': 'Math', ...})

Categories

Resources