Creating several classes in Python dynamically - python

I will appreciate any effort to clarify the following: is there a way in Python to dynamically create one object per class, where several classes are declared? My silly guess can be described as following:
...
suppose we have some data from db
props = dict_cur.fetchall()
classes_names = []
data = []
for i in props:
classes_names.append(i['client_name'].title())
classes = []
data = []
for i in props:
data.append(dict(i))
for i, d in zip(classes_names, data):
classes.append(type(i, (object,), dict(**d)))
print classes
#printing list of classes
objects = []
for obj in classes:
objects.append(obj())
for obj in objects:
print obj.client_name, obj.client_id
This is very naive approach and it never lets inherit from created classes in a regular way, just like this:
class ClientProcess(Someclient): #Someclient is the name of the created class before
def __init__(self):
print "Someclient stuff"
The goal is pretty simple: create the objects of several classes, preferably with the properties that are stored in the tables, but at the same time have class declaration for every client which will have specific method implemented that will very from class to class. The initial script that works well and uses Python version of Factory method is not sufficient because it only can process one class(client) a time (based on command-line argument which is client id).

If I understand you correctly, you can use the following ways to subclass dynamically created classes:
In : classes = []
In : cls_name = 'BaseCls1'
In : classes.append(type(cls_name, (object, ), {'x': 1}))
In : classes[0].x
Out: 1
In : classes[0].__bases__
Out: (object,)
# two ways to create subclass out of BaseCls1
In : class SubCls1(classes[0]):
: x = 2
:
In : SubCls1.x
Out: 2
In : SubCls1.__bases__
Out: (__main__.BaseCls1,)
In : SubCls2 = type('SubCls2', (classes[0],), {'x': 2})
In : SubCls2.x
Out: 2
In : SubCls2.__bases__
Out: (__main__.BaseCls1,)

class GetConfig(object):
def __init__(self, client_id):
self.client_id = client_id
#construct the query here to get the clients data ...where client_id = self.client_id
d = {'logfile': 'some_long_path', 'contact_name': 'some_name'}
class FirstClient(object):
def __init__(self):
client_id = '111111111'
props = GetConfig(client_id)
#print props.d
def check_source(self):
print "Checking FirstClient source"
return "Something"
#print props.d
def check_downl(self):
print "Checking FirstClient downloaded"
class SecondClient(object):
def __init__(self):
client_id = "222222"
props = GetConfig(client_id)
def check_source(self):
print "Checking SecondClient source"
def check_downl(self):
print "Checking SecondClient downloaded"
myfactory = {
"firstclient" : FirstClient,
"secondclient" : SecondClient,
}
for i in myfactory.values():
i().check_source()
i().check_downl()

collections.namedtuple. done.
Edit: to elaborate,
from collections import namedtuple
rows = dict_cur.fetchall()
# creates the class Row which is a tuple, but each position argument
# corresponds to the column name in that position
# Row can be instantiated as a tuple and then its elements can be accessed
# by name class attributes
Row = namedtuple("Row", zip(*dict_cur.description)[0])
objects = [Row(row) for row in rows]
for o in objects:
print o.client_name, ' is ' , o

Related

Serializable Static class variables in Python

Is it possible to have serializable static class variables or methods in python?
As an example suppose, I have the following code snippet:
import pickle
class Sample:
count = 0 # class variable
def __init__(self, a1=0, a2=0):
self.a = a1
self.b = a2
Sample.count += 1
#MAIN
f = open("t1.dat", "wb")
d = dict()
for i in range(10):
s = Sample(i, i*i)
d[i] = s
pickle.dump(d,f)
print "Sample.count = " + str(Sample.count)
f.close()
The output is:
Sample.count = 10
Now, I have another reader program similar to above:
import pickle
class Sample:
count = 0 # class variable
def __init__(self, a1=0, a2=0):
self.a = a1
self.b = a2
Sample.count += 1
#MAIN
f = open("t1.dat", "rb")
d = pickle.load(f)
print "Sample.count = " + str(Sample.count)
The output is:
Sample.count = 0
My question is:
How do I load the class variable from my file? In other words, how do I serialize a class variable? If directly not possible, is there any alternative? Please suggest.
Since class variable cannot be picked, as an alternative, I have used the code snippet in main part when reading from the file as below:
#MAIN
f = open("t1.dat", "rb")
d = pickle.load(f)
Sample.count = len(d.values())
print "Sample.count = " + str(Sample.count)
The output is now:
Sample.count = 10
Is it acceptable solution? Any other alternative?
Quoting the section on "What can be pickled and unpickled?"
Similarly, classes are pickled by named reference, so the same restrictions in the unpickling environment apply. Note that none of the class’s code or data is pickled, so in the following example the class attribute attr is not restored in the unpickling environment:
class Foo:
attr = 'a class attr'
picklestring = pickle.dumps(Foo)
So because attr, or in your case count, is part of the class definition, it never gets pickled. In your 'write' example, you're printing Sample.count which does exist but is not pickled in the first place.
You could store Sample.count in each instance as _count and put Sample.count = self._count. But remember that since your d is a dict, they may unpickle in any order. So essentially this won't work.
You'll need to add __setstate__ to your class customize the way it pickles and put in some flag value (like _count) which you then manipulate (via whatever logic works consistently) in __getstate__. (Edit: doesn't help with the given problem unless you store count in a global variable and access that in getstate and manipulate further each time an object is unpickled.)
Another potential workaround but yuck: Add a variable to your dict d so that it also gets pickled. When you read it back, restore with Sample.count = d['_count']. So before pickle.dump(d,f) when you pickle, do d['_count'] = Sample.count.
Important caveat: This is not actually allowing you to pickle Sample.count since what you're actually pickling (d) is a dictionary of Samples.
Edit: The Sample.count = len(d.values()) which you've put as a workaround is very specific to your use case and not to class attr's in general.

Python: referencing class object list of lists

I am fairly new to python. I have tried to define a class, I then want to create an instance from a file, then refer to specific pieces of it, but cannot seem to. This is Python 3.3.0
Here's the class....
class Teams():
def __init__(self, ID = None, Team = None, R = None, W = None, L = None):
self._items = [ [] for i in range(5) ]
self.Count = 0
def addTeam(self, ID, Team, R=None, W = 0, L = 0):
self._items[0].append(ID)
self._items[1].append(Team)
self._items[2].append(R)
self._items[3].append(W)
self._items[4].append(L)
self.Count += 1
def addTeamsFromFile(self, filename):
inputFile = open(filename, 'r')
for line in inputFile:
words = line.split(',')
self.addTeam(words[0], words[1], words[2], words[3], words[4])
def __len__(self):
return self.Count
Here's the code in Main
startFileName = 'file_test.txt'
filename = startFileName
###########
myTestData = Teams()
myTestData.addTeamsFromFile(startFileName)
sample data in file
100,AAAA,106,5,0
200,BBBB,88,3,2
300,CCCC,45,1,4
400,DDDD,67,3,2
500,EEEE,90,4,1
I think I am good to here (not 100% sure), but now how do I reference this data to see... am i not creating the class correctly? How do I see if one instance is larger than another...
ie, myTestData[2][2] > myTestData[3][2] <----- this is where I get confused, as this doesn't work
Why don't you create a Team class like this :
class Team():
def __init__(self, ID, Team, R=None, W = 0, L = 0)
# set up fields here
Then in Teams
class Teams():
def __init__(self):
self._teams = []
def addTeam (self, ID, Team, R=None, W = 0, L = 0)
team = Team (ID, Team, R=None, W = 0, L = 0)
self._teams.append (team)
Now If i got it right you want to overwrite the > operator's behaviour.
To do that overload __gt__(self, other) [link]
So it will be
class Team ():
# init code from above for Team
def __gt__ (self, otherTeam):
return self.ID > otherTeam.ID # for example
Also be sure to convert those strings to numbers because you compare strings not numbers. Use int function for that.
The immediate problem you're running into is that your code to access the team data doesn't account for your myTestData value being an object rather than a list. You can fix it by doing:
myTestData._items[2][2] > myTestData._items[3][2]
Though, if you plan on doing that much, I'd suggest renaming _items to something that's obviously supposed to be public. You might also want to make the addTeamsFromFile method convert some of the values it reads to integers (rather than leaving them as strings) before passing them to the addTeam method.
An alternative would be to make your Teams class support direct member access. You can do that by creating a method named __getitem__ (and __setitem__ if you want to be able to assign values directly). Something like:
def __getitem__(self, index):
return self._items[index]
#Aleksandar's answer about making a class for the team data items is also a good one. In fact, it might be more useful to have a class for the individual teams than it is to have a class containing several. You could replace the Teams class with a list of Team instances. It depends on what you're going to be doing with it I guess.

