如何使用 __setItem__ 设置 class 对象参数的值,就好像它是一个字典
How to set value of class object argument as if its a dict using __setItem__
我已经实现了一个示例 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)
我正在尝试使用以下方法设置参数 x 的值:
pointLocationObj[0] = 1
但我一直收到错误
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)
您的 Point
命名元组需要 x
、y
和 z
参数:
Point = _collections.namedtuple("Point", ("x", "y", "z"))
虽然您只提供了其中两个;您可能还想传入 self._location.z
:
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)
您还可以使用 namedtuple._replace()
method 替换特定属性(返回一个新实例):
def __setitem__(self, key, value):
if key == 0:
self._location = self._location._replace(y=value)
else:
self._location = self._location._replace(x=value)
如果您想使用索引来引用 x
、y
和 z
,请创建一个字典以用作 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})
这里我假设你的意思是 0
是 x
,而不是 1
。
仅通过更新以下方法,它就按预期工作了。感谢@Martijin 让我大开眼界。
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)
)
第二次更新:
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)
)
我已经实现了一个示例 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)
我正在尝试使用以下方法设置参数 x 的值:
pointLocationObj[0] = 1
但我一直收到错误
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)
您的 Point
命名元组需要 x
、y
和 z
参数:
Point = _collections.namedtuple("Point", ("x", "y", "z"))
虽然您只提供了其中两个;您可能还想传入 self._location.z
:
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)
您还可以使用 namedtuple._replace()
method 替换特定属性(返回一个新实例):
def __setitem__(self, key, value):
if key == 0:
self._location = self._location._replace(y=value)
else:
self._location = self._location._replace(x=value)
如果您想使用索引来引用 x
、y
和 z
,请创建一个字典以用作 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})
这里我假设你的意思是 0
是 x
,而不是 1
。
仅通过更新以下方法,它就按预期工作了。感谢@Martijin 让我大开眼界。
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)
)
第二次更新:
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)
)