Как добавить конструктор в числовой тип с подклассами? - PullRequest
8 голосов
/ 28 апреля 2010

Я хочу создать подкласс числового типа (скажем, int) в python и дать ему блестящий сложный конструктор. Примерно так:

class NamedInteger(int):
    def __init__(self, value):
        super(NamedInteger, self).__init__(value)
        self.name = 'pony'

    def __str__(self):
        return self.name

x = NamedInteger(5)
print x + 3
print str(x)

Это отлично работает в Python 2.4, но Python 2.6 выдает предупреждение об устаревании. Каков наилучший способ создать подкласс числового типа и переопределить конструкторы для встроенных типов в более новых версиях Python?

Edit: В комментариях заметили, что это работает без строки super (), поэтому это может выглядеть так:

class NamedInteger(int):
    def __init__(self, value):
        self.name = 'pony'

    def __str__(self):
        return self.name

x = NamedInteger(5)
print x + 3
print str(x)

Я считаю, что это работает, потому что тип int является неизменным и имеет только __new__ метод. Однако я был бы рад узнать правильный способ создания подклассов, чтобы я мог создать класс с таким поведением:

x = NamedInteger(5, 'kitty')

Второе редактирование:

Окончательная версия теперь выглядит так:

class NamedInteger(int):
    def __new__(cls, value, name='pony'):
        self = super(NamedInteger, cls).__new__(cls, value)
        self.name = name
        return self

    def __str__(self):
        return self.name

x = NamedInteger(5)
y = NamedInteger(3, 'kitty')
print "%d %d" % (x, y)
print "%s %s" % (x, y)

Ответы ниже также дали очень интересные ссылки на Абстрактные базовые классы и чисел модулей.

Ответы [ 3 ]

5 голосов
/ 28 апреля 2010

Начиная с Python 2.6, предпочтительным способом расширения числовых типов является не прямое наследование от них, а регистрация вашего класса в качестве подкласса абстрактного базового класса Number. Проверьте модуль abc для документации концепции абстрактного базового класса.

Документация этого модуля ссылается на модуль чисел , который содержит абстрактные базовые классы, частью которых вы можете объявить себя. Так что в основном вы бы сказали

import numbers
numbers.Number.register(NamedInteger)

, чтобы указать, что ваш класс является типом числа.

Конечно, проблема в том, что для этого требуется, чтобы вы реализовали все различные методы-обработчики, такие как __add__, __mul__ и т. Д. Тем не менее, вам действительно придется это делать, так как вы можете t полагаться на реализацию этих операций int class ', чтобы сделать правильную вещь для вашего класса. Например, что должно произойти, когда вы добавляете целое число к названному целому числу?

Насколько я понимаю, подход ABC предназначен для того, чтобы заставить вас ответить на эти вопросы. В этом случае самое простое, что можно сделать, - это сохранить int в качестве переменной экземпляра вашего класса; другими словами, пока вы register будете указывать своему классу отношение is-a с Number, ваша реализация дает ему отношение has-a с int.

5 голосов
/ 28 апреля 2010

Вы должны использовать __new__ вместо __init__ при создании подкласса неизменяемых встроенных типов, например, :

class NamedInteger(int):

    def __new__(cls, value, name='pony'):
        inst = super(NamedInteger, cls).__new__(cls, value)
        inst.name = name
        return inst

    def __str__(self):
        return self.name

x = NamedInteger(5)
print x + 3                 # => 8   
print str(x)                # => pony
x = NamedInteger(3, "foo")  
print x + 3                 # => 6
print str(x)                # => foo
0 голосов
/ 28 апреля 2010

Будет нормально работать, если вы не передадите значение в super(NamedInteger, self).__init__()

Интересно, почему я учусь на вашем посте: -)

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