Python子类化元组对象,能够在内部重新实例化自身

1 投票
2 回答
1730 浏览
提问于 2025-04-16 07:46

我明白Python中可变对象和不可变对象的概念,这没问题。虽然不可变对象的本质值不能直接修改,但我们可以用不同的值重新创建一个不可变对象的实例。我想做的是在一个元组的子类中建立一个内部函数,让它可以以一种受控的方式重新赋值。这个基本功能我找了很久都没找到,希望能得到一些帮助。

举个例子,我想做到这样的事情,但显然这样做是行不通的。

class myTuple(tuple):
    def __new__(self):
        initialValue = [1, 2, 3]
        return super(myTuple, self).__new__(self, initialValue)
    def resetMyself(self):
        newValue = [4, 5, 6]
        self = tuple(newValue)

结果如下...

>>> foo = myTuple()
>>> print foo
(1, 2, 3)
>>> foo.resetMyself()
>>> print foo
(4, 5, 6)

我在这个网站上看了很多类似问题的回答,知道有些人可能会问“你为什么想这么做?”但我希望大家能直接给出答案,包括可能的“你根本不能这样做”,如果真是这样的话。

非常感谢大家!

补充一下,感谢下面的回答,这就是我最后得到的结果...

class semiImmutableList(list):
    def __setitem__(self, *args):
        raise TypeError("'semiImmutableList' object doesn't support item assignment")
    __setslice__ = __setitem__
    def __delitem__(self, *args):
        raise TypeError("'semiImmutableList' object doesn't support item deletion")
    __delslice__ = __delitem__
    def append(self, *args):
        raise AttributeError("'semiImmutableList' object has no attribute 'append'")
    def extend(self, *args):
        raise AttributeError("'semiImmutableList' object has no attribute 'extend'")
    def insert(self, *args):
        raise AttributeError("'semiImmutableList' object has no attribute 'insert'")
    def remove(self, *args):
        raise AttributeError("'semiImmutableList' object has no attribute 'remove'")
    def pop(self, *args):
        raise AttributeError("'semiImmutableList' object has no attribute 'pop'")
    def __init__(self):
        x = [1, 2, 3]
        super(semiImmutableList, self).__init__(x)
    def resetMyself(self):
        super(semiImmutableList,self).append(5)

如果你看到上面的内容有什么改进或调整的地方,请分享一下。看起来AttributeError的重复抛出可以合并吗?

2 个回答

2

如果你想要一个可以改变的元组,那就用列表吧。

补充:

试试这个

class FrankenList(object):
    def __init__(self, init=None):
        self.__data = init or []

    def __getitem__(self, key):
        return self.__data[key]

    def __repr__(self):
        return repr(self.__data)

    def __str__(self):
        return str(self.__data)
1

其实很简单,你只需要把一个列表包裹起来就行。

class ImmutableList(object):
    def __init__(self, *args):
        self.__values = args; # internally we store the values in a list

    # make imuList[0] = 2 raise an error, just like a tuple would
    def __setitem__(self, index, value):
        raise TypeError('ImmutableList does not support item assignment')

    # del imuList[0] should also raise
    def __delitem__(self, index, value):
        raise TypeError('ImmutableList does not support item deletion')**

    # make our imuList indexable, also catch the normal index error and raise one
    # that tells that this is an immutable list, will make it easier to debug :)
    def __getitem__(self, index):
        try:
            return self.__values[index]

        except IndexError:
            raise IndexError('ImmutableList index out of range')

    # the usual stuff
    def __repr__(self):
        return repr(self.__values)

    def __str__(self):
        return str(self.__values)

# create a new imulist
e = ImmutableList(1, 2, 3, 4)

# works!
print e[0]

# raises an error
e[0] = 5

# raises another error
print e[9]

接下来,你只需要在这个类里面修改 self._values。最后再给你一个建议,虽然你在类里面可以控制 self._values,但外面的人还是有可能会动它,因为Python并不支持真正的私有成员

如果你想更好地防止别人修改 __values,可以直接从列表继承,但这样会多花一些功夫。而且即使这样,别人还是可以通过 list.__setitem__(imListInstance, 0, 5) 之类的方法来改动值。

撰写回答