用多个__init__参数对元组进行子类化
下面的代码可以正常运行:
class Foo(tuple):
def __init__(self, b):
super(Foo, self).__init__(tuple(b))
if __name__ == '__main__':
print Foo([3, 4])
$ python play.py
结果是:
play.py:4: DeprecationWarning: object.__init__() takes no parameters
super(Foo, self).__init__(tuple(b))
(3, 4)
但是下面的代码就不行:
class Foo(tuple):
def __init__(self, a, b):
super(Foo, self).__init__(tuple(b))
if __name__ == '__main__':
print Foo(None, [3, 4])
$ python play.py
结果是:
Traceback (most recent call last):
File "play.py", line 7, in <module>
print Foo(None, [3, 4])
TypeError: tuple() takes at most 1 argument (2 given)
这是为什么呢?
2 个回答
64
要给元组赋值,你需要重写一下 __new__
方法:
class Foo(tuple):
def __new__ (cls, a, b):
return super(Foo, cls).__new__(cls, tuple(b))
看起来元组类的 __init__
方法会忽略传入的参数,但如果你需要做一些初始化的工作,可以这样做:
class Foo(tuple):
def __new__ (cls, a, b):
return super(Foo, cls).__new__(cls, tuple(b))
def __init__(self, a, b):
self.a=a
self.b=b
if __name__ == '__main__':
foo = Foo(None, [3, 4])
print foo
print foo.a
print foo.b
77
因为元组是不可变的,所以你需要重写 __new__
方法:
object.__new__(cls[, ...])
这个方法是用来创建一个新类
cls
的实例的。__new__()
是一个静态方法(特别处理过,所以你不需要特别声明它),它的第一个参数是你想要创建实例的类。后面的参数是传给对象构造函数的(也就是调用类时传入的参数)。__new__()
的返回值应该是新创建的对象实例(通常是cls
的一个实例)。一般的实现方式是通过调用父类的
__new__()
方法来创建一个新实例,使用super(currentclass, cls).__new__(cls[, ...])
并传入合适的参数,然后在返回之前根据需要修改这个新创建的实例。如果
__new__()
返回的是cls
的实例,那么新实例的__init__()
方法会被调用,像这样__init__(self[, ...])
,其中 self 是新实例,后面的参数和传给__new__()
的参数是一样的。如果
__new__()
没有返回cls
的实例,那么新实例的__init__()
方法就不会被调用。
__new__()
主要是为了让不可变类型的子类(比如int
、str
或tuple
)能够自定义实例的创建。它也常常在自定义元类中被重写,以便自定义类的创建过程。