How to add an argument to derived class's constructor

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

How to add an argument to derived class's constructor

J Barchan
This may be as much a Python question as a PyQt one.  I come from a C++ background.  I do not understand the syntax/code I need in a class I am deriving from a PyQt class to allow a new parameter to be passed to the constructor.

I see that I asked this question a long time ago at https://stackoverflow.com/questions/45999732/python3-typing-overload-and-parameters but never got an answer.

I now want to sub-class from QListWidgetItem.  That starts with these constructors:

QListWidgetItem(QListWidget *parent = nullptr, int type = Type)
QListWidgetItem(const QString &text, QListWidget *parent = nullptr, int type = Type)
QListWidgetItem(const QIcon &icon, const QString &text, QListWidget *parent = nullptr, int type = Type)
QListWidgetItem(const QListWidgetItem &other)

My sub-class should still support these constructors.  In addition to the existing text, I want my sub-class to be able to store a new optional value. At minimum/sufficient I want a new possible constructor like one of the following:

MyListWidgetItem(const QString &text, const QVariant &value, QListWidget *parent = nullptr, int type = Type)
# or
MyListWidgetItem(const QString &text, QVariant value = QVariant(), QListWidget *parent = nullptr, int type = Type)

So for Python I know I start with a typing overload definition (for my editor) like

@typing.overload
def MyListWidgetItem(self, text: str, value: typing.Any, parent: QListWidget=None, type: int=Type)
    pass

Then I get to the definition bit.  To cater for everything am I supposed to do:

def __init__(self, *__args)
    # Now what??
    super().__init__(__args)

Is that how we do it?  Is it then my responsibility to look at __args[1] to see if it's my value argument?  And remove it from __args before passing it onto super().__init__(__args)?

Or, am I not supposed to deal with __args, and instead have some definition with all possible parameters explicitly and deal with them like that?

Or what?  This is pretty fundamental to sub-classing to add parameters where you don't own the code of what you're deriving from.  It's easy in C-type languages; I'm finding it real to hard to understand what I can/can't/am supposed to do for this, I'd be really gratefully for a couple of lines to show me, please...! :)

--
Kindest,
Jonathan

_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Re: How to add an argument to derived class's constructor

J Barchan


On Thu, 14 Feb 2019 at 13:34, J Barchan <[hidden email]> wrote:
This may be as much a Python question as a PyQt one.  I come from a C++ background.  I do not understand the syntax/code I need in a class I am deriving from a PyQt class to allow a new parameter to be passed to the constructor.

I see that I asked this question a long time ago at https://stackoverflow.com/questions/45999732/python3-typing-overload-and-parameters but never got an answer.

I now want to sub-class from QListWidgetItem.  That starts with these constructors:

QListWidgetItem(QListWidget *parent = nullptr, int type = Type)
QListWidgetItem(const QString &text, QListWidget *parent = nullptr, int type = Type)
QListWidgetItem(const QIcon &icon, const QString &text, QListWidget *parent = nullptr, int type = Type)
QListWidgetItem(const QListWidgetItem &other)

My sub-class should still support these constructors.  In addition to the existing text, I want my sub-class to be able to store a new optional value. At minimum/sufficient I want a new possible constructor like one of the following:

MyListWidgetItem(const QString &text, const QVariant &value, QListWidget *parent = nullptr, int type = Type)
# or
MyListWidgetItem(const QString &text, QVariant value = QVariant(), QListWidget *parent = nullptr, int type = Type)

So for Python I know I start with a typing overload definition (for my editor) like

@typing.overload
def MyListWidgetItem(self, text: str, value: typing.Any, parent: QListWidget=None, type: int=Type)
    pass

Then I get to the definition bit.  To cater for everything am I supposed to do:

def __init__(self, *__args)
    # Now what??
    super().__init__(__args)

Is that how we do it?  Is it then my responsibility to look at __args[1] to see if it's my value argument?  And remove it from __args before passing it onto super().__init__(__args)?

Or, am I not supposed to deal with __args, and instead have some definition with all possible parameters explicitly and deal with them like that?

Or what?  This is pretty fundamental to sub-classing to add parameters where you don't own the code of what you're deriving from.  It's easy in C-type languages; I'm finding it real to hard to understand what I can/can't/am supposed to do for this, I'd be really gratefully for a couple of lines to show me, please...! :)

--
Kindest,
Jonathan

P.S.
I think I got my overload a bit mixed up.  I meant I (think I) will have:

class MyListWidgetItem(QListWidgetItem)
    @typing.overload
    def __init__(self, text: str, value: typing.Any, parent: QListWidget=None, type: int=Type)
        pass

    def __init__(self, *__args)
        # Now what??
        super().__init__(__args)


--
Kindest,
Jonathan

_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Re: How to add an argument to derived class's constructor

Vincent Vande Vyvre-2
Le 14/02/19 à 14:56, J Barchan a écrit :


