Хочу поделиться некоторыми наблюдениями по этому поводу.
Вызов self.get_dough()
может быть невозможен, если вы переопределяете метод get_dough()
родительского класса, как здесь:
class AbdullahStore(DoughFactory):
def get_dough(self):
return 'Abdullah`s special ' + super().get_dough()
Я думаю, что это частый сценарий на практике. Если мы вызовем DoughFactory.get_dough(self)
напрямую, то поведение будет исправлено. Класс, производный от AbdullahStore
, должен будет переопределить полный метод и не сможет повторно использовать «добавленное значение» AbdullahStore
. С другой стороны, если мы используем super.get_dough(self)
, это напоминает шаблон: в любом классе, производном от AbdullahStore
, скажем
class Kebab(AbdullahStore):
def order_kebab(self, sauce):
dough = self.get_dough()
print('Making kebab with %s and %s sauce' % (dough, sauce))
мы можем «создать экземпляр» get_dough()
, используемого в AbdullahStore
, по-разному, перехватив его в MRO следующим образом
class OrganicKebab(Kebab, OrganicDoughFactory):pass
Вот что он делает:
Kebab().order_kebab('spicy')
Making kebab with Abdullah`s special insecticide treated wheat dough and spicy sauce
OrganicKebab().order_kebab('spicy')
Making kebab with Abdullah`s special pure untreated wheat dough and spicy sauce
Поскольку OrganicDoughFactory
имеет одного родителя DoughFactory
, он гарантированно будет вставлен в MRO прямо перед DoughFactory
и, таким образом, переопределяет его методы для всех предшествующих классов в MRO. Мне потребовалось некоторое время, чтобы понять алгоритм линеаризации C3, используемый для построения MRO. Проблема в том, что два правила
children come before parents
parents order is preserved
из этой ссылки https://rhettinger.wordpress.com/2011/05/26/super-considered-super/ еще не определили порядок однозначно. В иерархии классов
D->C->B->A
\ /
--E--
(класс A; класс B(A); класс C(B); класс E(A); класс D(C,E)) где E будет вставлен в MRO? Это DCBEA или DCEBA? Возможно, прежде чем можно будет уверенно отвечать на подобные вопросы, не стоит начинать везде вставлять super
. Я все еще не совсем уверен, но я думаю, что линеаризация C3, которая является однозначной и будет выбирать порядок DCBEA в этом примере, действительно позволяет нам выполнить трюк с перехватом так, как мы это сделали, однозначно.
Теперь, я полагаю, вы можете предсказать результат
class KebabNPizza(Kebab, OrganicPizza): pass
KebabNPizza().order_kebab('hot')
который является улучшенным шашлыком:
Making kebab with Abdullah`s special pure untreated wheat dough and hot sauce
Но, вероятно, вам потребовалось некоторое время, чтобы вычислить.
Когда я впервые просмотрел super
документов https://docs.python.org/3.5/library/functions.html?highlight=super#super слабый назад, исходящий из опыта работы с C++, это было похоже на «вау, хорошо, вот правила, но как это может когда-либо работать, а не ударить тебя в спину?». Теперь я больше разбираюсь в этом, но все равно неохота везде вставлять super
. Я думаю, что большая часть кодовой базы, которую я видел, делает это только потому, что super()
удобнее набирать, чем имя базового класса. И это даже не говоря об экстремальном использовании super()
в цепочке __init__
функций. Что я наблюдаю на практике, так это то, что все пишут конструкторы с удобной для класса (а не универсальной) сигнатурой и используют super()
для вызова того, что они считают своим конструктором базового класса.
person
Alexander Shekhovtsov
schedule
02.12.2017
self
ведет себя точно так же, как и любая другая ссылка на объект. Если вы делаетеp = OrganicPizza()
, тоself.get_dough()
в любом методеp
эквивалентноp.get_dough()
, независимо от того, где в графе наследования происходит использованиеself
. Вы понимаете, что сделал быp.get_dough()
? - person user2357112 supports Monica   schedule 05.05.2015Pizzeria
/OrganicPizzeria
(аDoughFactory
все еще mix-in!) - person jonrsharpe   schedule 05.05.2015