I'd like to create my own type of build-in namedtuple that has some extra features. Let's say we create a class:
from collections import namedtuple
MyClass = namedtuple('MyClass', 'field1 field2')
It`s immutable, readable and simple. Now I can create instances of MyClass:
myobj = MyClass(field1 = 1, field2 = 3.0)
print(myobj.field1, myobj.field2)
My extra requirement is when instance is created I'd like to check if field1
is int
type and field2
is float
. For example if user try to create MyClass instance:
obj = MyClass(field1 = 1, field2 = 3.0) # instantiates ok
obj1 = MyClass(field1 = 'sometext', field2 = 3.0) # raises TypeError
I tried to make a customized namedtuple that can validate datatypes (MyClass should be immutable) something like.:
MyClass = modifiednamedtuple('MyClass', 'field1 field2', (int, float) )
but got stuck :(. namedtuple
is function (cannot be a baseclass for modifiednamedtuple), my experiments with metaclasses failed.
Any tips or suggestions?
ok, I came up with a solution that might be not "clean" or pythonic. It works except that my objects are not immutable. How to make them immutable? Any suggestions how to make it more clean and redable?
Here is my code.:
def typespecificnamedtuple(name, *attr_definitions):
def init(self, *args, **kwargs):
valid_types = dict(attr_definitions) # tuples2dict
for attr_name, value in kwargs.items():
valid_type = valid_types[attr_name]
if not isinstance(value, valid_type):
raise TypeError('Cannot instantiate class '+ self.__name__+
'. Inproper datatype for '+ attr_name + '=' + str(value)+
', expected '+str(valid_type) )
setattr(self, attr_name, value)
class_dict = {'__init__' : init, '__name__' : name}
for attr_def in attr_definitions:
class_dict[attr_def[0]] = attr_def[1] # attr_def is ('name', <type int>)
customType = type(name, (object, ), class_dict )
return customType
if __name__ == '__main__':
MyClass = typespecificnamedtuple('MyClass', ('value', int), ('value2', float) )
mc = MyClass(value = 1, value2 = 3.0)
mc.something = 1 # this assigment is possible :( how to make immutable?
print(mc.__name__, mc.value, mc.value2, mc.something)
mc1 = MyClass(value = 1, value2 = 'sometext') # TypeError exception is raised
and console output.:
MyClass 1 3.0 1
Traceback (most recent call last):
File "/home/pawel/workspace/prices/prices.py", line 89, in <module>
mc1 = MyClass(value = 1, value2 = 'sometext') # TypeError exception is raised
File "/home/pawel/workspace/prices/prices.py", line 70, in init
', expected '+str(valid_type) )
TypeError: Cannot instantiate class MyClass. Inproper datatype for value2=sometext, expected <class 'float'>
namedtuple
isn't a class, as you note; it's a function. But it's a function that returns a class. Thus, you can use the result of thenamedtuple
call as a parent class.Since it is immutable, a
namedtuple
is initialized in__new__
rather in in__init__
.So something like this, perhaps:
namedtuple()
uses a string template to generate a class object.You could use that same technique for your modified version; but do use the code already generated for you as a base class:
This lets you produce new type-checking namedtuple classes: