У меня возникают некоторые проблемы с инициализацией родительского класса внутри одного подкласса в Python 2. Я пытаюсь переопределить атрибуты родительского класса со свойствами в дочернем классе.
Почему-то, когда я не использую метод _update_rect(self)
в установщиках дочерних классов (например, _set_grab(self, ps_value)
и _set_grab(self, ps_value)
), все работает как положено. Но как только я использую его, инициализация родительского класса завершается неудачно (print '+++ END GfxObject initialisation'
не достигнута), и я получаю AttributeError: 'GfxRect' object has no attribute '_s_grab'
.
Как я сказал в начале, код выглядит для меня корректно, а проблемный метод _update_rect
использует только реальные атрибуты самого себя, поэтому я понятия не имею, где возникает ошибка. Я мог бы избежать использования наследования в дочернем классе в качестве обходного пути, но я действительно хочу понять, в чем проблема.
С уважением и заранее спасибо.
# Extra code to simplify test code
#=================================
class pygame:
class Rect:
def __init__(self, x, y, w, h):
self.x = x
self.y = y
self.w = w
self.h = h
# Classes
#========
class GfxObject(object):
"""
Generic Graphical Object which is the parent class of all the sub-classes below.
"""
def __init__(self):
self.i_x = 0
self.i_y = 0
self.s_grab = 'nw'
class GfxRect(GfxObject):
"""
Class to draw a rectangle.
"""
def __init__(self):
print '--- START GfxObject initialisation'
super(GfxRect, self).__init__()
print '+++ END GfxObject initialisation'
self._i_x = 0
self._s_grab = 'nw'
self._o_rect = None
print self
self._update_rect()
def __str__(self):
return unicode(self).encode('utf8')
def __unicode__(self):
u_out = u'<GfxRect>\n'
u_out += u' .i_x: %s\n' % self.i_x
u_out += u' ._i_x: %s\n' % self._i_x
u_out += u' .s_grab: %s\n' % self.s_grab
u_out += u' ._s_grab: %s\n' % self._s_grab
return u_out
def _get_grab(self):
return self._s_grab
def _get_x(self):
return self._i_x
def _set_grab(self, ps_value):
self._s_grab = ps_value
#self._update_rect()
self._b_redraw = True
def _set_x(self, i_value):
self._i_x = i_value
self._update_rect()
self._b_redraw = True
def _update_rect(self):
"""
Method to update the pygame rectangle object.
:return:
"""
# [1/?] Calculating the deltas for (x,y) based on the grab position
#------------------------------------------------------------------
if self._s_grab == 'nw':
i_dx = 0
elif self._s_grab == 'n':
i_dx = -800 / 2
else:
raise ValueError('Invalid grab value "%s"' % self._s_grab)
# [2/?] Applying the deltas
#--------------------------
i_x = self._i_x + i_dx
self._o_rect = pygame.Rect(i_x, 0, 800, 600)
i_x = property(fget=_get_x, fset=_set_x)
s_grab = property(fget=_get_grab, fset=_set_grab)
# Main code
#==========
if __name__ == '__main__':
o_progbar = GfxRect()
ОБНОВЛЕНИЕ: Перемещение инициализации родительского класса в дочерний класс после того, как внутренние свойства, кажется, решает проблему, что для меня даже более странно.
До (не работает)
def __init__(self):
print '--- START GfxObject initialisation'
super(GfxRect, self).__init__()
print '+++ END GfxObject initialisation'
self._i_x = 0
self._s_grab = 'nw'
self._o_rect = None
self._update_rect()
После (работы)
def __init__(self):
self._i_x = 0
self._s_grab = 'nw'
self._o_rect = None
print '--- START GfxObject initialisation'
super(GfxRect, self).__init__()
print '+++ END GfxObject initialisation'
self._update_rect()
... но, похоже, что-то не так происходит под капотом. Если я добавлю print 'child class "_update_rect" called'
к методу _update_rect
, я получу этот вывод при запуске скрипта:
--- START GfxObject initialisation
child class "_update_rect" called <-- ERROR!?
child class "_update_rect" called <-- ERROR!?
+++ END GfxObject initialisation
child class "_update_rect" called <-- this is correct
...
Что означает, что родительский класс вызывает дочерние методы при инициализации!?
ОБНОВЛЕНИЕ 2: Кажется, это рабочий процесс при инициализации дочернего класса.
[1] Child.__init__()
[2] Parent.__init__()
[3] self.i_x = 0
[4] Child._set_x(0)
[5] Child._update_rect()
[6] Child._s_grab = 'foo'
Проблема появляется на шаге [6], поскольку атрибут ._s_grab
еще не создан, поскольку инициализация класса Child все еще инициализирует класс Parent. Для меня это нелогично (и я бы сказал, что это даже ошибка), шаг [3] - [4] при установке атрибута .i_x
класса Parent вызывает свойство класса Child.
Если переместить инициализацию родительского класса в конец дочернего класса или добавить отсутствующий атрибут как глобальный родительский класс (не для экземпляров), проблема исчезнет.