Re: [Tutor] super constructor usage
On 30/03/17 21:08, Alan Gauld via Tutor wrote: > Of course, the __init__ methods are special in any way Should have said *not special* in any way... > But remember that not calling super potentially leaves > some attributes of your superclass uninitialized. By not > calling super you assume full responsibility for > initializing both your sub class and the superclass. And it's worth reminding ourselves that there could be several superclasses not just the one we immediately inherit from. Finally, this discussion has been in the context of constructors but super() applies to all methods. There is nothing unique about construction, it's just like any other method call where you want to include the superclass functionality. -- Alan G Author of the Learn to Program web site http://www.alan-g.me.uk/ http://www.amazon.com/author/alan_gauld Follow my photo-blog on Flickr at: http://www.flickr.com/photos/alangauldphotos ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] super constructor usage
On 03/30/2017 05:39 AM, Rafael Knuth wrote: I am trying to wrap my head around the super constructor. > > Is it possible to embed a super constructor into an if / elif > statement within the child class? > > if message == "string A": return X > elif: return Y > > How should I modify my code below? > (I couldn't solve that by myself) > > class A: > def __init__(self, message): > self.message = message > print(message) > > class B(A): > def __init__(self, message): > print("This is the message from your parent class A:") > super(B, self).__init__(message) > > B("BlaBla") For grins, try this (decorated with prints). There's an additional argument allowed to the class B initializer, but set as a default argument so that if you omit it it defaults to True. === class A(object): def __init__(self, msg): print('A: Initializing instance of', self.__class__.__name__) self.message = msg class B(A): def __init__(self, msg, doinit=True): print('B: Initializing instance of', self.__class__.__name__) if doinit: super().__init__(msg) print("Instantiating an A:") a = A("some message") print(a.message) print("Instantiating a B:") b = B("some message") print(b.message) print("Instantiating a B without calling superclass __init__:") c = B("some message", False) print(c.message) === When you run it: Instantiating an A: A: Initializing instance of A some message Instantiating a B: B: Initializing instance of B A: Initializing instance of B some message Instantiating a B without calling superclass __init__: B: Initializing instance of B Traceback (most recent call last): File "constr-tutor.py", line 22, in print(c.message) AttributeError: 'B' object has no attribute 'message' === So note that: the instance attribute "message" is set in the class A initializer, as in all your postings in this thread. Just like Alan pointed out, there are implications if you don't call up to the superclass, and it shows up pretty clearly here: in the third case, where we decide not to call the parent's __init__, this initialization doesn't happen and the attribute is missing, so accessing it blows up with an AttributeError exception. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] super constructor usage
On 30/03/17 12:39, Rafael Knuth wrote: I am trying to wrap my head around the super constructor. > > Is it possible to embed a super constructor into an if / elif > statement within the child class? Of course, the __init__ methods are special in any way the normal coding mechanisms all work. If for some reason you only want to call super some of the time then by all means put it inside an if clause. But remember that not calling super potentially leaves some attributes of your superclass uninitialized. By not calling super you assume full responsibility for initializing both your sub class and the superclass. -- Alan G Author of the Learn to Program web site http://www.alan-g.me.uk/ http://www.amazon.com/author/alan_gauld Follow my photo-blog on Flickr at: http://www.flickr.com/photos/alangauldphotos ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] super constructor usage
>> > I am trying to wrap my head around the super constructor. Is it possible to embed a super constructor into an if / elif statement within the child class? if message == "string A": return X elif: return Y How should I modify my code below? (I couldn't solve that by myself) class A: def __init__(self, message): self.message = message print(message) class B(A): def __init__(self, message): print("This is the message from your parent class A:") super(B, self).__init__(message) B("BlaBla") ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] super constructor usage
On 03/29/2017 08:33 AM, Rafael Knuth wrote: > class A: > def __init__(self, message): > self.message = message > print(message) > > I then modified the child class B like this: > > class B(A): > def __init__(self, message): > print("This is the message from your parent class A:") > super(B, self).__init__(message) > > B("BlaBla") > > That works, however I am not sure about what exactly happens inside the code. > What I am concerned about is whether the argument is being actually > inherited from the parent class A or does B overwrite the argument. > Can anyone advise what the correct solution would be (in case mine is wrong). > Thank you. Alan (as usual) already sorted this. Just to try to fill in some of these questions - what's inherited, overridden, etc., I'm pasting a bit of code I wrote for somewhere else to demonstrate what's going on. Hope it provides some enlightenment (it's written for Python3, you'd have to change the super() call if you're using Python2). Note that your print(message) in A's initializer doesn't really tell you much, it just tells you what argument was passed to the initializer. That would be the same for any function/method, and tells you nothing about inheritance. class A(object): print('Setting class variables in A') aa_cls = 'class A data' def __init__(self): print('A: Initializing instance of', self.__class__.__name__) self.aa = 'instance of class A' def ameth(self): return "A method from class A" class B(A): print('Setting class variables in B') bb_cls = 'class B data' def __init__(self): print('B: Initializing instance of', self.__class__.__name__) super().__init__() self.bb = 'instance of class B' print("Begin examination...") print("Data from classes:") print("A.aa_cls:", A.aa_cls) print("B.aa_cls:", B.aa_cls) print("Instantiating A as a:") a = A() print("Instantiating B as b:") b = B() print("Data from instance a:") print("a.aa_cls:", a.aa_cls) print("a.aa:", a.aa) print("call ameth directly from a:", a.ameth()) print("Dict a:", a.__dict__) print("Data from instance b:") print("b.bb_cls:", b.bb_cls) print("b.bb:", b.bb) print("b.aa_cls:", b.aa_cls) print("call ameth from b:", b.ameth()) print("b.aa:", b.aa) print("Dict b:", b.__dict__) ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] super constructor usage
On 03/29/2017 04:02 PM, Mats Wichmann wrote: > On 03/29/2017 08:33 AM, Rafael Knuth wrote: > >> class A: >> def __init__(self, message): >> self.message = message >> print(message) >> >> I then modified the child class B like this: >> >> class B(A): >> def __init__(self, message): >> print("This is the message from your parent class A:") >> super(B, self).__init__(message) >> >> B("BlaBla") >> >> That works, however I am not sure about what exactly happens inside the code. >> What I am concerned about is whether the argument is being actually >> inherited from the parent class A or does B overwrite the argument. >> Can anyone advise what the correct solution would be (in case mine is wrong). >> Thank you. > > Alan (as usual) already sorted this. > > Just to try to fill in some of these questions - what's inherited, > overridden, etc., I'm pasting a bit of code I wrote for somewhere else > to demonstrate what's going on. etc. To make sure there's an even simpler answer than poring through all those cases (which I think is useful), also try this minimal rewrite of your example: class A(object): def __init__(self, message): self.message = message + " (decorated by superclass)" class B(A): def __init__(self, message): print("Class B initializer called with %s argument" % message) super().__init__(message) b = B("BlaBla") print("instance message =", b.message) ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] super constructor usage
On Wed, Mar 29, 2017 at 10:32:52PM +0100, Alan Gauld via Tutor wrote: > On 29/03/17 15:33, Rafael Knuth wrote: > > I am trying to wrap my head around the super constructor. > > This is one of these cases where it matters whether you > are using Python v2 or v3. Use of super in v3 is much > easier. It looks from your examples like you are using > v2 but it would be good to confirm that. It can't be Python 2, because A doesn't inherit from object. In that case, B's attempt to call super() would fail. [...] > > That works, however I am not sure about what exactly happens inside the > > code. > > Yes, you have the mechanism right. > As to what exactly happens inside the interpreter I'll leave > that for those who care about such things :-) The only real magic here is in super(). Everything else is just normal calling methods with arguments. What super() does is return a special object, let's call it S. When you call S.__init__, S is smart enough to ignore it's own __init__ method, and instead search B's inheritance chain (called the MRO, or Method Resolution Order), returning the first __init__ it finds. For B, the MRO is really short: first it looks at class A, then it looks at A's parent, namely `object`, which is the ultimate top of all inheritance chains in Python 3. But in general, the MRO might be very long, it might contain branches, and the same class might be included multiple times. By using super(), Python will ensure that each superclass method is called at most *one* time, in the right order, no matter how many superclasses are involved. -- Steve ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] super constructor usage
On Wed, Mar 29, 2017 at 04:33:20PM +0200, Rafael Knuth wrote: > I am trying to wrap my head around the super constructor. Simple example: > > class A: > def __init__(self): > print("world") > > class B(A): > def __init__(self): > print("hello") > super(B, self).__init__() If you are using Python 2, this cannot work. You cannot use super() inside "classic classes" in Python 2, it will fail with TypeError. To make this work in Python 2, the class A needs to inherit from object: class A(object): ... So I think you are using Python 3. In Python 3 super() is much easier to use, as there is a special shortcut: # like super(B, self).__init__() super().__init__() > B() > > Then I changed the parent class A like this, as I wanted to test how > the code would look like if I passed arguments: > > class A: > def __init__(self, message): > self.message = message > print(message) > > I then modified the child class B like this: > > class B(A): > def __init__(self, message): > print("This is the message from your parent class A:") > super(B, self).__init__(message) > > B("BlaBla") > > That works, however I am not sure about what exactly happens inside the code. > What I am concerned about is whether the argument is being actually > inherited from the parent class A or does B overwrite the argument. *Arguments* are not inherited. You are confusing two distinct, and different, parts of programming. Inheritance is that if you call a method on a child class, say B.method(), but it doesn't exist, it will call the parent class instead, say A.method(). When you pass an argument to a method or function, you pass whatever you pass, and the method or function receives what you pass. In your example, you call B("BlaBla"), so B's __init__ method receives the same argument "BlaBla" as the argument "message". Inside B, it then passes on message unchanged: B.__init__ receives message="BlaBla" B.__init__ calls super().__init__(message) A.__init__ receives message="BlaBla" If you want to change the message, of course you can do so: class C(A): def __init__(self, message): print("This is the message from your parent class A:") super().__init__(message.upper() + "!!!") C("BlaBla") And now we have: C.__init__ receives message="BlaBla" C.__init__ calls super().__init__(modified message) A.__init__ receives message="BLABLA!!!" That is exactly the same process as if we had this instead: def a_print(message): print(message) def b_print(message): print("This is output from a_print:") a_print(message) def c_print(message): print("This is output from a_print:") a_print(message.upper() + "!!!") > Can anyone advise what the correct solution would be (in case mine is wrong). > Thank you. You have the right idea. When you call your superclass method: super().__init__() # or any other method you need to decide what the *purpose of your overridden method is*. If B.__init__() does exactly the same as A.__init__(), there is no point in writing B.__init__ at all! Just leave it out, and Python will automatically do the right thing. So when you write B.__init__(), you have to decide what you want: - ignore the superclass method, and just provide your own method: class B(A): def __init__(self, message): self.message = message (but if you do this for **everything**, then why are you inheriting from A? just write B as an independent class). - call the superclass method, then do post-processing: class B(A): def __init__(self, message): super().__init__(message) self.message += "?" - pre-process the argument, then call the superclass method: class B(A): def __init__(self, message): if message == "hello?": print("There's nobody here right now.") message = "hello" super().__init__(message) - or any combination of the above. -- Steve ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] super constructor usage
On 29/03/17 15:33, Rafael Knuth wrote: > I am trying to wrap my head around the super constructor. This is one of these cases where it matters whether you are using Python v2 or v3. Use of super in v3 is much easier. It looks from your examples like you are using v2 but it would be good to confirm that. > class A: > def __init__(self): > print("world") > > class B(A): > def __init__(self): > print("hello") > super(B, self).__init__() > > B() > > Then I changed the parent class A like this, as I wanted to test how > the code would look like if I passed arguments: > > class A: > def __init__(self, message): > self.message = message > print(message) > > I then modified the child class B like this: > > class B(A): > def __init__(self, message): > print("This is the message from your parent class A:") > super(B, self).__init__(message) > > B("BlaBla") > > That works, however I am not sure about what exactly happens inside the code. Yes, you have the mechanism right. As to what exactly happens inside the interpreter I'll leave that for those who care about such things :-) > What I am concerned about is whether the argument is being actually > inherited from the parent class A or does B overwrite the argument. The argument is just a parameter of the init() method like any other argument. It is effectively a local variable. The self.message attribute however is instantiated in A and inherited by B. (At least conceptually. I'll let the interpreter gurus answer how it work in the implementation) Thus in B you could access self.message directly - and in a normal method that might be the right thing to do. But in a constructor/initializer you should leave the initializing to super() -- Alan G Author of the Learn to Program web site http://www.alan-g.me.uk/ http://www.amazon.com/author/alan_gauld Follow my photo-blog on Flickr at: http://www.flickr.com/photos/alangauldphotos ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
[Tutor] super constructor usage
I am trying to wrap my head around the super constructor. Simple example: class A: def __init__(self): print("world") class B(A): def __init__(self): print("hello") super(B, self).__init__() B() Then I changed the parent class A like this, as I wanted to test how the code would look like if I passed arguments: class A: def __init__(self, message): self.message = message print(message) I then modified the child class B like this: class B(A): def __init__(self, message): print("This is the message from your parent class A:") super(B, self).__init__(message) B("BlaBla") That works, however I am not sure about what exactly happens inside the code. What I am concerned about is whether the argument is being actually inherited from the parent class A or does B overwrite the argument. Can anyone advise what the correct solution would be (in case mine is wrong). Thank you. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor