[prev in list] [next in list] [prev in thread] [next in thread] 

List:       pykde
Subject:    Re: [PyQt] How to add an argument to derived class's constructor
From:       Phil Thompson <phil () riverbankcomputing ! com>
Date:       2019-02-18 22:23:40
Message-ID: B01F0045-7518-4947-95ED-52300CC06F18 () riverbankcomputing ! com
[Download RAW message or body]

On 18 Feb 2019, at 5:58 pm, J Barchan <jnbarchan@gmail.com> wrote:
> 
> 
> 
> On Mon, 18 Feb 2019 at 17:27, Phil Thompson <phil@riverbankcomputing.com> wrote:
> On 18 Feb 2019, at 4:51 pm, J Barchan <jnbarchan@gmail.com> wrote:
> > 
> > 
> > 
> > On Thu, 14 Feb 2019 at 17:48, J Barchan <jnbarchan@gmail.com> wrote:
> > 
> > 
> > On Thu, 14 Feb 2019 at 14:56, Vincent Vande Vyvre \
> > <vincent.vande.vyvre@telenet.be> wrote: Le 14/02/19 à 14:56, J Barchan a écrit \
> > :
> > > 
> > > 
> > > On Thu, 14 Feb 2019 at 13:34, J Barchan <jnbarchan@gmail.com> 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    
> > > PyQt@riverbankcomputing.com
> > > 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    PyQt@riverbankcomputing.com
> > 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    PyQt@riverbankcomputing.com
https://www.riverbankcomputing.com/mailman/listinfo/pyqt


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic