Dynamically building up types in python - python

Suppose I am building a composite set of types:
def subordinate_type(params):
#Dink with stuff
a = type(myname, (), dict_of_fields)
return a()
def toplevel(params)
lots_of_types = dict(keys, values)
myawesomedynamictype = type(toplevelname, (), lots_of_types)
#Now I want to edit some of the values in myawesomedynamictype's
#lots_of_types.
return myawesomedynamictype()
In this particular case, I want a reference to the "typeclass" myawesomedynamictype inserted into lots_of_types.
I've tried to iterate through lots_of_types and set it, supposing that the references were pointed at the same thing, but I found that the myawesomedynamictype got corrupted and lost its fields.
The problem I'm trying to solve is that I get values related to the type subordinate_type, and I need to generate a toplevel instantiation based on subordinate_type.

This is an ancient question, and because it's not clear what the code is trying to do (being a code gist rather than working code), it's a little hard to answer.
But it sounds like you want a reference to the dynamically created class "myawesomedynamictype" on the class itself. A copy of (I believe a copy of) the dictionary lots_of_types became the __dict__ of this new class when you called type() to construct it.
So, just set a new attribute on the class to have a value of the class you just constructed; Is that what you were after?
def toplevel(params)
lots_of_types = dict(keys, values)
myawesomedynamictype = type(toplevelname, (), lots_of_types)
myawesomedynamictype.myawesomedynamictype = myawesomedynamictype
return myawesomedynamictype()

Related

Names of instances and loading objects from a database

I got for example the following structure of a class.
class Company(object):
Companycount = 0
_registry = {}
def __init__(self, name):
Company.Companycount +=1
self._registry[Company.Companycount] = [self]
self.name = name
k = Company("a firm")
b = Company("another firm")
Whenever I need the objects I can access them by using
Company._registry
which gives out a dictionary of all instances.
Do I need reasonable names for my objects since the name of the company is a class attribute, and I can iterate over Company._registry?
When loading the data from the database does it matter what the name of the instance (here k and b) is? Or can I just use arbitrary strings?
Both your Company._registry and the names k and b are just references to your actual instances. Neither play any role in what you'd store in the database.
Python's object model has all objects living on a big heap, and your code interacts with the objects via such references. You can make as many references as you like, and objects automatically are deleted when there are no references left. See the excellent Facts and myths about Python names and values article by Ned Batchelder.
You need to decide, for yourself, if the Company._registry structure needs to have names or not. Iteration over a list is slow if you already have a name for a company you wanted to access, but a dictionary gives you instant access.
If you are going to use an ORM, then you don't really need that structure anyway. Leave it to the ORM to help you find your objects, or give you a sequence of all objects to iterate over. I recommend using SQLAlchemy for this.
the name doesn't matter but if you are gonna initialize a lot of objects you are still gonna make it reasonable somehow

MongoEngine: Create Pickle field

I'm using MongoEngine and trying to create a field that works like SQLAlchemy's PickleType field. Basically, I just need to pickle objects before they're written to the database, and unpickle them when they're loaded.
However it looks like MongoEngine's fields don't provide proper conversion methods I could override, instead having two coercion methods (to_python and to_mongo). If I understand correctly, these functions can be called anytime, that is, a call to to_python(v) does not guarantee that v comes from the database. I've thought of writing something like this:
class PickleField(fields.BinaryField):
def to_python(self, value):
value = super().to_python(value)
if <<value was pickled by the field>>
return pickle.loads(value)
else:
return value
Unfortunately, if I want to be as general as possible, I don't see a way to check whether the value should be unpickled or not. For instance,
a = pickle.dumps(x)
PickleField().to_python(a) # should return a, will return x
I also don't think I can store any state in the PickleField, since that's shared by all instances.
Is there a way around this?

Python: Concatenate two strings for getting a variable from a class