On Thu, 14 Feb 2019 at 13:34, J Barchan <[hidden email]> wrote:
This may be as much a Python question as a PyQt one.  I come from a C++ background.  I do not understand the syntax/code I need in a class I am deriving from a PyQt class to allow a new parameter to be passed to the constructor.

I see that I asked this question a long time ago at https://stackoverflow.com/questions/45999732/python3-typing-overload-and-parameters but never got an answer.

I now want to sub-class from QListWidgetItem.  That starts with these constructors:

QListWidgetItem(QListWidget *parent = nullptr, int type = Type)
QListWidgetItem(const QString &text, QListWidget *parent = nullptr, int type = Type)
QListWidgetItem(const QIcon &icon, const QString &text, QListWidget *parent = nullptr, int type = Type)
QListWidgetItem(const QListWidgetItem &other)

My sub-class should still support these constructors.  In addition to the existing text, I want my sub-class to be able to store a new optional value. At minimum/sufficient I want a new possible constructor like one of the following:

MyListWidgetItem(const QString &text, const QVariant &value, QListWidget *parent = nullptr, int type = Type)
# or
MyListWidgetItem(const QString &text, QVariant value = QVariant(), QListWidget *parent = nullptr, int type = Type)

So for Python I know I start with a typing overload definition (for my editor) like

@typing.overload
def MyListWidgetItem(self, text: str, value: typing.Any, parent: QListWidget=None, type: int=Type)
    pass

Then I get to the definition bit.  To cater for everything am I supposed to do:

def __init__(self, *__args)
    # Now what??
    super().__init__(__args)

Is that how we do it?  Is it then my responsibility to look at __args[1] to see if it's my value argument?  And remove it from __args before passing it onto super().__init__(__args)?

Or, am I not supposed to deal with __args, and instead have some definition with all possible parameters explicitly and deal with them like that?

Or what?  This is pretty fundamental to sub-classing to add parameters where you don't own the code of what you're deriving from.  It's easy in C-type languages; I'm finding it real to hard to understand what I can/can't/am supposed to do for this, I'd be really gratefully for a couple of lines to show me, please...! :)

--
Kindest,
Jonathan

P.S.
I think I got my overload a bit mixed up.  I meant I (think I) will have:

class MyListWidgetItem(QListWidgetItem)
    @typing.overload
    def __init__(self, text: str, value: typing.Any, parent: QListWidget=None, type: int=Type)
        pass

    def __init__(self, *__args)
        # Now what??
        super().__init__(__args)


--
Kindest,
Jonathan

_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt

Hi,

I use just that:

class ListItem(QListWidgetItem):
    def __init__(self, img, text, parent=None):
        super().__init__(parent)
        icon = QIcon()
        icon.addPixmap(QPixmap(img), QIcon.Normal, QIcon.Off)
        self.setIcon(icon)
        self.setText(text)

The arguments are examples, not mandatory.

Vincent


_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Re: How to add an argument to derived class's constructor

J Barchan


On Thu, 14 Feb 2019 at 14:56, Vincent Vande Vyvre <[hidden email]> wrote:
Le 14/02/19 à 14:56, J Barchan a écrit :


On Thu, 14 Feb 2019 at 13:34, J Barchan <[hidden email]> wrote:
This may be as much a Python question as a PyQt one.  I come from a C++ background.  I do not understand the syntax/code I need in a class I am deriving from a PyQt class to allow a new parameter to be passed to the constructor.

I see that I asked this question a long time ago at https://stackoverflow.com/questions/45999732/python3-typing-overload-and-parameters but never got an answer.

I now want to sub-class from QListWidgetItem.  That starts with these constructors:

QListWidgetItem(QListWidget *parent = nullptr, int type = Type)
QListWidgetItem(const QString &text, QListWidget *parent = nullptr, int type = Type)
QListWidgetItem(const QIcon &icon, const QString &text, QListWidget *parent = nullptr, int type = Type)
QListWidgetItem(const QListWidgetItem &other)

My sub-class should still support these constructors.  In addition to the existing text, I want my sub-class to be able to store a new optional value. At minimum/sufficient I want a new possible constructor like one of the following:

MyListWidgetItem(const QString &text, const QVariant &value, QListWidget *parent = nullptr, int type = Type)
# or
MyListWidgetItem(const QString &text, QVariant value = QVariant(), QListWidget *parent = nullptr, int type = Type)

So for Python I know I start with a typing overload definition (for my editor) like

@typing.overload
def MyListWidgetItem(self, text: str, value: typing.Any, parent: QListWidget=None, type: int=Type)
    pass

Then I get to the definition bit.  To cater for everything am I supposed to do:

def __init__(self, *__args)
    # Now what??
    super().__init__(__args)

Is that how we do it?  Is it then my responsibility to look at __args[1] to see if it's my value argument?  And remove it from __args before passing it onto super().__init__(__args)?

