python - 子类未在 Python 2.x 中初始化父类
问题描述
我在 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 类。.i_x
对我来说,当设置Parent 类的属性触发 Child 类的属性时,步骤 [3]-[4] 是违反直觉的(我会说它甚至是一个错误) 。
通过在子类末尾移动父类的初始化或将缺少的属性添加为全局父类(而不是实例),问题就消失了。
解决方案
您的问题是您正在尝试使用方法调用初始化不存在的类属性/变量(例如,您正在调用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
编辑
有趣的是,一旦我移动i_x
并s_grab
从GfxObject()
's init 开始,您的代码就像一个魅力。基本上我只将该类更改为:
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
定义为属性之前没有将其设置为或其他值,那么第一次我不会抛出任何属性/未定义错误d 尝试使用该 getter/setter。
推荐阅读
- c# - 如何使用 C# 验证 SSL 证书
- delphi - Delphi 和 High-DPI:在运行时创建的控件获得错误的位置
- c++ - 如何在 Xcode 中使用 boost::multiprecision::float128
- c# - 从另一个类而不是新创建的 C# WPF 更新 Window 的当前实例
- javascript - 函数不同步运行
- java - 我们如何解决 Android Studio 中的“无法解析符号”问题?
- php - PHP | 如何使用唯一标志对数组中的值进行排序?
- assembly - 如何在 cortex m3 中进行 32*32 位乘法
- java - 如何使用 SpEL 设置注释字段以处理值
- java - 测试 bean 实例化会引发异常