Reputation: 8277
I have implemented a sample class PointLocation,
import collections as _collections
Point = _collections.namedtuple("Point", ("x", "y", "z"))
class PointLocation(object):
def __init__(self, x, y, z):
self._x = x
self._y = y
self._z = z
self._location = Point(x, y, z)
print "First Item: %s " % self._location[0]
def __repr__(self):
return "%s(%r, %r, %r)" % (
self.__class__.__name__,
self._x,
self._y,
self._z,
)
def __getitem__(self, key):
"""
to make the object to be used in a manner similar to a tuple or list
"""
return self._location.__getitem__(key)
def __setitem__(self, key, value):
if key == 0:
self._location = Point(self._location.x, value)
else:
self._location = Point(value, self._location.y)
and I am trying to set value of an argument x using:
pointLocationObj[0] = 1
but I keep getting error
Traceback (most recent call last):
File "/usr/san/Desktop/testScripts/classObject_returnsList.py", line 40, in <module>
pointLocationObj[0] = 7
File "/usr/san/Desktop/testScripts/classObject_returnsList.py", line 32, in __setitem__
self._location = Point(self._location.x, value)
TypeError: __new__() takes exactly 4 arguments (3 given)
Upvotes: 0
Views: 231
Reputation: 1121654
Your Point
named tuple requires x
, y
and z
arguments:
Point = _collections.namedtuple("Point", ("x", "y", "z"))
while you only provided two of those; you probably wanted to pass in self._location.z
as well:
def __setitem__(self, key, value):
if key == 0:
self._location = Point(self._location.x, value, self._location.y)
else:
self._location = Point(value, self._location.y, self._location.z)
You can also use the namedtuple._replace()
method to replace a specific attribute (a new instance is returned):
def __setitem__(self, key, value):
if key == 0:
self._location = self._location._replace(y=value)
else:
self._location = self._location._replace(x=value)
If you wanted to use indices to refer to x
, y
and z
, create a dictionary to apply as a keyword argument to namedtuple._replace()
:
def __setitem__(self, key, value):
coordinate = self._location._fields[key] # can raise IndexError, we want to propagate that
self._location = self._location._replace(**{coordinate: value})
Here I assume you meant 0
to be x
, not 1
.
Upvotes: 1
Reputation: 8277
just by updating the below method, it worked as expected. Thanks @Martijin for opening my eyes.
def __setitem__(self, key, value):
if key == 0:
self._location = Point(value, self._location.y, self._location.z)
elif key == 1:
self._location = Point(self._location.x, value, self._location.z)
elif key == 2:
self._location = Point(self._location.x, self._location.y, value)
else:
raise IndexError("%s takes %s has arguments. You are trying to update %s argument." % (
self.__class__.__name__,
len(self._location), key+1)
)
2nd Update:
def __setitem__(self, key, value):
""" update the value of argument like a dictionary
"""
try:
self._location = self._location._replace(**{'xyz'[key]: value})
except IndexError:
raise IndexError("%s takes %s has arguments. You are trying to update %s argument." % (
self.__class__.__name__,
len(self._location), key)
)
Upvotes: 0