Reputation: 7514
Here is some code to start with:
def objectify(name, fields):
""" Create a new object including the __init__() method. """
def __init__(self, *argv):
for name, val in zip(var_names, argv):
setattr(self, name, val)
# The following line of code is currently limited to a single dynamic class.
# We would like to extend it to allow creating multiple classes
# and each class should remember it's own fields.
__init__.var_names = fields
result = type(name, (object,), dict(__init__=__init__))
The challenge here is to find a way to make unique copies of the __init__()
method of each class which has a static list of its variable names.
Plan B:
We can do this using eval()
to run code that a function generates. But eval()
is to be avoided wherever possible. The challenge here is to do this without eval()
.
EDIT: While writing up the question I came up with a solution. (See below.) Maybe this will help someone.
EDIT2: I would use this function to create something like a namedtuple()
, except that they are mutable.
Point = objectify('point', ['x', 'y'])
a = Point(1, 2)
b = Point(2, 3)
print a.__dict__
print b.__dict__
Upvotes: 0
Views: 93
Reputation: 34175
You don't mention anything about the usage of fields later on. If you only need them in __init__
, you don't need to save them at all:
def objectify(name, fields):
""" Create a new object including the __init__() method. """
fields = fields[:]
def __init__(self, *argv):
for name, val in zip(fields, argv):
setattr(self, name, val)
result = type(name, (object,), dict(__init__=__init__))
return result
Otherwise, you should look at metaclasses - that's exactly the usecase for them.
Updated: making a copy of fields
ensures that changing the list in the caller will not affect the stored one. The values can still change... left as an exercise to the reader to verify everything is a str
.
Upvotes: 3
Reputation: 7514
Here is one solution:
def objectify(obj_name, fields):
""" Create a new object including the __init__() method. """
def __init__(self, *argv):
""" Generic initializer for dynamically created classes. """
fields = objectify.fields[self.__class__.__name__]
for field, val in zip(fields, argv):
setattr(self, field, val)
result = type(obj_name, (object,), dict())
result.__init__ = __init__
# Save the list of fields in a static dictionary that is retrieved by class name.
objectify.fields[obj_name] = fields
return result
objectify.fields = {} # A static local variable.
Upvotes: 0