简体   繁体   English

子类没有在Python 2.x中初始化父类

[英]Subclass not initialising parent class in Python 2.x

I'm having some problems initialising the parent class inside one subclass in Python 2. What I'm trying to do is override parent class attributes with properties in the child class. 我在Python 2中的一个子类中初始化父类时遇到了一些问题。我要做的是使用子类中的属性覆盖父类属性。

Somehow, when I don't use the method _update_rect(self) in the child class setters (eg _set_grab(self, ps_value) and _set_grab(self, ps_value) ), everything works as expected. 不知何故,当我不在子类setter中使用方法_update_rect(self)时(例如_set_grab(self, ps_value)_set_grab(self, ps_value) ),一切都按预期工作。 But as soon as I use it the initialization of the parent class fails (the print '+++ END GfxObject initialisation' is not reached) and I get AttributeError: 'GfxRect' object has no attribute '_s_grab' . 但是一旦我使用它,父类的初始化失败(未达到print '+++ END GfxObject initialisation' )并且我得到AttributeError: 'GfxRect' object has no attribute '_s_grab'

As I said at the beginning, the code looks correct to me and the problematic method _update_rect only uses real attributes of itself so I have no idea where the error comes. 正如我在开头所说,代码对我来说是正确的,有问题的方法_update_rect只使用自身的真实属性,所以我不知道错误来自哪里。 I could avoid using inheritance in the child class as a workaround but I really want to understand what the problem is. 我可以避免在子类中使用继承作为解决方法,但我真的想了解问题所在。

Regards and thanks in advance. 提前问候并表示感谢。

# 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()

UPDATE: Moving the initialisation of the parent class in the child class after the internal properties seems to fix the problem which it's even more weird for me. 更新:在内部属性似乎解决问题之后,在子类中移动父类的初始化,这对我来说更加奇怪。

Before (doesn't work) 之前(不起作用)

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()

After (works) 之后(工作)

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()

...but something wrong seems to be happening under the hood. ......但是在引擎盖下似乎发生了一些错误。 If I add print 'child class "_update_rect" called' to the _update_rect method, I get this output when running the script: 如果我在_update_rect方法中添加print 'child class "_update_rect" called' ,我在运行脚本时会得到这个输出:

--- 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
...

Which means the parent class is calling the child methods when being initialised!? 这意味着父类在初始化时调用子方法!?

UPDATE 2: It seems this is the workflow when initialising the child class. 更新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'

The problem appears in step [6] because ._s_grab attribute hasn't been created yet since the initialisation of the Child class is still initialising the Parent class. 问题出现在步骤[6]中,因为尚未创建._s_grab属性,因为Child类的初始化仍在初始化Parent类。 To me, it's counter-intuitive (and I would say that it's even a bug) the step [3]-[4] when setting the attribute .i_x of the Parent class triggers the property of the Child class. 对我来说,这是违反直觉的(我会说它甚至是一个错误)步骤[3] - [4]设置父类的属性.i_x时会触发Child类的属性。

By moving the initialisation of the parent class at the end of the child class or adding the missing attribute as a Parent class global (not to the instances), the problem disappear. 通过在子类的末尾移动父类的初始化或将缺少的属性添加为父类全局(而不是实例),问题就会消失。

Your issue is that you're trying to initialise non-existing class properties/variables (you're calling self.i_x , but you've initialised self._i_x , for example) with a method call. 您的问题是您尝试使用方法调用初始化不存在的类属性/变量(您正在调用self.i_x ,但是您已经初始化了self._i_x )。

Changing GfxObject to: 将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'

Executed script on my machine. 在我的机器上执行脚本。 Result output: 结果输出:

 $ python2 issue.py --- START GfxObject initialisation +++ END GfxObject initialisation <GfxRect> .i_x: 0 ._i_x: 0 .s_grab: nw ._s_grab: nw 

EDIT 编辑

Funny thing, once I moved i_x and s_grab from GfxObject() 's init, your code worked as a charm. 有趣的事情,有一次我感动i_xs_grabGfxObject()的初始化,您的代码工作的魅力。 Basically I only changed that class to this: 基本上我只改变了这个类:

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

So, it seems that you're expperiencing same issue I had with Python3 and @property decorator - if I didn't set an object to None or some other value before defining it as a property, it threw no attribute/not defined errors first time I'd try to use that getter/setter. 所以,看来你expperiencing同样的问题,我曾与Python3和@property装饰-如果我没有对象设置为None将其定义为一个属性之前或其他一些价值,它首先扔无属性/没有定义的错误我试着使用那个getter / setter。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM