Расширение базовых классов в Python - PullRequest
11 голосов
/ 29 августа 2008

Я пытаюсь расширить некоторые "базовые" классы в 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)

Он отлично работает в случае list , потому что метод append изменяет объект "на месте", не возвращая его. Но в случае int метод add не изменяет значение внешней переменной x . Я полагаю, это нормально в том смысле, что self является локальной переменной в методе add класса, но это не позволяет мне изменить начальное значение, назначенное экземпляру класса .

Можно ли расширить класс таким способом или я должен определить свойство класса с базовым типом и сопоставить все необходимые методы этому свойству?

Ответы [ 4 ]

23 голосов
/ 29 августа 2008

Ваши два 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'>
5 голосов
/ 29 августа 2008

int является типом значения, поэтому каждый раз, когда вы делаете присвоение (например, оба экземпляра + = выше), оно не изменяет объект, который имеется куча, но заменяет ссылку на один из результатов правой части присваивания (т. е. int)

список не является типом значения, поэтому он не связан теми же правилами.

На этой странице есть более подробная информация о различиях: http://docs.python.org/ref/objects.html

IMO, да, вы должны определить новый класс, который хранит int как переменную экземпляра

2 голосов
/ 25 июля 2011

Я немного расширил ваш класс 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)
0 голосов
/ 29 августа 2008

Ints являются неизменяемыми, и вы не можете изменить их на месте, поэтому вы должны пойти с опцией # 2 (потому что вариант # 1 невозможен без некоторых хитростей).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...