我在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
属性尚未创建,因为子类的初始化仍在初始化父类。对我来说,设置父类的属性.i_x
触发子类的属性时,步骤[3]-[4]是违反直觉的(而且我什至会说这甚至是个错误)。>
通过在子类的末尾移动父类的初始化或将缺少的属性添加为全局的父类(不包括在实例中),问题消失了。
答案 0 :(得分:0)
您的问题是,您正在尝试使用方法调用来初始化不存在的类属性/变量(例如,您正在调用self.i_x
,但您已经初始化了self._i_x
)。
将GfxObject更改为:
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'
在我的机器上执行的脚本。结果输出:
$ python2 issue.py --- START GfxObject initialisation +++ END GfxObject initialisation <GfxRect> .i_x: 0 ._i_x: 0 .s_grab: nw ._s_grab: nw
EDIT
有趣的是,一旦我从i_x
的初始位置移走了s_grab
和GfxObject()
,您的代码就成了一种魅力。基本上,我只将此类更改为:
class GfxObject(object):
"""
Generic Graphical Object which is the parent class of all the sub-classes below.
"""
i_x = None
s_grab = None
def __init__(self):
# self.i_x = None
# self.s_grab = None
#self.s_grab = 'nw'
pass
因此,似乎您遇到了与Python3和@property
装饰器相同的问题-如果在将其定义为属性之前未将对象设置为None
或其他某个值,那么在我第一次尝试使用该getter / setter时,它不会引发任何属性/未定义的错误。