Различия между конструкторами Python и С++
Недавно я узнал больше о Python, и когда я проходил отличный Dive into Python, автор отметил здесь, что метод __init__
не является технически конструктором, хотя он обычно функционирует как один.
У меня есть два вопроса:
-
Каковы различия между тем, как
С++ создает объект и как
Python "конструирует" объект?
-
Что
делает конструктор конструктором,
и как метод __init__
не соответствуют этим критериям?
Ответы
Ответ 1
Различие, которое автор рисует, заключается в том, что в отношении языка Python у вас есть действительный объект указанного типа, прежде чем вы даже войдете в __init__
. Поэтому он не является "конструктором", поскольку в С++ и теоретически конструктор превращает недопустимый предварительно сконструированный объект в "правильный" завершенный объект типа.
В принципе __new__
в Python определяется как возвращающий "экземпляр нового объекта", тогда как новые операторы С++ возвращают некоторую память, которая еще не является экземпляром какого-либо класса.
Однако, __init__
в Python, вероятно, там, где вы сначала устанавливаете некоторые важные инварианты класса (какие атрибуты он имеет, только для стартеров). Что касается пользователей вашего класса, это может быть конструктором. Это просто, что среда выполнения Python не заботится ни о одном из этих инвариантов. Если вам нравится, у него очень низкие стандарты для того, что представляет собой построенный объект.
Я думаю, что автор делает справедливую точку, и это, безусловно, интересное замечание о том, как Python создает объекты. Это довольно тонкое различие, хотя и я сомневаюсь, что вызов __init__
конструктора когда-либо приведет к сломанному коду.
Кроме того, я отмечаю, что документация Python относится к __init__
как конструктор (http://docs.python.org/release/2.5.2/ref/customization.html)
В качестве специального ограничения на конструкторы, никакое значение не может быть возвращено
... так что если есть какие-либо практические проблемы с мышлением __init__
в качестве конструктора, то Python в беде!
То, как объекты конструкции Python и С++ имеют некоторое сходство. Оба вызова функции с относительно простой ответственностью (__new__
для экземпляра объекта против некоторой версии operator new
для необработанной памяти), тогда оба вызова функции, которая имеет возможность сделать больше работы для инициализации объекта в полезное состояние (__init__
против конструктора).
Практические отличия:
-
в С++ конструкторы no-arg для базовых классов вызываются автоматически в соответствующем порядке, если необходимо, тогда как для __init__
в Python вы должны явно инициализировать свою базу в своем собственном __init__
. Даже в С++ вы должны указать конструктор базового класса, если он имеет аргументы.
-
в С++, у вас есть целый механизм того, что происходит, когда конструктор генерирует исключение с точки зрения вызова деструкторов для уже созданных под-объектов. В Python я думаю, что время выполнения (самое большее) вызывает __del__
.
Тогда также существует разница, что __new__
не только выделяет память, но и возвращает фактический экземпляр объекта. Опять же, необработанная память на самом деле не является концепцией, применимой к коду Python.
Ответ 2
Конструктор на многих других языках выделяет пространство для объекта, который строится; в Python это задание метода распределителя, __new__()
. __init__()
- это только метод инициализации.
Ответ 3
В Python создается объект __new__
, и этот общий объект по умолчанию изменяется __init__
. И __init__
- обычный метод. В частности, это можно назвать практически, и вызывающие методы из __init__
называет их практически.
В С++ необработанная память для объекта выделяется каким-то образом, статически или в стеке вызовов или динамически через operator new
или как часть другого объекта. Затем конструктор типа, который вы создаете, инициализирует необработанную память подходящими значениями. Конструктор для данного класса автоматически вызывает конструкторы базовых классов и членов, поэтому построение гарантируется конструкцией "снизу вверх", делая части сначала.
С++ добавляет поддержку языка для двух особенно важных аспектов идеи построения из частей:
- Если конструктор выходит из строя (путем исключения исключения), то части, которые были успешно созданы, автоматически уничтожаются, а память для объекта автоматически освобождается.
- Во время выполнения тела конструктора типа
T
объект имеет тип T
, поэтому вызовы виртуальных методов будут разрешаться, как если бы объект имел тип T
(который он есть, при этом point), где T
может быть базовым классом класса, который вы создали.
Первая точка означает, что с правильно спроектированным классом С++, когда у вас есть объект под рукой, он гарантированно применим как есть. Если конструкция завершится неудачей, вы просто не окажетесь под рукой.
Кроме того, правила С++ предназначены для обеспечения того, что для каждого объекта большинства производного класса T
существует один и только один вызов конструктора T
. Я называл это единственной гарантией вызова конструктора. Он не указывается как таковое в стандартном месте, и вы можете сфокусировать его, используя очень низкоуровневые возможности языка, но там, там, для чего разработаны подробные правила стандарта (он почти такой же, как вы выиграли 't найти какое-либо одно правило о завершении с запятой-завершение инструкций, но все бесчисленные правила синтаксиса для различных операторов сговариваются, чтобы получить простое правило высокого уровня).
Гарантия единственного конструктора, а также автоматическая очистка и изменение типа объекта в качестве конструкторов базовых классов, возможно, являются тремя наиболее важными отличиями от конструкции объекта Python.
Гораздо многое предстоит сказать, но я думаю, что это самые важные идеи.
Приветствия и hth.,