I have a Python class , having some variables. The definition of the class is as follows:
class student:
def __init__(self,name,rollno,DOB,branch):
self.name=name
self.rollno=rollno
self.DOB=DOB
self.branch=branch
self.books=[]
self.fines=[]
I am adding new attributes for a student , and need to store the corresponding values as well (for future use). This is done using the setattr method, and works fine.
Code snippet:
setattr(student,"date_of_join",date())
Now I am approaching the problem as, if the user adds a new attribute (say, "date_of_join"), then I update a list (studattr), initially containing ["name","rollno",DOB","branch","books","fines"] to update the list of attributes. This means that the updated list will also have "date_of_join" now appended to it.
Now if I want to access this list of attributes of a student Instance, then how do I do it? ( Since the records are dynamically updated, and let us suppose I have to access x.date_of_join, then how do I join the two strings? Is there anything similar to python's os.path.join, or rather linux's system call, (merging two strings)? )
Problem:
for attribute in studattr:
print attribute,x.attribute
{ This throws an Exception since the instance x has no variable or method named "attribute")
PS: I tried using inspect,inspect.getmembers(x) as well as dirs(x), vars(x) ,(mentioned on stackoverflow), but it only gives me a list of variables/methods in main class body and not in init.
Use getattr() to access dynamic attributes:
for attr in student.studattr:
print attr, getattr(student, attr)
or use vars() will give you a dictionary of current attributes on a student:
for attr, value in vars(student).iteritems():
print attr, value

Get field value within Flask-MongoAlchemy Document

I've looked at documentation, and have searched Google extensively, and haven't found a solution to my problem.
This is my readRSS function (note that 'get' is a method of Kenneth Reitz's requests module):
def readRSS(name, loc):
linkList = []
linkTitles = list(ElementTree.fromstring(get(loc).content).iter('title'))
linkLocs = list(ElementTree.fromstring(get(loc).content).iter('link'))
for title, loc in zip(linkTitles, linkLocs):
linkList.append((title.text, loc.text))
return {name: linkList}
This is one of my MongoAlchemy classes:
class Feed(db.Document):
feedname = db.StringField(max_length=80)
location = db.StringField(max_length=240)
lastupdated = datetime.utcnow()
def __dict__(self):
return readRSS(self.feedname, self.location)
As you can see, I had to call the readRSS function within a function of the class, so I could pass self, because it's dependent on the fields feedname and location.
I want to know if there's a different way of doing this, so I can save the readRSS return value to a field in the Feed document. I've tried assigning the readRSS function's return value to a variable within the function __dict__ -- that didn't work either.
I have the functionality working in my app, but I want to save the results to the Document to lessen the load on the server (the one I am getting my RSS feed from).
Is there a way of doing what I intend to do or am I going about this all wrong?
I found out the answer. I needed to make use of a computed_field decorator, where the first argument was the structure of my return value and deps was a set which contained the fields that this field was dependent on. I then passed the dependent fields into a function's arguments and there you have it.
#fields.computed_field(db.KVField(db.StringField(), db.ListField(db.TupleField(db.StringField()))), deps=[feedname, location])
def getFeedContent(a=[feedname, location]):
return readRSS(a['feedname'], a['location'])
Thanks anyway, everyone.

How do I get the key value of a db.ReferenceProperty without a database hit?

Is there a way to get the key (or id) value of a db.ReferenceProperty, without dereferencing the actual entity it points to? I have been digging around - it looks like the key is stored as the property name preceeded with an _, but I have been unable to get any code working. Examples would be much appreciated. Thanks.
EDIT: Here is what I have unsuccessfully tried:
class Comment(db.Model):
series = db.ReferenceProperty(reference_class=Series);
def series_id(self):
return self._series
And in my template:
more
The result:
more
Actually, the way that you are advocating accessing the key for a ReferenceProperty might well not exist in the future. Attributes that begin with '_' in python are generally accepted to be "protected" in that things that are closely bound and intimate with its implementation can use them, but things that are updated with the implementation must change when it changes.
However, there is a way through the public interface that you can access the key for your reference-property so that it will be safe in the future. I'll revise the above example:
class Comment(db.Model):
series = db.ReferenceProperty(reference_class=Series);
def series_id(self):
return Comment.series.get_value_for_datastore(self)
When you access properties via the class it is associated, you get the property object itself, which has a public method that can get the underlying values.
You're correct - the key is stored as the property name prefixed with '_'. You should just be able to access it directly on the model object. Can you demonstrate what you're trying? I've used this technique in the past with no problems.
Edit: Have you tried calling series_id() directly, or referencing _series in your template directly? I'm not sure whether Django automatically calls methods with no arguments if you specify them in this context. You could also try putting the #property decorator on the method.

Categories