我想在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)
Run Code Online (Sandbox Code Playgroud)
这在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)
Run Code Online (Sandbox Code Playgroud)
我相信这是有效的,因为int是不可变类型并且只有__new__
方法.但是我很高兴知道一种正确的子类化方法,所以我可以用这样的行为构建一个类:
x = NamedInteger(5, 'kitty')
Run Code Online (Sandbox Code Playgroud)
第二次编辑:
最终版本现在看起来像这样:
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)
Run Code Online (Sandbox Code Playgroud)
从Python 2.6开始,扩展数值类型的首选方法不是直接从它们继承,而是将您的类注册为Number抽象基类的子类.查看abc模块以获取Abstract Base Class概念的文档.
该模块的文档链接到数字模块,其中包含您可以选择声明自己的一部分的抽象基类.所以基本上你会说
import numbers
numbers.Number.register(NamedInteger)
Run Code Online (Sandbox Code Playgroud)
表示您的班级是一种数字.
当然,这个问题是它需要你实现所有不同的处理方法,例如__add__
,__mul__
等等.但是,你真的无论如何要做到这一点,因为你不能依靠int
那些类的实现操作为你的班级做正确的事情.例如,当您将整数添加到命名整数时应该发生什么?
我的理解是ABC方法旨在迫使你面对这些问题.在这种情况下,最简单的事情可能是将int保存为类的实例变量; 换句话说,当你register
的班级给你的is-a
关系时Number
,你的实现会给它一个has-a
关系int
.
您必须使用__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
Run Code Online (Sandbox Code Playgroud)