如何将构造函数添加到子类数字类型?

时间:2010-04-28 18:45:51

标签: python

我想在python中继承一个数字类型(比方说,int)并给它一个闪亮的复杂构造函数。像这样:

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版本中,为数字类型子类化并重新定义内置类型的构造函数的最佳方法是什么?

编辑: 在评论中发现这没有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)

下面的答案还提供了非常有趣的Abstract Base Classesnumbers模块链接。

3 个答案:

答案 0 :(得分:5)

从Python 2.6开始,扩展数值类型的首选方法不是直接从它们继承,而是将您的类注册为Number抽象基类的子类。查看the abc module以获取抽象基类概念的文档。

该模块的文档链接到the numbers module,其中包含您可以选择声明自己的一部分的抽象基类。所以基本上你会说

import numbers
numbers.Number.register(NamedInteger)

表示您的班级是一种数字。

当然,问题在于它需要您实现所有各种处理程序方法,例如__add____mul__等。但是,无论如何,你真的必须这样做,因为你不能依赖这些操作的int类'实现来为你的班级做正确的事情。例如,当您将整数添加到命名整数时应该发生什么?

我的理解是ABC方法旨在迫使您面对这些问题。在这种情况下,最简单的方法是将int保存为类的实例变量;换句话说,当您register您的班级与is-a建立Number关系时,您的实施会与has-a建立int关系。

答案 1 :(得分:5)

当您继承不可变内置类型时,必须使用__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

答案 2 :(得分:0)

如果您没有将值传递给super(NamedInteger, self).__init__()

,它将正常工作

我想知道为什么,我正在从你的帖子中学习: - )