Or, am I not supposed to deal with __args, and instead have some definition with all possible parameters explicitly and deal with them like that?

Or what?  This is pretty fundamental to sub-classing to add parameters where you don't own the code of what you're deriving from.  It's easy in C-type languages; I'm finding it real to hard to understand what I can/can't/am supposed to do for this, I'd be really gratefully for a couple of lines to show me, please...! :)

--
Kindest,
Jonathan

P.S.
I think I got my overload a bit mixed up.  I meant I (think I) will have:

class MyListWidgetItem(QListWidgetItem)
    @typing.overload
    def __init__(self, text: str, value: typing.Any, parent: QListWidget=None, type: int=Type)
        pass

    def __init__(self, *__args)
        # Now what??
        super().__init__(__args)


--
Kindest,
Jonathan

_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt

Hi,

I use just that:

class ListItem(QListWidgetItem):
    def __init__(self, img, text, parent=None):
        super().__init__(parent)
        icon = QIcon()
        icon.addPixmap(QPixmap(img), QIcon.Normal, QIcon.Off)
        self.setIcon(icon)
        self.setText(text)

The arguments are examples, not mandatory.

Vincent

_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt

Hello Vincent,

Thank you for replying.  I'm afraid the suggestion you give is so significantly different from what I am asking that I don't see how it addresses it.  I could write a lot about the differences between what you show and what I am asking.  Here are some:
  • I don't see that you're adding any argument that QListWidgetItem does not already accept??  Please bear in mind there is already QListWidgetItem(const QIcon &icon, const QString &text, QListWidget *parent = nullptr, int type = Type).  I want to add a new argument.
  • Your super().__init__() is not passing anything other than parent to the base constructor, yet the base constructor accepts more arguments than that, just like your derived class does.
  • (untested) it seems to me that your code will break the existing QListWidgetItem(const QIcon &icon, const QString &text, QListWidget *parent = nullptr, int type = Type) constructor overload (i.e. what happens when I pass a QIcon() as the img parameter to your ListItem constructor?)
  • how does your code allow for the existing QListWidgetItem(const QString &text, QListWidget *parent = nullptr, int type = Type) overload
  • you are not using any typing hints so this will lose my editor's context completion
I don't know whether one of us is misunderstanding the other, or we're on different planes? :)

--
Kindest,
Jonathan

_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Re: How to add an argument to derived class's constructor

J Barchan


On Thu, 14 Feb 2019 at 17:48, J Barchan <[hidden email]> wrote:


On Thu, 14 Feb 2019 at 14:56, Vincent Vande Vyvre <[hidden email]> wrote:
Le 14/02/19 à 14:56, J Barchan a écrit :


On Thu, 14 Feb 2019 at 13:34, J Barchan <[hidden email]> wrote:
This may be as much a Python question as a PyQt one.  I come from a C++ background.  I do not understand the syntax/code I need in a class I am deriving from a PyQt class to allow a new parameter to be passed to the constructor.

I see that I asked this question a long time ago at https://stackoverflow.com/questions/45999732/python3-typing-overload-and-parameters but never got an answer.

I now want to sub-class from QListWidgetItem.  That starts with these constructors:

QListWidgetItem(QListWidget *parent = nullptr, int type = Type)
QListWidgetItem(const QString &text, QListWidget *parent = nullptr, int type = Type)
QListWidgetItem(const QIcon &icon, const QString &text, QListWidget *parent = nullptr, int type = Type)
QListWidgetItem(const QListWidgetItem &other)

My sub-class should still support these constructors.  In addition to the existing text, I want my sub-class to be able to store a new optional value. At minimum/sufficient I want a new possible constructor like one of the following:

MyListWidgetItem(const QString &text, const QVariant &value, QListWidget *parent = nullptr, int type = Type)
# or
MyListWidgetItem(const QString &text, QVariant value = QVariant(), QListWidget *parent = nullptr, int type = Type)

So for Python I know I start with a typing overload definition (for my editor) like

@typing.overload
def MyListWidgetItem(self, text: str, value: typing.Any, parent: QListWidget=None, type: int=Type)
    pass

Then I get to the definition bit.  To cater for everything am I supposed to do:

def __init__(self, *__args)
    # Now what??
    super().__init__(__args)

Is that how we do it?  Is it then my responsibility to look at __args[1] to see if it's my value argument?  And remove it from __args before passing it onto super().__init__(__args)?

Or, am I not supposed to deal with __args, and instead have some definition with all possible parameters explicitly and deal with them like that?

Or what?  This is pretty fundamental to sub-classing to add parameters where you don't own the code of what you're deriving from.  It's easy in C-type languages; I'm finding it real to hard to understand what I can/can't/am supposed to do for this, I'd be really gratefully for a couple of lines to show me, please...! :)

--
Kindest,
Jonathan

P.S.
I think I got my overload a bit mixed up.  I meant I (think I) will have:

