Это подробно описано с достаточным количеством подробностей самим Гвидо в его сообщении в блоге Order Resolution (включая две предыдущие попытки).
В вашем примере Third()
вызовет First.__init__
. Python ищет каждый атрибут в родителях класса, поскольку они перечислены слева направо. В этом случае мы ищем __init__
. Итак, если вы определите
class Third(First, Second):
...
, Python начнет с просмотра First
, и, если First
не имеет атрибута, тогда он будет смотреть на Second
.
Эта ситуация становится более сложной, когда наследование начинает пересекать пути (например, если First
унаследовано от Second
). Прочтите ссылку выше для более подробной информации, но, в двух словах, Python попытается сохранить порядок, в котором каждый класс появится в списке наследования, начиная с самого дочернего класса.
Так, например, если у вас есть:
class First(object):
def __init__(self):
print "first"
class Second(First):
def __init__(self):
print "second"
class Third(First):
def __init__(self):
print "third"
class Fourth(Second, Third):
def __init__(self):
super(Fourth, self).__init__()
print "that's it"
, MRO будет [Fourth, Second, Third, First].
. Кстати: если Python не может найти порядок согласованного метода, он вызовет исключение, вместо этого о возврате к поведению, которое может удивить пользователя.
Отредактировано, чтобы добавить пример двусмысленного MRO:
class First(object):
def __init__(self):
print "first"
class Second(First):
def __init__(self):
print "second"
class Third(First, Second):
def __init__(self):
print "third"
Если MF Third
будет [First, Second]
или [Second, First]
? Нет очевидного ожидания, и Python вызовет ошибку:
TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution order (MRO) for bases Second, First
Редактирование: я вижу, что несколько человек утверждают, что в приведенных выше примерах нет вызовов super()
, поэтому позвольте мне объяснить: точка примеров чтобы показать, как строится MRO. Они не предназначены для печати «first\nsecond \ third» или что-то еще. Вы можете - и должны, конечно, поиграть с примером, добавить super()
звонки, посмотреть, что произойдет, и получить более глубокое понимание модели наследования Python. Но моя цель состоит в том, чтобы держать его простым и показать, как строится MRO. И он построен, как я объяснил:
>>> Fourth.__mro__
(,
, ,
,
)
Все функции в C / C ++ имеют определенное соглашение о вызовах. Суть соглашения о вызовах состоит в том, чтобы установить, как данные передаются между вызывающим и вызываемым объектами и кто отвечает за такие операции, как очистка стека вызовов.
Самые популярные соглашения о вызовах в Windows:
__ stdcall
, помещает параметры в стек в обратном порядке (справа налево) __ cdecl
, помещает параметры в стек в обратном порядке (справа налево) __ clrcall
, загружать параметры в стек выражений CLR по порядку (слева направо). __ fastcall
, сохраняется в регистрах, затем помещается в стек __ thiscall
, Помещен в стек; этот указатель хранится в ECX . Добавление этого спецификатора к объявлению функции по существу сообщает компилятору, что вы хотите, чтобы эта конкретная функция имела это конкретное соглашение о вызовах.
Соглашения о вызовах описаны здесь
Рэймонд Чен также провел длинную серию статей по истории различных вызовов. соглашения (5 частей), начинающиеся здесь.
__ stdcall - это соглашение о вызовах: способ определения того, как параметры передаются в функцию (в стеке или в регистрах) и кто отвечает за очистку после возврата функции (вызывающий или вызываемый).
Раймонд Чен написал блог об основных соглашениях о вызовах x86 , а также там есть хорошая статья CodeProject .
По большей части вам не стоит о них беспокоиться. Единственный случай, в котором вы должны это сделать, - это если вы вызываете библиотечную функцию, которая использует что-то отличное от значения по умолчанию, иначе компилятор сгенерирует неправильный код и ваша программа, вероятно, выйдет из строя.
К сожалению, нет простого ответ на вопрос, когда его использовать, а когда нет.
__ stdcall означает, что аргументы функции помещаются в стек от первого до последнего. В этом отличие от __cdecl, что означает, что аргументы передаются от последнего к первому, а __fastcall,
Он определяет соглашение о вызовах для функции. Соглашение о вызовах - это набор правил того, как параметры передаются функции: в каком порядке, для каждого адреса или для каждой копии, кто должен очистить параметры (вызывающий или вызываемый) и т. Д.
__ stdcall обозначает соглашение о вызовах (см. этот PDF для некоторых деталей). Это означает, что он определяет, как аргументы функции выталкиваются и извлекаются из стека, и кто за это отвечает.
__ stdcall - это лишь одно из нескольких соглашений о вызовах, которое используется во всем WINAPI. Вы должны использовать его, если вы предоставляете указатели на функции в качестве обратных вызовов для некоторых из этих функций. В общем, вам не нужно указывать какое-либо конкретное соглашение о вызовах в вашем коде, а просто используйте значение по умолчанию компилятора, за исключением случая, указанного выше (обеспечение обратных вызовов для стороннего кода).
Это соглашение о вызовах, согласно которому функции WinAPI должны вызываться правильно. Соглашение о вызовах - это набор правил о том, как параметры передаются в функцию и как возвращаемое значение передается из функции.
Если вызывающий и вызываемый код используют разные соглашения, вы столкнетесь с неопределенным поведением (например, ] такой странный сбой ).
Компиляторы C ++ по умолчанию не используют __stdcall - они используют другие соглашения. Поэтому, чтобы вызывать функции WinAPI из C ++, вам необходимо указать, что они используют __stdcall - обычно это делается в файлах заголовков SDK Windoes, и вы также делаете это при объявлении указателей на функции.