6

General Question: What is the easiest/"most pythonic" way to initialize a child class exactly as its parent, but adding a single attribute?

My specific question: I'd like to extend an (Urwid) Edit object to include a single additional attribute, my_attribute; I've copied the original signature into __init__ and super().__init__, but there are a few undefined parameters/constants (LEFT, SPACE) in the signature and I don't understand how they're set in the parent class. Below are my (breaking) class definition and the parent init method:

class MyEdit(urwid.Edit):

    def __init__(self, my_attribute, caption="", edit_text="", multiline=False, align=LEFT, wrap=SPACE, allow_tab=False, edit_pos=None, layout=None, mask=None):

        super().__init__(caption="", edit_text="", multiline=False, align=LEFT, wrap=SPACE, allow_tab=False, edit_pos=None, layout=None, mask=None)
        self.my_attribute = []    
        # super().__super.__init__("", align, wrap, layout)

    def my_method(self):
        #some code that modifies my_attribute
        return self.my_attribute




class Edit(Text):
    """
    Text editing widget implements cursor movement, text insertion and
    deletion.  A caption may prefix the editing area.  Uses text class
    for text layout.

    Users of this class to listen for ``"change"`` events
    sent when the value of edit_text changes.  See :func:``connect_signal``.
    """
    # (this variable is picked up by the MetaSignals metaclass)
    signals = ["change"]

    def valid_char(self, ch):
        """
        Filter for text that may be entered into this widget by the user

        :param ch: character to be inserted
        :type ch: bytes or unicode

        This implementation returns True for all printable characters.
        """
        return is_wide_char(ch,0) or (len(ch)==1 and ord(ch) >= 32)

    def selectable(self): return True

    def __init__(self, caption="", edit_text="", multiline=False,
            align=LEFT, wrap=SPACE, allow_tab=False,
            edit_pos=None, layout=None, mask=None):
        """
        :param caption: markup for caption preceeding edit_text, see
                        :class:`Text` for description of text markup.
        :type caption: text markup
        :param edit_text: initial text for editing, type (bytes or unicode)
                          must match the text in the caption
        :type edit_text: bytes or unicode
        :param multiline: True: 'enter' inserts newline  False: return it
        :type multiline: bool
        :param align: typically 'left', 'center' or 'right'
        :type align: text alignment mode
        :param wrap: typically 'space', 'any' or 'clip'
        :type wrap: text wrapping mode
        :param allow_tab: True: 'tab' inserts 1-8 spaces  False: return it
        :type allow_tab: bool
        :param edit_pos: initial position for cursor, None:end of edit_text
        :type edit_pos: int
        :param layout: defaults to a shared :class:`StandardTextLayout` instance
        :type layout: text layout instance
        :param mask: hide text entered with this character, None:disable mask
        :type mask: bytes or unicode

        >>> Edit()
        <Edit selectable flow widget '' edit_pos=0>
        >>> Edit("Y/n? ", "yes")
        <Edit selectable flow widget 'yes' caption='Y/n? ' edit_pos=3>
        >>> Edit("Name ", "Smith", edit_pos=1)
        <Edit selectable flow widget 'Smith' caption='Name ' edit_pos=1>
        >>> Edit("", "3.14", align='right')
        <Edit selectable flow widget '3.14' align='right' edit_pos=4>
        """

        self.__super.__init__("", align, wrap, layout)
        self.multiline = multiline
        self.allow_tab = allow_tab
        self._edit_pos = 0
        self.set_caption(caption)
        self.set_edit_text(edit_text)
        if edit_pos is None:
            edit_pos = len(edit_text)
        self.set_edit_pos(edit_pos)
        self.set_mask(mask)
        self._shift_view_to_cursor = False
anon01
  • 10,618
  • 8
  • 35
  • 58
  • I don't see any problems with this code. Is there an error? – Primusa Apr 14 '18 at 19:20
  • @Primusa `name 'LEFT' is not defined` – anon01 Apr 14 '18 at 19:22
  • @Primusa I think this must be set from the parent classes super, but I'm not knowledgeable about inheriting two generations up :) – anon01 Apr 14 '18 at 19:23
  • So, did you define it? It is indeed not defined in this code. This doesn't appear to have anything to do with inheritance though. (Also, your Edit class appears to be completely irrelevant so I don't know why you posted it.) – Daniel Roseman Apr 14 '18 at 19:23
  • is it a keyword argument in the parent class? – Primusa Apr 14 '18 at 19:24
  • @DanielRoseman You can observe that I have simply copy/pasted the signature from the parent class. I have no problem defining a parent object without defining those parameters; I don't know why it's a problem to define a child object without them. – anon01 Apr 14 '18 at 19:35
  • @DanielRoseman that's the `urwid.Edit` class, not mine – anon01 Apr 14 '18 at 19:35
  • 1
    But LEFT *is* defined in the urwid module. It is not defined in your module. If you want to use it in yours, you need to reference `urwid.LEFT` or import it explicitly. Again, this is to do with Python scope, not with inheritance. – Daniel Roseman Apr 14 '18 at 19:40
  • @DanielRoseman ok - that's helpful! – anon01 Apr 14 '18 at 21:48
  • Note that the recommended approach for [customizing existing widgets is to use `widget.WidgetWrap`](http://urwid.org/manual/widgets.html#modifying-existing-widgets), if you don't have highly coupled logic with it. – Elias Dorneles Apr 16 '18 at 16:15

1 Answers1

11

You don't use those variables so just blindly pass them through.

class MyEdit(urwid.Edit):

    def __init__(self, my_attribute, *args, **kw):
        super().__init__(*args, **kw)
        self.my_attribute = []    

    def my_method(self):
        #some code that modifies my_attribute
        return self.my_attribute
tdelaney
  • 73,364
  • 6
  • 83
  • 116
  • Can you *always* use `*args`, `**kwargs` to copy a parent signature, as you've done? – anon01 Apr 14 '18 at 19:26
  • 1
    Mostly... if you are doing multiple inheritance then you have to worry about which data should go to which initializer. But its used often for your specific use case where you don't want to dig around figuring out default parameters in the parent. – tdelaney Apr 14 '18 at 19:46