class MyListWidgetItem(QListWidgetItem)
    @typing.overload
    def __init__(self, text: str, value: typing.Any, parent: QListWidget=None, type: int=Type)
        pass

    def __init__(self, *__args)
        # Now what??
        super().__init__(__args)


--
Kindest,
Jonathan

_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt

Hi,

I use just that:

class ListItem(QListWidgetItem):
    def __init__(self, img, text, parent=None):
        super().__init__(parent)
        icon = QIcon()
        icon.addPixmap(QPixmap(img), QIcon.Normal, QIcon.Off)
        self.setIcon(icon)
        self.setText(text)

The arguments are examples, not mandatory.

Vincent

_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt

Hello Vincent,

Thank you for replying.  I'm afraid the suggestion you give is so significantly different from what I am asking that I don't see how it addresses it.  I could write a lot about the differences between what you show and what I am asking.  Here are some:
  • I don't see that you're adding any argument that QListWidgetItem does not already accept??  Please bear in mind there is already QListWidgetItem(const QIcon &icon, const QString &text, QListWidget *parent = nullptr, int type = Type).  I want to add a new argument.
  • Your super().__init__() is not passing anything other than parent to the base constructor, yet the base constructor accepts more arguments than that, just like your derived class does.
  • (untested) it seems to me that your code will break the existing QListWidgetItem(const QIcon &icon, const QString &text, QListWidget *parent = nullptr, int type = Type) constructor overload (i.e. what happens when I pass a QIcon() as the img parameter to your ListItem constructor?)
  • how does your code allow for the existing QListWidgetItem(const QString &text, QListWidget *parent = nullptr, int type = Type) overload
  • you are not using any typing hints so this will lose my editor's context completion
I don't know whether one of us is misunderstanding the other, or we're on different planes? :)

--
Kindest,
Jonathan

May I politely try bumping this question?  I have had one answer, which as far as I understand does not work.

How exactly could/would you derive from QListWidgetItem from Python to add a "value" parameter in a constructor?   I could do it easily from C++.  It does seem to me this is at least partly a PyQt question, I've tried asking it at https://stackoverflow.com/questions/54746309/python-3-add-argument-when-subclassing-from-complex-arguments , I'm getting comments like "If PyQT makes it impossible to use common Python idioms then I can't do much about it actually <g>" and "The OP needs to have a re-think and accept that some compromises are inevitable when trying to fake c++ idioms in pure python."

This is a bit above my head.  I'm either getting a generic answer which is inadequate or no answer or told it may not be doable.  I don't understand this.  Can someone tell me how to add the argument I have in mind, or something similar (you do need to read through the precise example I am asking about), or explain why it can't be done, or something?  I should be so obliged!


--
Kindest,
Jonathan

_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Re: How to add an argument to derived class's constructor

Phil Thompson-5
On 18 Feb 2019, at 4:51 pm, J Barchan <[hidden email]> wrote:

