'Python super and setting parent class property
I'm having a really strange problem with Python super() and inheritance and properties. First, the code:
#!/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
This works fine. However, what I want (what seems Pythonic to me)
#super(Sprite, self.__class__).x.fset(self, value)
super().x = value
doesn't work even though
super().x
gets the value fine. x in this case is a property of the superclass with both fset and fget defined. So why doesn't it work?
Solution 1:[1]
super(type(self), type(self)).setter.fset(self, value)
is a common workaround; however it doesn't work adequately with multiple inheritance, which can change the MRO (Method Resolution Order).
Try using my duper class: duper(super()).setter = value
class duper:
"""Super wrapper which allows property setting & deletion.
Super can't be subclassed with empty __init__ arguments.
Works with multiple inheritance.
References:
https://mail.python.org/pipermail/python-dev/2010-April/099672.html
https://bugs.python.org/issue14965
https://bugs.python.org/file37546/superprop.py
Usage: duper(super())
"""
def __init__(self, osuper):
object.__setattr__(self, 'osuper', osuper)
def _find(self, name):
osuper = object.__getattribute__(self, 'osuper')
if name != '__class__':
mro = iter(osuper.__self_class__.__mro__)
for cls in mro:
if cls == osuper.__thisclass__:
break
for cls in mro:
if isinstance(cls, type):
try:
return object.__getattribute__(cls, name)
except AttributeError:
pass
return None
def __getattr__(self, name):
return getattr(object.__getattribute__(self, 'osuper'), name)
def __setattr__(self, name, value):
osuper = object.__getattribute__(self, 'osuper')
desc = object.__getattribute__(self, '_find')(name)
if hasattr(desc, '__set__'):
return desc.__set__(osuper.__self__, value)
return setattr(osuper, name, value)
def __delattr__(self, name):
osuper = object.__getattribute__(self, 'osuper')
desc = object.__getattribute__(self, '_find')(name)
if hasattr(desc, '__delete__'):
return desc.__delete__(osuper.__self__)
return delattr(osuper, name)
(full source https://gist.github.com/willrazen/bef3fcb26a83dffb6692e5e10d3e67ac)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | SuperStormer |