2010-04-28 115 views
7

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

编辑: 看准评论认为,这部作品没有超()行,所以它可能是这样的:

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模块非常有趣的链接。

+1

+1好问题 - 请参阅[关于Python bug跟踪器的此线程](http://bugs.python.org/issue1683368)了解此更改的历史记录。 – balpha 2010-04-28 18:54:30

回答

4

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

这将正常工作,如果你没有通过价值super(NamedInteger, self).__init__()

我不知道为什么,虽然,我从您的文章学习:-)

+0

我把你的代码示例放在反引号中,以便正确显示。另外,这种方法的问题在于'NamedInteger'没有用适当的值进行初始化。 – 2010-04-28 18:54:07

+0

啊,你是对的,你有一个鹰眼来发现!我想现在我有一个想法,为什么这个没有super() – abbot 2010-04-28 18:54:55

5

对于Python 2.6的,首选的方法来扩展数字类型不是直接从它们继承,而是将您的类注册为Number抽象基类的子类。查阅the abc module获取Abstract Base Class概念的文档。

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

import numbers 
numbers.Number.register(NamedInteger) 

,表明你的类是一个类型的号码。

当然,问题在于它需要你实现所有各种处理方法,例如__add__,__mul__等等。但是,无论如何你都必须这样做,因为你不能依靠类的实现这些操作来为你的类做正确的事情。例如,当您将一个整数添加到一个已命名的整数时会发生什么?

我的理解是,ABC方法的目的是强迫你面对这些问题。在这种情况下,最简单的做法可能是将int保存为类的实例变量;换句话说,当你将你的register类给它与Numberis-a关系,您的实现提供了其与int一个has-a关系。