>
>
>
> On Thu, 14 Feb 2019 at 17:48, J Barchan <[hidden email]> wrote:
>
>
> On Thu, 14 Feb 2019 at 14:56, Vincent Vande Vyvre <[hidden email]> wrote:
> Le 14/02/19 à 14:56, J Barchan a écrit :
>>
>>
>> On Thu, 14 Feb 2019 at 13:34, J Barchan <[hidden email]> wrote:
>> This may be as much a Python question as a PyQt one.  I come from a C++ background.  I do not understand the syntax/code I need in a class I am deriving from a PyQt class to allow a new parameter to be passed to the constructor.
>>
>> I see that I asked this question a long time ago at https://stackoverflow.com/questions/45999732/python3-typing-overload-and-parameters but never got an answer.
>>
>> I now want to sub-class from QListWidgetItem.  That starts with these constructors:
>>
>> QListWidgetItem(QListWidget *parent = nullptr, int type = Type)
>> QListWidgetItem(const QString &text, QListWidget *parent = nullptr, int type = Type)
>> QListWidgetItem(const QIcon &icon, const QString &text, QListWidget *parent = nullptr, int type = Type)
>> QListWidgetItem(const QListWidgetItem &other)
>>
>> My sub-class should still support these constructors.  In addition to the existing text, I want my sub-class to be able to store a new optional value.                       At minimum/sufficient I want a new possible constructor like one of the following:
>>
>> MyListWidgetItem(const QString &text, const QVariant &value, QListWidget *parent = nullptr, int type = Type)
>> # or
>> MyListWidgetItem(const QString &text, QVariant value = QVariant(), QListWidget *parent = nullptr, int type = Type)
>>
>> So for Python I know I start with a typing overload definition (for my editor) like
>>
>> @typing.overload
>> def MyListWidgetItem(self, text: str, value: typing.Any, parent: QListWidget=None, type: int=Type)
>>     pass
>>
>> Then I get to the definition bit.  To cater for everything am I supposed to do:
>>
>> def __init__(self, *__args)
>>     # Now what??
>>     super().__init__(__args)
>>
>> Is that how we do it?  Is it then my responsibility to look at __args[1] to see if it's my value argument?  And remove it from __args before passing it onto super().__init__(__args)?
>>
>> Or, am I not supposed to deal with __args, and instead have some definition with all possible parameters explicitly and deal with them like that?
>>
>> Or what?  This is pretty fundamental to sub-classing to add parameters where you don't own the code of what you're deriving from.  It's easy in C-type languages; I'm finding it real to hard to understand what I can/can't/am supposed to do for this, I'd be really gratefully for a couple of lines to show me, please...! :)
>>
>> --
>> Kindest,
>> Jonathan
>>
>> P.S.
>> I think I got my overload a bit mixed up.  I meant I (think I) will have:
>>
>> class MyListWidgetItem(QListWidgetItem)
>>     @typing.overload
>>     def __init__(self, text: str, value: typing.Any, parent: QListWidget=None, type: int=Type)
>>         pass
>>
>>     def __init__(self, *__args)
>>         # Now what??
>>         super().__init__(__args)
>>
>>
>> --
>> Kindest,
>> Jonathan
>>
>>
>> _______________________________________________
>> PyQt mailing list    
>> [hidden email]
>> https://www.riverbankcomputing.com/mailman/listinfo/pyqt
> Hi,
>
> I use just that:
>
> class ListItem(QListWidgetItem):
>     def __init__(self, img, text, parent=None):
>         super().__init__(parent)
>         icon = QIcon()
>         icon.addPixmap(QPixmap(img), QIcon.Normal, QIcon.Off)
>         self.setIcon(icon)
>         self.setText(text)
>
> The arguments are examples, not mandatory.
>
> Vincent
>
> _______________________________________________
> PyQt mailing list    [hidden email]
> https://www.riverbankcomputing.com/mailman/listinfo/pyqt
>
> Hello Vincent,
>
> Thank you for replying.  I'm afraid the suggestion you give is so significantly different from what I am asking that I don't see how it addresses it.  I could write a lot about the differences between what you show and what I am asking.  Here are some:
> • I don't see that you're adding any argument that QListWidgetItem does not already accept??  Please bear in mind there is already QListWidgetItem(const QIcon &icon, const QString &text, QListWidget *parent = nullptr, int type = Type).  I want to add a new argument.
> • Your super().__init__() is not passing anything other than parent to the base constructor, yet the base constructor accepts more arguments than that, just like your derived class does.
> • (untested) it seems to me that your code will break the existing QListWidgetItem(const QIcon &icon, const QString &text, QListWidget *parent = nullptr, int type = Type) constructor overload (i.e. what happens when I pass a QIcon() as the img parameter to your ListItem constructor?)
> • how does your code allow for the existing QListWidgetItem(const QString &text, QListWidget *parent = nullptr, int type = Type) overload
> • you are not using any typing hints so this will lose my editor's context completion
> I don't know whether one of us is misunderstanding the other, or we're on different planes? :)
>
> --
> Kindest,
> Jonathan
>
> May I politely try bumping this question?  I have had one answer, which as far as I understand does not work.
>
> How exactly could/would you derive from QListWidgetItem from Python to add a "value" parameter in a constructor?   I could do it easily from C++.  It does seem to me this is at least partly a PyQt question, I've tried asking it at https://stackoverflow.com/questions/54746309/python-3-add-argument-when-subclassing-from-complex-arguments , I'm getting comments like "If PyQT makes it impossible to use common Python idioms then I can't do much about it actually <g>" and "The OP needs to have a re-think and accept that some compromises are inevitable when trying to fake c++ idioms in pure python."
>
> This is a bit above my head.  I'm either getting a generic answer which is inadequate or no answer or told it may not be doable.  I don't understand this.  Can someone tell me how to add the argument I have in mind, or something similar (you do need to read through the precise example I am asking about), or explain why it can't be done, or something?  I should be so obliged!

I know it's not what you are asking but things get much easier if you require the value to be specified as a keyword argument...

    def __init__(self, *args, value, **kwargs):
        super().__init__(*args, **kwargs)
        print("Got value", value)

...and it makes your code more readable.

Phil
_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Re: How to add an argument to derived class's constructor

J Barchan


