Если я привяжу супер к другому имени, почему это другое имя ведет себя так? [Дубликат]

Хммм ... Я бы почти поклялся, что это сработало для оригинальной оболочки Bourne, но сейчас у меня нет доступа к текущей копии.

Существует, однако, очень тривиальный обходной путь к проблеме.

Измените первую строку сценария:

#!/bin/bash

на

#!/bin/ksh

Et voila! Чтение в конце конвейера работает отлично, если у вас установлена ​​оболочка Korn.

131
задан Martijn Pieters 10 April 2014 в 17:23
поделиться

1 ответ

Новое поведение магии super() было добавлено во избежание нарушения D.R.Y. (Не повторяйте себя), см. PEP 3135 . Чтобы явно указать класс, ссылаясь на него как на глобальный, также подвержены тем же проблемам перезаписи, которые вы обнаружили с помощью самого super():

class Foo(Bar):
    def baz(self):
        return super(Foo, self).baz() + 42

Spam = Foo
Foo = something_else()

Spam().baz()  # liable to blow up

То же самое относится к использованию декораторов классов, где декоратор возвращает новый объект, который перепроверяет имя класса:

@class_decorator_returning_new_class
class Foo(Bar):
    def baz(self):
        # Now `Foo` is a *different class*
        return super(Foo, self).baz() + 42

Магическая ячейка super() __class__ уклоняется от этих проблем, предоставляя вам доступ к исходному объекту класса.

PEP был выпущен Guido, который изначально предполагал super стать ключевым словом , а идея использования ячейки для поиска текущего класса была также его . Конечно, идея сделать это ключевым словом была частью первого черновика PEP .

Однако на самом деле сам Гвидо, который затем отступил от ключевое слово как «слишком магическое» , предлагая вместо этого текущую реализацию. Он предположил, что использование другого имени для super() может быть проблемой :

В моем патче используется промежуточное решение: предполагается, что вам нужно __class__ всякий раз, когда вы используете переменную с именем 'super'. Таким образом, если вы (глобально) переименуете super в supper и используете supper, но не super, он не будет работать без аргументов (но он все равно будет работать, если вы передадите его либо __class__, либо фактическое объект класса); если у вас есть несвязанная переменная с именем super, все будет работать, но метод будет использовать несколько более медленный путь вызова, используемый для переменных ячейки.

Итак, в конце концов, это был сам Гвидо что с использованием ключевого слова super не было правильно, и что предоставление магии __class__ ячейки было приемлемым компромиссом.

Я согласен с тем, что магическое, неявное поведение реализации несколько удивительно, но super() является одной из самых неправильно применяемых функций на языке. Просто взгляните на все неправильные super(type(self), self) или super(self.__class__, self) вызовы, найденные в Интернете; если какой-либо из этого кода когда-либо вызывался из производного класса , у вас было бы исключение с бесконечной рекурсией . По меньшей мере упрощенный вызов super() без аргументов позволяет избежать проблемы .

Что касается переименованного super_; просто ссылку __class__ в свой метод , а также , и он снова будет работать. Ячейка создается, если вы ссылаетесь на имена super или __class__ в вашем методе:

>>> super_ = super
>>> class A(object):
...     def x(self):
...         print("No flipping")
... 
>>> class B(A):
...     def x(self):
...         __class__  # just referencing it is enough
...         super_().x()
... 
>>> B().x()
No flipping
190
ответ дан Martijn Pieters 22 August 2018 в 22:23
поделиться
  • 1
    Хорошая рецензия. Это все еще так ясно, как грязь. Вы говорите, что super () эквивалентно автоматически созданной функции типа def super(of_class=magic __class__) типа self.super(); def super(self): return self.__class__? – Charles Merriam 14 March 2014 в 18:28
  • 2
    @CharlesMerriam: Это сообщение не о том, как работает super() без аргументов; он в основном имеет дело с why , он существует. super(), в методе класса, эквивалентен super(ReferenceToClassMethodIsBeingDefinedIn, self), где ReferenceToClassMethodIsBeingDefinedIn определяется во время компиляции, прикрепляется к методу как закрытие с именем __class__, а super() будет искать как из вызывающего кадра во время выполнения. Но на самом деле вам не нужно все это знать. – Martijn Pieters♦ 14 March 2014 в 18:37
  • 3
    @CharlesMerriam: но super() нигде не близок к автоматически созданной функции , no. – Martijn Pieters♦ 14 March 2014 в 18:38
  • 4
    @ chris.leonard: ключевое предложение Ячейка создается, если вы используете super () или используете __class__ в вашем методе . Вы использовали имя super в своей функции. Компилятор видит это и добавляет закрытие __class__. – Martijn Pieters♦ 10 February 2018 в 19:27
  • 5
    @Alexey: достаточно not . type(self) дает тип current , который не совпадает с типом, на котором определен метод. Таким образом, класс Foo с методом baz нуждается в super(Foo, self).baz(), потому что он может быть подклассифицирован как class Ham(Foo):, и в этот момент type(self) есть Ham, а super(type(self), self).baz() даст вам бесконечный цикл. См. Сообщение, на которое я ссылаюсь в своем ответе: При вызове super () в производном классе я могу передать сам .__ class __? – Martijn Pieters♦ 23 February 2018 в 18:37
Другие вопросы по тегам:

Похожие вопросы: