Python super и установка свойства родительского класса

У меня действительно странная проблема с Python super(), наследованием и свойствами. Во-первых, код:

#!/usr/bin/env python3

import pyglet
import pygame

class Sprite(pyglet.sprite.Sprite):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.rect = pygame.Rect(0, 0, self.width, self.height)
        self.rect.center = self.x, self.y

    @property
    def x(self):
        return super().x

    @x.setter
    def x(self, value):
        super(Sprite, self.__class__).x.fset(self, value)
        self.rect.centerx = value

    @property
    def y(self):
        return super().y

    @y.setter
    def y(self, value):
        super(Sprite, self.__class__).y.fset(self, value)
        self.rect.centery = value

Это прекрасно работает. Однако то, что я хочу (что мне кажется Pythonic)

#super(Sprite, self.__class__).x.fset(self, value)
super().x = value

не работает, хотя

super().x

получает значение в порядке. x в этом случае является свойством суперкласса с определенными как fset, так и fget. Так почему же это не работает?


person darkfeline    schedule 30.05.2012    source источник


Ответы (2)


Я пытался найти правильный язык, чтобы подтвердить, почему это поведение такое, какое оно есть, чтобы не давать вам ответ «потому что это просто так» ... Но, похоже, этот вопрос задавали не раз, и что все сводится к поведению super(). Вы можете увидеть обсуждение этого точного поведения в 2010 году здесь: http://mail.python.org/pipermail/python-dev/2010-April/099672.html

В конечном счете, это действительно сводится к вызовам super(), которые позволяют вам напрямую обращаться к геттерам, а не к сеттерам. Доступ к сеттерам должен осуществляться через fset() или __set__(). Это, вероятно, проще всего объяснить как «функциональность super() просто не поддерживает ее». Он разрешит функциональность свойств операции «получить», а не установщика в левостороннем назначении, в операции «установить» (отсюда и вызов метода fset()). Как вы можете видеть по дате этой ветки обсуждения, очевидно, что так было с момента появления super().

Может быть, у кого-то есть более конкретно техническая причина, но, честно говоря, я не уверен, что это вообще имеет значение. Если он не поддерживается, это достаточно веская причина.

person jdi    schedule 30.05.2012
comment
Я сообщил об ошибке: bugs.python.org/issue14965 Надеюсь, это скоро будет решено, поэтому этот вопрос уже не актуально. - person darkfeline; 02.09.2012
comment
это не поддерживается ... звучит достаточно веская причина, потому что это просто так. - person simonzack; 10.12.2014
comment
@simonzack - я сказал, что пытался не давать такого ответа и объяснить как можно больше о его функциональности. - person jdi; 11.12.2014
comment
Еще одна причина избегать super - person dashesy; 04.03.2015
comment
Можете ли вы привести пример, который будет использоваться в дочернем классе? - person nmz787; 18.03.2016
comment
@nmz787 какой пример тебе нужен? мой ответ был не о том, как научить использовать super(). это было просто о том, почему супер ведет себя так, как он. В исходном вопросе есть пример использования fset - person jdi; 18.03.2016
comment
о, я не видел, чтобы ОП сказал, что это работает нормально. Однако спасибо! - person nmz787; 21.03.2016
comment
Этот ответ может быть полезен, если он действительно показывает, как получить доступ к super с помощью fset или set - person Erik Aronesty; 05.05.2020
comment
@ErikAronesty: ОП уже сделал: super(self.__class__, self.__class__).x.fset(self, value) - person MestreLion; 14.04.2021

super(type(self), type(self)).setter.fset(self, value) — распространенный обходной путь, однако он не работает должным образом с множественным наследованием, которое может изменить mro.

Попробуйте мое решение (ссылка ниже): duper(super()).setter = value

https://gist.github.com/willrazen/bef3fcb26a83dffb6692e5e10d3e67ac

person Will Razen    schedule 21.05.2021