Подтвердить что ты не робот

Подклассификация кортежей Python с несколькими аргументами __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)

Почему?

4b9b3361

Ответ 1

Поскольку кортежи неизменяемы, вместо этого вы должны переопределить __new__:

документы python

object.__new__(cls[, ...])

Вызывается для создания нового экземпляра class cls. __new__() является статическим метод (специальный корпус, поэтому вам не нужно объявите его как таковой), который принимает класс которого экземпляр был в качестве первого аргумента. остальными аргументами являются те, которые прошли к выражению конструктора объекта (вызов класса). Возврат значение __new__() должно быть новым экземпляр объекта (обычно это экземпляр of cls).

Типичные реализации создают новый экземпляр класса, вызвав метод суперкласса __new__(), используя super(currentclass, cls).__new__(cls[, ...]) с соответствующими аргументами и затем изменение вновь созданного если необходимо, перед возвратом он.

Если __new__() возвращает экземпляр cls, то новые экземпляры __init__() будет вызываться как __init__(self[, ...]), где self - это новый экземпляр, а остальные аргументы те же, что и переданные до __new__().

Если __new__() не возвращает экземпляр cls, то новый instance __init__() метод не будет вызывается.

__new__() предназначен главным образом для обеспечения подклассов неизменяемых типов (например, int, str или tuple) для настройки создание экземпляра. Это также обычно переопределяется в пользовательских метаклассах в чтобы настроить создание класса.

Ответ 2

Чтобы назначить значение кортежа, вам необходимо переопределить метод __new__:

class Foo(tuple):

    def __new__ (cls, a, b):
        return super(Foo, cls).__new__(cls, tuple(b))

Аргументы, по-видимому, игнорируются реализацией типа tuple __init__, но если вам нужно сделать некоторые файлы 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