On Mon, 18 Feb 2019 at 17:27, Phil Thompson <[hidden email]> wrote:
On 18 Feb 2019, at 4:51 pm, J Barchan <[hidden email]> wrote:
>
>
>
> On Thu, 14 Feb 2019 at 17:48, J Barchan <[hidden email]> wrote:
>
>
> On Thu, 14 Feb 2019 at 14:56, Vincent Vande Vyvre <[hidden email]> wrote:
> Le 14/02/19 à 14:56, J Barchan a écrit :
>>
>>
>> On Thu, 14 Feb 2019 at 13:34, J Barchan <[hidden email]> wrote:
>> This may be as much a Python question as a PyQt one.  I come from a C++ background.  I do not understand the syntax/code I need in a class I am deriving from a PyQt class to allow a new parameter to be passed to the constructor.
>>
>> I see that I asked this question a long time ago at https://stackoverflow.com/questions/45999732/python3-typing-overload-and-parameters but never got an answer.
>>
>> I now want to sub-class from QListWidgetItem.  That starts with these constructors:
>>
>> QListWidgetItem(QListWidget *parent = nullptr, int type = Type)
>> QListWidgetItem(const QString &text, QListWidget *parent = nullptr, int type = Type)
>> QListWidgetItem(const QIcon &icon, const QString &text, QListWidget *parent = nullptr, int type = Type)
>> QListWidgetItem(const QListWidgetItem &other)
>>
>> My sub-class should still support these constructors.  In addition to the existing text, I want my sub-class to be able to store a new optional value.                       At minimum/sufficient I want a new possible constructor like one of the following:
>>
>> MyListWidgetItem(const QString &text, const QVariant &value, QListWidget *parent = nullptr, int type = Type)
>> # or
>> MyListWidgetItem(const QString &text, QVariant value = QVariant(), QListWidget *parent = nullptr, int type = Type)
>>
>> So for Python I know I start with a typing overload definition (for my editor) like
>>
>> @typing.overload
>> def MyListWidgetItem(self, text: str, value: typing.Any, parent: QListWidget=None, type: int=Type)
>>     pass
>>
>> Then I get to the definition bit.  To cater for everything am I supposed to do:
>>
>> def __init__(self, *__args)
>>     # Now what??
>>     super().__init__(__args)
>>
>> Is that how we do it?  Is it then my responsibility to look at __args[1] to see if it's my value argument?  And remove it from __args before passing it onto super().__init__(__args)?
>>
>> Or, am I not supposed to deal with __args, and instead have some definition with all possible parameters explicitly and deal with them like that?
>>
>> Or what?  This is pretty fundamental to sub-classing to add parameters where you don't own the code of what you're deriving from.  It's easy in C-type languages; I'm finding it real to hard to understand what I can/can't/am supposed to do for this, I'd be really gratefully for a couple of lines to show me, please...! :)
>>
>> --
>> Kindest,
>> Jonathan
>>
>> P.S.
>> I think I got my overload a bit mixed up.  I meant I (think I) will have:
>>
>> class MyListWidgetItem(QListWidgetItem)
>>     @typing.overload
>>     def __init__(self, text: str, value: typing.Any, parent: QListWidget=None, type: int=Type)
>>         pass
>>
>>     def __init__(self, *__args)
>>         # Now what??
>>         super().__init__(__args)
>>
>>
>> --
>> Kindest,
>> Jonathan
>>
>>
>> _______________________________________________
>> PyQt mailing list   
>> [hidden email]
>> https://www.riverbankcomputing.com/mailman/listinfo/pyqt
> Hi,
>
> I use just that:
>
> class ListItem(QListWidgetItem):
>     def __init__(self, img, text, parent=None):
>         super().__init__(parent)
>         icon = QIcon()
>         icon.addPixmap(QPixmap(img), QIcon.Normal, QIcon.Off)
>         self.setIcon(icon)
>         self.setText(text)
>
> The arguments are examples, not mandatory.
>
> Vincent
>
> _______________________________________________
> PyQt mailing list    [hidden email]
> https://www.riverbankcomputing.com/mailman/listinfo/pyqt
>
> Hello Vincent,
>
> Thank you for replying.  I'm afraid the suggestion you give is so significantly different from what I am asking that I don't see how it addresses it.  I could write a lot about the differences between what you show and what I am asking.  Here are some:
>       • I don't see that you're adding any argument that QListWidgetItem does not already accept??  Please bear in mind there is already QListWidgetItem(const QIcon &icon, const QString &text, QListWidget *parent = nullptr, int type = Type).  I want to add a new argument.
>       • Your super().__init__() is not passing anything other than parent to the base constructor, yet the base constructor accepts more arguments than that, just like your derived class does.
>       • (untested) it seems to me that your code will break the existing QListWidgetItem(const QIcon &icon, const QString &text, QListWidget *parent = nullptr, int type = Type) constructor overload (i.e. what happens when I pass a QIcon() as the img parameter to your ListItem constructor?)
>       • how does your code allow for the existing QListWidgetItem(const QString &text, QListWidget *parent = nullptr, int type = Type) overload
>       • you are not using any typing hints so this will lose my editor's context completion
> I don't know whether one of us is misunderstanding the other, or we're on different planes? :)
>
> --
> Kindest,
> Jonathan
>
> May I politely try bumping this question?  I have had one answer, which as far as I understand does not work.
>
> How exactly could/would you derive from QListWidgetItem from Python to add a "value" parameter in a constructor?   I could do it easily from C++.  It does seem to me this is at least partly a PyQt question, I've tried asking it at https://stackoverflow.com/questions/54746309/python-3-add-argument-when-subclassing-from-complex-arguments , I'm getting comments like "If PyQT makes it impossible to use common Python idioms then I can't do much about it actually <g>" and "The OP needs to have a re-think and accept that some compromises are inevitable when trying to fake c++ idioms in pure python."
>
> This is a bit above my head.  I'm either getting a generic answer which is inadequate or no answer or told it may not be doable.  I don't understand this.  Can someone tell me how to add the argument I have in mind, or something similar (you do need to read through the precise example I am asking about), or explain why it can't be done, or something?  I should be so obliged!

