super () печатное представление - PullRequest
0 голосов
/ 10 февраля 2020

sup = super(B, self) и sup2 = super(B, B) имеют неразличимые представления, они оба выглядят так:

<super: <class 'B'>, <B object>>

, в то время как super(B, self).spam дает связанный метод, super(B, B) работает только с методами класса, поэтому super(B, B).cls_spam(), как показано ниже. Вы не можете использовать его для обычных методов, вы получаете обычную функцию:

class A:
    @classmethod
    def cls_spam(cls):
        print('A.cls_spam: cls =', cls)

    def spam(self):
        print('A.spam: self =', self)

class B(A):
    def call_spam(self):
        sup = super(B, self)
        print('B.call_spam: sup =', sup)
        print('B.call_spam: sup.spam =', sup.spam)
        print('B.call_spam: sup.cls_spam =', sup.cls_spam)
        sup.spam()
        sup.cls_spam()

        sup2 = super(B, B)
        print('B.call_spam: sup2 =', sup2)
        print('B.call_spam: sup2.css_spam =', sup2.cls_spam)
        # can't call sup2.spam(), not without giving it self explicitly
        sup2.cls_spam()

Следующий интерактивный сеанс иллюстрирует:

>>> b = B()
>>> b.call_spam3()
B.call_spam: sup = <super: <class 'B'>, <B object>>
B.call_spam: sup.spam = <bound method A.spam of <__main__.B object at 0x108830b50>>
B.call_spam: sup.cls_spam = <bound method A.cls_spam of <class '__main__.B'>>
A.spam: self = <__main__.B object at 0x108830b50>
A.cls_spam: cls = <class '__main__.B'>
B.call_spam: sup2 = <super: <class 'B'>, <B object>>
B.call_spam: sup2.css_spam = <bound method A.cls_spam of <class '__main__.B'>>
A.cls_spam: cls = <class '__main__.B'>

super() - сложный предмет, если продемонстрированное выше поведение является документированным пониманием того, что оно мне очень поможет.

Использование Python 3.5.3, Debian GNU / Linux 9.11 (stretch)

1 Ответ

4 голосов
/ 10 февраля 2020

super() предназначен для использования как в методах класса, так и в обычных методах. В classmethod нет экземпляра, у вас есть доступ только к классу, поэтому второй аргумент super() принимает либо экземпляр, либо класс. По крайней мере, это описано в документации для super():

Если вторым аргументом является объект, isinstance(obj, type) должно быть истинным. Если второй аргумент является типом, issubclass(type2, type) должно быть истинным (, это полезно для методов класса ).

Мой жирный акцент.

Теперь Основная задача, которую super() должен выполнить, - это поиск атрибутов в списке классов Порядка разрешения методов (MRO) по заданной отправной точке. Отправной точкой является первый аргумент, но MRO должен быть взят из второго аргумента; если вы используете super() в классе Foo, вы не можете знать в это время, если Foo мог быть разделен на подклассы, что может изменить MRO второго аргумента. Таким образом, для этой цели super() отслеживает две части информации:

  1. Класс, который вы хотите использовать в качестве отправной точки для поиска (первый аргумент)
  2. Класс из которого берется MRO (тип второго аргумента, если он является экземпляром, или просто второй аргумент, если это класс).

Существует также третья часть информации, экземпляр или класс, к которому привязаны атрибуты, когда вы выполняете поиск атрибутов. Это просто второй аргумент, либо экземпляр, либо класс. Вывод repr() отражает только первые два значения , в значительной степени потому, что они «скрыты» в этом super(), без аргументов, получает свои аргументы из контекста и поэтому вы не можете, так же просто посмотрите, что является отправной точкой, или каков источник MRO, но вы можете намного легче увидеть первый аргумент метода (так self или cls).

Если вы хотите различать guish между вашими двумя super() экземплярами, вы можете вместо этого взглянуть на атрибут __self__, который представляет 3-й фрагмент информации:

>>> sup = super(B, b)
>>> sup.__self__
<__main__.B object at 0x108b4c520>
>>> sup2 = super(B, B)
>>> sup2.__self__
<class '__main__.B'>

Другой две части информации, которые вы видите в выводе repr(), это атрибуты __thisclass__ и __self_class__ соответственно:

>>> sup.__thisclass__, sup.__self_class__
(<class '__main__.B'>, <class '__main__.B'>)

Это легче заметить, когда вы используете другой класс в качестве первого аргумента :

>>> sup_a = super(A, b)
>>> sup_a
<super: <class 'A'>, <B object>>
>>> sup_a.__thisclass__, sup_a.__self_class__
(<class '__main__.A'>, <class '__main__.B'>)
...