Interfering objects (or something less sinister?)

I have created a word object, which consists of just two methods, and takes just two parameters. In spite of this apparent simplicity it is behaving in a way that's beyond my comprehension: if I create two instances of the same object, with the same first argument ("dissembling" in this case) the second instance somehow interferes with the first. Printing the instances reveals that they are indeed separate, so why are the interacting in this way?
# Example tested with Python 2.7.3
from collections import namedtuple
DefinitionTuple = namedtuple("Definition", "word word_id text pos")
class Word(object):
def __init__(self, word, defs=None):
""""""
self.definitions = []
self.word = word
if defs != None:
for each in defs:
try:
each.pos
if each.word.lower() == self.word.lower():
self.definitions.append(each)
except AttributeError:
raise AttributeError("Definitions must be named tuples")
self.orderDefinitions()
def orderDefinitions(self):
""""""
ordered = sorted(self.definitions, key=lambda definition: definition.pos)
for i,each in enumerate(ordered):
each.pos = (i+1)
self.definitions = ordered
class Definition(object):
""""""
def __init__(self, definition):
"""Incoming arg is a single namedtuple"""
self.word = definition.word
self.word_id = definition.word_id
self.text = definition.text
self.pos = definition.pos
if __name__ == "__main__":
nt1 = DefinitionTuple("dissemble", 5, "text_string_a", 1)
nt2 = DefinitionTuple("dissemble", 5, "text_string_b)", 2)
nt3 = DefinitionTuple("dissemble", 5, "text_string_c", 3)
# Definiton objects
def_1 = Definition(nt1)
def_2 = Definition(nt2)
def_3 = Definition(nt3)
dissemble = Word("dissemble", [def_1, def_2, def_3])
print "first printing: "
for each in dissemble.definitions:
print each.pos, each.text
# create a new instance of Word ...
a_separate_instance = Word("dissemble", [def_3])
# ... and now the 'pos' ordering of my first instance is messed up!
print "\nnow note how numbers differ compared with first printing:"
for each in dissemble.definitions:
print each.pos, each.text
You create a new instance of Word, but you reuse the same instance of def_3:
a_separate_instance = Word("dissemble", [def_3])
which is stateful. If we look inside using vars:
print vars(def_3)
# create a new instance of Word ...
a_separate_instance = Word("dissemble", [def_3])
print vars(def_3)
We see
{'text': 'text_string_c', 'word': 'dissemble', 'pos': 3, 'word_id': 5}
{'text': 'text_string_c', 'word': 'dissemble', 'pos': 1, 'word_id': 5}
due to orderDefinitions.
In your orderDefinitions method, you are modifying the pos attribute of your Definition objects:
each.pos = (i+1)
So when you call orderDefinitions a second time, you will be doing def_3.pos = 1.
But, dissemble holds a reference to this def_3 object, whose pos attribute has now changed, hence your issue.

Python nested objects unable to retrieve value in function

I am trying to build a tree structure that represents a parsed configuration file (the configuration file has a hierarchical structure to it). I represented this as:
class configContainer():
treeDict = {}
instances = {}
class configObject():
def __init__(self, name, configLine, parent):
self.name = name # Assign to the line number to make unique
self.parent = parent
self.children = []
self.configLine = configLine # Actual line of the configuration
configContainer.instances[name] = self
The configContainer contains a set of objects. configContainer.instances uses a key of "line#" to map to the object. treeDict does a similar mapping, but with a different key (I create treeDict after the entire container is created).
I then try to reference two objects inside two different configContainers. This works fine from __main__. But when I pass the two configContainers to a function, instances always returns objects from configContainer2
if __name__ == "__main__":
f1 = open('rfile', 'r')
configFile1 = f1.read()
f1.close()
configTree1 = parseConfig(configFile1)
configTree1.treeDict = createTreeDict(configTree1)
zObject1 = configTree1.instances["line10"]
f2 = open('sfile', 'r')
configFile2 = f2.read()
f2.close()
configTree2 = parseConfig(configFile2)
configTree2.treeDict = createTreeDict(configTree2)
zObject2 = configTree2.instances["line10"]
print "\n\nFrom __main__"
print "###########################"
print configTree1
print configTree2
print zObject1
print zObject2
compareConfigurations(configTree1, configTree2)
def compareConfigurations(tmpTree1, tmpTree2):
print "\n\nFrom compareConfigurations"
print "###########################"
print tmpTree1
print tmpTree2
zObject1 = tmpTree1.instances["line10"]
zObject2 = tmpTree2.instances["line10"]
print zObject1
print zObject2
Result is:
### From __main__
<__main__.configContainer instance at 0xb77a34ec>
<__main__.configContainer instance at 0xb740a68c>
<__main__.configObject instance at 0xb740e3ac>
<__main__.configObject instance at 0xb7414bcc>
### From compareConfigurations
<__main__.configContainer instance at 0xb77a34ec>
<__main__.configContainer instance at 0xb740a68c>
<__main__.configObject instance at 0xb7414bcc>
<__main__.configObject instance at 0xb7414bcc>
I can't figure out why I am always getting back the 0xb7414bcc object from inside compareConfigurations?
configContainer.instances is a class attribute, so if you modify it for any instance of a class it will change for all instances of that class. With your current code any time you create a new configObject with the same name it will overwrite the entry in configContainer.instances for that name. You should either make instances an instance attribute of configContainer or make sure your configObjects have different names.
class configContainer():
def __init__(self):
self.instances = {}
...
Here is a quick example of what is happening:
>>> cc1 = configContainer()
>>> cc2 = configContainer()
>>> cc1.instances["line10"] = "foo"
>>> configContainer.instances
{'line10': 'foo'}
>>> cc2.instances["line10"] = "bar"
>>> configContainer.instances
{'line10': 'bar'}
>>> cc1.instances
{'line10': 'bar'}
You are aware that configContainer.instances doesn’t access a instance variable, right?
if you want to refer to the wrapping class, you will have to do something like this:
class configContainer(object):
treeDict = {}
instances = {}
def configObject(self, name, configLine, parent):
return _configObject(self, name, configLine, parent)
class _configObject(object):
def __init__(self, container, name, configLine, parent):
self.name = name # Assign to the line number to make unique
self.parent = parent
self.children = []
self.configLine = configLine # Actual line of the configuration
container.instances[name] = self
Something either in parseConfig or createTreeDict is corrupting your instances dictionary.
Notice that in main you get both zObject1 and zObject2 from configTree1:
zObject1 = configTree1.instances["line10"]
#...
zObject2 = configTree1.instances["line10"]
#
print zObject1
print zObject2
Which you said produces:
<__main__.configObject instance at 0xb740e3ac>
<__main__.configObject instance at 0xb7414bcc>
If you posted the source to parseConfig and createTreeDict we could get to the root of it.

Class design: Last Modified

My class:
class ManagementReview:
"""Class describing ManagementReview Object.
"""
# Class attributes
id = 0
Title = 'New Management Review Object'
fiscal_year = ''
region = ''
review_date = ''
date_completed = ''
prepared_by = ''
__goals = [] # List of <ManagementReviewGoals>.
__objectives = [] # List of <ManagementReviewObjetives>.
__actions = [] # List of <ManagementReviewActions>.
__deliverables = [] # List of <ManagementReviewDeliverable>.
__issues = [] # List of <ManagementReviewIssue>.
__created = ''
__created_by = ''
__modified = ''
__modified_by = ''
The __modified attribute is a datetime string in isoformat. I want that attribute to be automatically to be upated to datetime.now().isoformat() every time one of the other attributes is updated. For each of the other attributes I have a setter like:
def setObjectives(self,objectives):
mro = ManagementReviewObjective(args)
self.__objectives.append(mro)
So, is there an easier way to than to add a line like:
self.__modified = datetime.now().isoformat()
to every setter?
Thanks! :)
To update __modified when instance attributes are modified (as in your example of self.__objectives), you could override __setattr__.
For example, you could add this to your class:
def __setattr__(self, name, value):
# set the value like usual and then update the modified attribute too
self.__dict__[name] = value
self.__dict__['__modified'] = datetime.now().isoformat()
Perhaps adding a decorator before each setter?
If you have a method that commits the changes made to these attributes to a database (like a save() method or update_record() method. Something like that), you could just append the
self.__modified = datetime.now().isoformat()
just before its all committed, since thats the only time it really matters anyway.

Categories