Subclassing tuple with multiple __init__ arguments
The following code works:
class Foo(tuple):
def __init__(self, b):
super(Foo, self).__init__(tuple(b))
if __name__ == '__main__':
print Foo([3, 4])
$ python play.py
Result:
play.py:4: DeprecationWarning: object.__init__() takes no parameters
super(Foo, self).__init__(tuple(b))
(3, 4)
But not the following:
class Foo(tuple):
def __init__(self, a, b):
super(Foo, self).__init__(tuple(b))
if _开发者_StackOverflow_name__ == '__main__':
print Foo(None, [3, 4])
$ python play.py
Result:
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)
Why?
Because tuples are immutable, you have to override __new__
instead:
python docs
object.__new__(cls[, ...])
Called to create a new instance of class
cls
.__new__()
is a static method (special-cased so you need not declare it as such) that takes the class of which an instance was requested as its first argument. The remaining arguments are those passed to the object constructor expression (the call to the class). The return value of__new__()
should be the new object instance (usually an instance ofcls
).Typical implementations create a new instance of the class by invoking the superclass’s
__new__()
method usingsuper(currentclass, cls).__new__(cls[, ...])
with appropriate arguments and then modifying the newly-created instance as necessary before returning it.If
__new__()
returns an instance ofcls
, then the new instance’s__init__()
method will be invoked like__init__(self[, ...])
, where self is the new instance and the remaining arguments are the same as were passed to__new__()
.If
__new__()
does not return an instance ofcls
, then the new instance’s__init__()
method will not be invoked.
__new__()
is intended mainly to allow subclasses of immutable types (likeint
,str
, ortuple
) to customize instance creation. It is also commonly overridden in custom metaclasses in order to customize class creation.
To assign the tuple value you need to override the __new__
method:
class Foo(tuple):
def __new__ (cls, a, b):
return super(Foo, cls).__new__(cls, tuple(b))
The arguments seem to be ignored by the __init__
implementation of the tuple class, but if you need to do some init stuff you can do it as follows:
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
精彩评论