Creating immutable data classes in Python with namedtuple
I was reviewing some Python code at work today, in which we wanted to wrap up a number of fields in a simple immutable data class. Our initial attempt was to construct a long-winded class definition, for example:
class Parameters( object ):
def __init__( self, x, y, z ):
super( Parameters, self ).__init__( )
self._x = x
self._y = y
self._z = z
@property
def x( self ):
return self._x
@property
def y( self ):
return self._y
@property
def z( self ):
return self._z
Our real-world class had many more properties than the example above, and during the review, I did wonder whether there was a more elegant way of expressing this. After I bit of research, I eventually found collections.namedtuple
. This function can be used to construct a new class type, which has the same semantics as a tuple, but provides access to its members by name rather than by index. Using this function, the above class can be expressed as follows:
import collections
Parameters = collections.namedtuple( 'Parameters', [ 'x', 'y', 'z' ] )
The class type returned by collections.namedtuple
can be used in exactly the same way as in the first example:
# The namedtuple can be constructed in the same way
params = Parameters( 1, 2, z = 3 )
# The properties can be accessed in the same way
print params.x
# The properties are immutable
try:
params.x = 200
except:
print 'Cannot modify a namedtuple member'
# Attempting to access a non-existant property raises an exception
try:
print params.w
except:
print 'Cannot get non-existant namedtuple member'
One notable difference between the two versions of this class type is that with namedtuple, you aren’t allowed to set a non-existant property either. This is presumably such that the namedtuple matches the semantics of a plain tuple:
# Attempting to set a non-existant property also raises an exception
try:
params.w = 200
except:
print 'Cannot set non-existant namedtuple member'