如何使用__setItem__将类对象参数的值设置为dict

时间:2015-05-06 11:35:49

标签: python namedtuple

我已经实现了一个示例类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)

2 个答案:

答案 0 :(得分:1)

您的Point命名元组需要xyz个参数:

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)

如果您想使用索引来引用xyz,请创建一个词典以作为关键字参数应用于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})

我假设您的意思是0x,而不是1

答案 1 :(得分:0)

只需更新以下方法,就可以正常工作了。感谢@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)
            )