I know it's not what you are asking but things get much easier if you require the value to be specified as a keyword argument...

    def __init__(self, *args, value, **kwargs):
        super().__init__(*args, **kwargs)
        print("Got value", value)

...and it makes your code more readable.

Phil

Thank you for responding.  Ahh, maybe we're getting somewhere...! :)

So, you're suggesting I forget about positional and add an optional value=... keyword argument?  So instead of calling it like:
addItem(MyListWidgetItem(text, value))
caller will go:
addItem(MyListWidgetItem(text, value=value))
I guess that's not too bad.  I'm not used to this at all, it's not how I'd do it in C++!

So I'm looking at your definition closely:

     def __init__(self, *args, value, **kwargs):
        super().__init__(*args, **kwargs)
        print("Got value", value)


So putting that value after the *args and before the **kwargs makes it so it is a specifically-named argument, is that what is going on?  I was thinking I'd have to search/index/remove from the **kwargs to find my named parameter, this seems nicer....

So this is how you would do it (simplest/best) if you were me and wanted to add this value parameter?


--
Kindest,
Jonathan

_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Re: How to add an argument to derived class's constructor

Phil Thompson-5
On 18 Feb 2019, at 5:58 pm, J Barchan <[hidden email]> wrote:

>
>
>
> On Mon, 18 Feb 2019 at 17:27, Phil Thompson <[hidden email]> wrote:
> On 18 Feb 2019, at 4:51 pm, J Barchan <[hidden email]> wrote:
> >
> >
> >
> > On Thu, 14 Feb 2019 at 17:48, J Barchan <[hidden email]> wrote:
> >
> >
> > On Thu, 14 Feb 2019 at 14:56, Vincent Vande Vyvre <[hidden email]> wrote:
> > Le 14/02/19 à 14:56, J Barchan a écrit :
> >>
> >>
> >> On Thu, 14 Feb 2019 at 13:34, J Barchan <[hidden email]> wrote:
> >> This may be as much a Python question as a PyQt one.  I come from a C++ background.  I do not understand the syntax/code I need in a class I am deriving from a PyQt class to allow a new parameter to be passed to the constructor.
> >>
> >> I see that I asked this question a long time ago at https://stackoverflow.com/questions/45999732/python3-typing-overload-and-parameters but never got an answer.
> >>
> >> I now want to sub-class from QListWidgetItem.  That starts with these constructors:
> >>
> >> QListWidgetItem(QListWidget *parent = nullptr, int type = Type)
> >> QListWidgetItem(const QString &text, QListWidget *parent = nullptr, int type = Type)
> >> QListWidgetItem(const QIcon &icon, const QString &text, QListWidget *parent = nullptr, int type = Type)
> >> QListWidgetItem(const QListWidgetItem &other)
> >>
> >> My sub-class should still support these constructors.  In addition to the existing text, I want my sub-class to be able to store a new optional value.                       At minimum/sufficient I want a new possible constructor like one of the following:
> >>
> >> MyListWidgetItem(const QString &text, const QVariant &value, QListWidget *parent = nullptr, int type = Type)
> >> # or
> >> MyListWidgetItem(const QString &text, QVariant value = QVariant(), QListWidget *parent = nullptr, int type = Type)
> >>
> >> So for Python I know I start with a typing overload definition (for my editor) like
> >>
> >> @typing.overload
> >> def MyListWidgetItem(self, text: str, value: typing.Any, parent: QListWidget=None, type: int=Type)
> >>     pass
> >>
> >> Then I get to the definition bit.  To cater for everything am I supposed to do:
> >>
> >> def __init__(self, *__args)
> >>     # Now what??
> >>     super().__init__(__args)
> >>
> >> Is that how we do it?  Is it then my responsibility to look at __args[1] to see if it's my value argument?  And remove it from __args before passing it onto super().__init__(__args)?
> >>
> >> Or, am I not supposed to deal with __args, and instead have some definition with all possible parameters explicitly and deal with them like that?
> >>
> >> Or what?  This is pretty fundamental to sub-classing to add parameters where you don't own the code of what you're deriving from.  It's easy in C-type languages; I'm finding it real to hard to understand what I can/can't/am supposed to do for this, I'd be really gratefully for a couple of lines to show me, please...! :)
> >>
> >> --
> >> Kindest,
> >> Jonathan
> >>
> >> P.S.
> >> I think I got my overload a bit mixed up.  I meant I (think I) will have:
> >>
> >> class MyListWidgetItem(QListWidgetItem)
> >>     @typing.overload
> >>     def __init__(self, text: str, value: typing.Any, parent: QListWidget=None, type: int=Type)
> >>         pass
> >>
> >>     def __init__(self, *__args)
> >>         # Now what??
> >>         super().__init__(__args)
> >>
> >>
> >> --
> >> Kindest,
> >> Jonathan
> >>
> >>
> >> _______________________________________________
> >> PyQt mailing list    
> >> [hidden email]
> >> https://www.riverbankcomputing.com/mailman/listinfo/pyqt
> > Hi,
> >
> > I use just that:
> >
> > class ListItem(QListWidgetItem):
> >     def __init__(self, img, text, parent=None):
> >         super().__init__(parent)
> >         icon = QIcon()
> >         icon.addPixmap(QPixmap(img), QIcon.Normal, QIcon.Off)
> >         self.setIcon(icon)
> >         self.setText(text)
> >
> > The arguments are examples, not mandatory.
> >
> > Vincent
> >
> > _______________________________________________
> > PyQt mailing list    [hidden email]
> > https://www.riverbankcomputing.com/mailman/listinfo/pyqt
> >
> > Hello Vincent,
> >
> > Thank you for replying.  I'm afraid the suggestion you give is so significantly different from what I am asking that I don't see how it addresses it.  I could write a lot about the differences between what you show and what I am asking.  Here are some:
> >       • I don't see that you're adding any argument that QListWidgetItem does not already accept??  Please bear in mind there is already QListWidgetItem(const QIcon &icon, const QString &text, QListWidget *parent = nullptr, int type = Type).  I want to add a new argument.
> >       • Your super().__init__() is not passing anything other than parent to the base constructor, yet the base constructor accepts more arguments than that, just like your derived class does.
> >       • (untested) it seems to me that your code will break the existing QListWidgetItem(const QIcon &icon, const QString &text, QListWidget *parent = nullptr, int type = Type) constructor overload (i.e. what happens when I pass a QIcon() as the img parameter to your ListItem constructor?)
> >       • how does your code allow for the existing QListWidgetItem(const QString &text, QListWidget *parent = nullptr, int type = Type) overload
> >       • you are not using any typing hints so this will lose my editor's context completion
> > I don't know whether one of us is misunderstanding the other, or we're on different planes? :)
> >
> > --
> > Kindest,
> > Jonathan
> >
> > May I politely try bumping this question?  I have had one answer, which as far as I understand does not work.
> >
> > How exactly could/would you derive from QListWidgetItem from Python to add a "value" parameter in a constructor?   I could do it easily from C++.  It does seem to me this is at least partly a PyQt question, I've tried asking it at https://stackoverflow.com/questions/54746309/python-3-add-argument-when-subclassing-from-complex-arguments , I'm getting comments like "If PyQT makes it impossible to use common Python idioms then I can't do much about it actually <g>" and "The OP needs to have a re-think and accept that some compromises are inevitable when trying to fake c++ idioms in pure python."
> >
> > This is a bit above my head.  I'm either getting a generic answer which is inadequate or no answer or told it may not be doable.  I don't understand this.  Can someone tell me how to add the argument I have in mind, or something similar (you do need to read through the precise example I am asking about), or explain why it can't be done, or something?  I should be so obliged!
>
> I know it's not what you are asking but things get much easier if you require the value to be specified as a keyword argument...
>
>     def __init__(self, *args, value, **kwargs):
>         super().__init__(*args, **kwargs)
>         print("Got value", value)
>
> ...and it makes your code more readable.
>
> Phil
>
> Thank you for responding.  Ahh, maybe we're getting somewhere...! :)
>
> So, you're suggesting I forget about positional and add an optional value=... keyword argument?  So instead of calling it like:
> addItem(MyListWidgetItem(text, value))
> caller will go:
> addItem(MyListWidgetItem(text, value=value))
> I guess that's not too bad.  I'm not used to this at all, it's not how I'd do it in C++!
>
> So I'm looking at your definition closely:
>
>      def __init__(self, *args, value, **kwargs):
>         super().__init__(*args, **kwargs)
>         print("Got value", value)
>
> So putting that value after the *args and before the **kwargs makes it so it is a specifically-named argument, is that what is going on?  I was thinking I'd have to search/index/remove from the **kwargs to find my named parameter, this seems nicer....
>
> So this is how you would do it (simplest/best) if you were me and wanted to add this value parameter?

Yes - and you can make it optional as well by giving it a default value.

Phil
_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt