Различия между конструкторами Python и C ++ - PullRequest
14 голосов
/ 26 октября 2010

Недавно я узнал больше о Python, и когда я проходил через превосходное Погружение в Python , автор отметил здесь , что метод __init__ технически не являетсяконструктор, хотя обычно он работает как единое целое.

У меня есть два вопроса:

  1. В чем различия между тем, как C ++ создает объект, и тем, как Python "конструирует" объектобъект?

  2. Что делает конструктор конструктором и как метод __init__ не удовлетворяет этому критерию?

Ответы [ 3 ]

15 голосов
/ 26 октября 2010

Различие, которое рисует автор, состоит в том, что для языка Python у вас есть действительный объект указанного типа до , в который вы даже вводите __init__.Следовательно, это не «конструктор», поскольку в C ++ и теоретически конструктор превращает недопустимый предварительно созданный объект в «правильный» завершенный объект типа.

В основном __new__ в Python определен каквернуть «экземпляр нового объекта», тогда как новые операторы C ++ просто возвращают некоторую память, которая еще не является экземпляром какого-либо класса.

Однако, __init__ в Python, вероятно, - то, где вы сначала устанавливаете некоторые важные инварианты класса(какие атрибуты у него есть, только для начала).Таким образом, что касается пользователей вашего класса, он также может быть конструктором.Просто среда выполнения Python не заботится ни об одном из этих инвариантов.Если хотите, у него очень низкие стандарты того, что составляет построенный объект.

Я думаю, что автор делает справедливое замечание, и это, безусловно, интересное замечание о том, как Python создает объекты.Это довольно тонкое различие, и я сомневаюсь, что вызов __init__ конструктора когда-либо приведет к некорректному коду.

Также отмечу, что документация Python ссылается на __init__ как конструктор (http://docs.python.org/release/2.5.2/ref/customization.html)

Как специальное ограничение для конструкторов, никакое значение не может быть возвращено

... поэтому, если есть практические проблемы с представлением __init__ как конструктора, тогда Pythonв беде!

То, как объекты Python и C ++ имеют некоторые сходства, вызывает функцию с относительно простой ответственностью (__new__ для экземпляра объекта против некоторой версии operator new для необработанной памяти),затем оба вызывают функцию, которая имеет возможность проделать дополнительную работу для инициализации объекта в полезное состояние (__init__ по сравнению с конструктором).

Практические различия включают в себя:

  • в C ++, конструкторы без аргументов для базовых классов при необходимости вызываются автоматически в соответствующем порядке, тогда как для __init__ в Python вы должныявно инициируйте свою базу в своем собственном __init__.Даже в C ++ вы должны указать конструктор базового класса, если он имеет аргументы.

  • в C ++, у вас есть целый механизм для того, что происходит, когда конструктор выдает исключение, с точки зрениявызов деструкторов для уже созданных подобъектов.Я думаю, что в Python среда выполнения (самое большее) вызывает __del__.

Кроме того, есть разница, что __new__ не просто выделяет память, этодолжен вернуть фактический экземпляр объекта.Опять же, необработанная память не является концепцией, которая применима к коду Python.

3 голосов
/ 26 октября 2010

В Python объект создается с помощью __new__, и этот тип общего объекта по умолчанию изменяется с помощью __init__. И __init__ это просто обычный метод. В частности, он может вызываться виртуально, а вызов методов из __init__ вызывает их виртуально.

В C ++ необработанная память для объекта выделяется каким-либо образом, статически, или в стеке вызовов, или динамически через operator new, или как часть другого объекта. Затем конструктор для создаваемого вами типа инициализирует необработанную память подходящими значениями. Конструктор для данного класса автоматически вызывает конструкторы базовых классов и членов, поэтому конструкции гарантируется конструкция "снизу вверх", в которой сначала создаются детали.

C ++ добавляет языковую поддержку для двух особенно важных аспектов идеи построения из частей:

  • Если конструктор дает сбой (выбрасывая исключение), то части, которые были успешно сконструированы, автоматически уничтожаются, а память для объекта освобождается автоматически.
  • Во время выполнения тела конструктора типа T объект относится к типу T, поэтому вызовы виртуальных методов разрешаются так, как если бы объект имел тип T (что на самом деле точка), где T может быть базовым классом класса, который вы создали.

Первый пункт означает, что с правильно разработанным классом C ++, когда у вас есть объект под рукой, он гарантированно будет использоваться как есть. Если конструкция терпит неудачу, то вы просто не получите под рукой какой-либо предмет.

Кроме того, правила C ++ предназначены для обеспечения того, чтобы для каждого объекта самого производного класса T был один и только один вызов конструктора T. Раньше я называл это гарантия вызова одного конструктора . Это место не указано в качестве такового в стандарте, и вы можете помешать ему, используя очень низкоуровневые средства языка, но оно есть, это то, для чего предназначены подробные правила стандарта (это почти то же самое, что вы выиграли Не найдено ни одного единственного правила о точках с запятой в конце операторов, но все бесчисленные правила синтаксиса для различных операторов приводят к получению простого правила высокого уровня).

Гарантия единого вызова конструктора, гарантия автоматической очистки и изменение типа объекта в качестве конструкторов базовых классов, возможно, являются тремя наиболее важными отличиями от конструкции объекта Python.

Можно сказать гораздо больше, но я думаю, что это самые важные идеи.

Приветствия и hth.,

2 голосов
/ 26 октября 2010

Конструктор во многих других языках выделяет пространство для конструируемого объекта;в Python это работа метода распределителя, __new__().__init__() это просто метод инициализатора.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...