16

我正在尝试在 Python 中扩展一些“基”类:

class xlist (list):
    def len(self):
        return len(self)

    def add(self, *args):
        self.extend(args)
        return None


class xint (int):
    def add(self, value):
        self += value
        return self


x = xlist([1,2,3])
print x.len()   ## >>> 3 ok
print x         ## >>> [1,2,3] ok
x.add (4, 5, 6)
print x         ## >>> [1,2,3,4,5,6] ok

x = xint(10)
print x         ## >>> 10 ok
x.add (2)
print x         ## >>> 10  # Not ok (#1)

print type(x)         ## >>> <class '__main__.xint'> ok
x += 5
print type(x)         ## >>> <type 'int'>  # Not ok (#2)

它在列表情况下工作正常,因为append方法“就地”修改对象,而不返回它。但在int情况下,add方法不会修改外部x变量的值。我想这很好,因为self是类的add方法中的局部变量,但这阻止了我修改分配给类实例的初始值。

是否可以以这种方式扩展一个类,或者我应该用基类型定义一个类属性并将所有需要的方法映射到这个属性?

4

5 回答 5

29

由于两个不同的原因,您的两个xint示例不起作用。

第一个不起作用,因为self += value相当于self = self + value将局部变量重新分配self给不同的对象(整数)但不更改原始对象。你真的无法得到这个

>>> x = xint(10)
>>> x.add(2)

使用一个子类,int因为整数是不可变的。

要让第二个工作,您可以定义一个__add__方法,如下所示:

class xint(int):
    def __add__(self, value):
        return xint(int.__add__(self, value))

>>> x = xint(10)
>>> type(x)
<class '__main__.xint'>
>>> x += 3
>>> x
13
>>> type(x)
<class '__main__.xint'>
于 2008-08-28T23:41:55.720 回答
6

int是一个值类型,所以每次你做一个赋值,(例如+=上面的两个实例),它不会修改你在堆上的对象,而是用右边的结果之一替换引用赋值(即一个int

list不是值类型,因此不受相同规则的约束。

此页面有更多关于差异的详细信息:Python 语言参考 - 3. 数据模型

IMO,是的,您应该定义一个将 int 作为实例变量的新类

于 2008-08-28T22:32:40.147 回答
3

我稍微扩展了你的 xlist 类,做了它,这样你就可以找到一个数字的所有索引点,这样你就可以一次扩展多个列表,使它初始化并使它可以迭代它

class xlist:
    def __init__(self,alist):
        if type(alist)==type(' '):
            self.alist = [int(i) for i in alist.split(' ')]
        else:
            self.alist = alist
    def __iter__(self):
        i = 0
        while i<len(self.alist):
            yield self.alist[i]
            i+=1
    def len(self):
        return len(self.alist)
    def add(self, *args):
        if type(args[0])==type([1]):
            if len(args)>1:
                tmp = []
                [tmp.extend(i) for i in args]
                args = tmp
            else:args = args[0]
        if type(args)==type(''):args = [int(i) for i in args.split(' ')] 
        (self.alist).extend(args)
        return None
    def index(self,val):
        gen = (i for i,x in enumerate(self.alist) if x == val)
        return list(gen)
于 2011-07-24T20:30:07.467 回答
0

Ints 是不可变的,您不能就地修改它们,因此您应该使用选项#2(因为选项#1 没有一些技巧是不可能的)。

于 2008-08-28T22:28:36.413 回答
0

我编写了一个可变整数类的示例,该类实现了运算符方法列表中的一些基本方法。它可以正确打印、加法、减法、乘法、除法、排序和比较相等性。

如果你想让它做 int 的所有事情,你将不得不实现更多的方法。

class MutablePartialInt:
    def __init__(self, value):
        self.value = value

    def _do_relational_method(self, other, method_to_run):
        func = getattr(self.value, method_to_run)
        if type(other) is MutablePartialInt:
            return func(other.value)
        else:
            return func(other)

    def __add__(self, other):
        return self._do_relational_method(other, "__add__")
    
    def __sub__(self, other):
        return self._do_relational_method(other, "__sub__")

    def __mul__(self, other):
        return self._do_relational_method(other, "__mul__")
    
    def __truediv__(self, other):
        return self._do_relational_method(other, "__truediv__")

    def __floordiv__(self, other):
        return self._do_relational_method(other, "__floordiv__")

    def __eq__(self, other):
       return self._do_relational_method(other, "__eq__")
    
    def __neq__(self, other):
       return self._do_relational_method(other, "__neq__")

    def __lt__(self, other):
        return self._do_relational_method(other, "__lt__")

    def __gt__(self, other):
        return self._do_relational_method(other, "__gt__")

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

    def __repr__(self):
        return self.__str__()
于 2022-02-16T10:55:42.467 回答