Is there a purpose in calling super() from a basic python class? - python

I have somewhat of a strange question here. Let's say I'm making a simple, basic class as follows:
class MyClass(object):
def __init__(self):
super(MyClass, self).__init__()
Is there any purpose in calling super()? My class only has the default object parent class. The reason why I'm asking this is because my IDE automagically gives me this snippet when I create a new class. I usually remove the super() function because I don't see any purpose in leaving it. But maybe I'm missing something ?

You're not obliged to call object.__init__ (via super or otherwise). It does nothing.
However, the purpose of writing that snippet in that way in an __init__ function (or any function that calls the superclass) is to give you some flexibility to change the superclass without modifying that code.
So it doesn't buy you much, but it does buy you the ability to change the superclass of MyClass to a different class whose __init__ likewise accepts no-args, but which perhaps does do something and does need to be called by subclass __init__ functions. All without modifying your MyClass.__init__.
Your call whether that's worth having.
Also in this particular example you can leave out MyClass.__init__ entirely, because yours does nothing too.

Related

Call the method of the super class in an other method of the subclass

I already asked about something related to the game I am developing. The Problem occured while the developement, but actually it has nothing to do with the game it self.
I have a method ('resize' in a subclass) in my Code which calls the equivalent method in it's super class ('resize' of the superclass).
Expected Behaviour: Super-resize calls Super-do_rotozoom
What happend: Super-resize called Sub-do_rotozoom
Here is a code Example:
Subclass:
def do_rotozoom(self):
# do rotozoom stuff of subclass
def resize(self,factor):
super().resize(factor)
self.do_rotozoom()
Superclass:
def do_rotozoom(self):
#do rotozoom stuff of superclass
def resize(self,factor):
self.factor = factor
self.do_rotozoom()
I found a workaround which involved calling super().do_rotozoom() in the Subclass method do_rotozoom() which then was called by the super().resize(). I also found out, that I could in this case remove the line self.do_rotozoom().
In this case it was a pretty easy fix, but what would I do in a more complex scenario, for example, if I need to call the method do_rotozoom() with other variables in the superclass than I do in the subclass/another specific implementation? In other words, how am I able to select which method I want to use in a specific context?
Normaly you are only able to reach the super-methods from the subclass, but no super-methods (not of it's superclass but it's own methods) from the superclass.
I have not found a better title... :D
Developers tend to prefer Composition over inheritance , it's much more manageable .
what i advise you to do is to include an instance of your superclass in you subclass and use it whenever you want to .
The very definition of a subclass is that it inherits everything from the superclass except the methods and attributes it overrides.
A subclass can refer to its superclass and its method implementations with super(), like you already do in your example.
Either don't override do_rotozoom, or refer to the superclass method with super().do_rotozoom() where that's the behavior you require.

When do you need to pass arguments to python super()?

A use case of the super() builtin in python is to call an overridden method. Here is a simple example of using super() to call Parent class's echo function:
class Parent():
def echo(self):
print("in Parent")
class Child(Parent):
def echo(self):
super().echo()
print("in Child")
I've seen code that passes 2 parameters to super(). In that case, the signature looks somehing like super(subClass, instance) where subClass is the sub class calling super() from, and instance is the instance the call being made from, ie self. So in the above example, the super() line would become:
super(Child, self).echo()
Looking at python3 docs, these 2 use cases are the same when calling from inside of a class.
Is calling super() with 2 parameters completely deprecated as of python3? If this is only deprecated for calling overridden functions, can you show an example why they're needed for other cases?
I'm also interested to know why python needed those 2 arguments? Are they injected/evaluated when making super() calls in python3, or they're just not needed in that case?
If you don't pass the arguments, Python 3 makes an effort to provide them for you. It's a little kludgy, but it usually works. Essentially, it just assumes the first parameter to your method is self (the second argument to super), and when the class definition completes, it provides a virtual closure scope for any function that refers to super or __class__ that defines __class__ as the class you just defined, so no-arg super() can check the stack frame to find __class__ as the first argument.
This usually works, but there are cases where it doesn't:
In staticmethods (since the first argument isn't actually the class), though staticmethods aren't really supposed to participate in the inheritance hierarchy the same way, so that's not exactly unexpected.
In functions that take *args as the first argument (which was the only safe way to implement any method that accepted arbitrary keyword arguments like dict subclasses prior to 3.8, when they introduced positional-only arguments).
If the super call is in a nested scope, which can be implicit, e.g. a generator expression, or comprehension of any kind (list, set, dict), since the nested scope isn't directly attached to the class, so it doesn't get the __class__ defining magic that methods attached to the class itself get.
There are also rare cases where you might want to explicitly bypass a particular class for resolving the parent method, in which case you'd need to explicitly pass a different class from later in the MRO than the one it would pull by default. This is deep and terrible magic, so I don't recommend it, but I think I've had cause to do it once.
All of those are relatively rare cases, so most of the time, for code purely targeting Python 3, you're fine using no-arg super, and only falling back to explicitly passing arguments when you can't use it for whatever reason. No-arg super is cleaner, faster, and during live development can be more correct (if you replace MyClass, instances of the old version of the class will have the old version cached and no-arg super will continue to work, where looking it up manually in your globals would find the new version of the class and explode), so use it whenever you can.
In Python 3, super() with zero arguments is already the shortcut for super(__class__, self). See PEP3135 for complete explanation.
This is not the case for Python 2, so I guess that most code examples you found were actually written for Python 2 (or Python2+3 compatible)

Should methods that do not act on object data be made static?

I have a class that includes some auxiliary functions that do not operate on object data. Ordinarily I would leave these methods private, but I am in Python so there is no such thing. In testing, I am finding it slightly goofy to have to instantiate an instance of my class in order to be able to call these methods. Is there a solid theoretical reason to choose to keep these methods non-static or to make them static?
If a method does not need access to the current instance, you may want to make it either a classmethod, a staticmethod or a plain function.
A classmethod will get the current class as first param. This enable it to access the class attributes including other classmethods or staticmethods. This is the right choice if your method needs to call other classmethods or staticmethods.
A staticmethod only gets it's explicit argument - actually it nothing but a function that can be resolved on the class or instance. The main points of staticmethods are specialization - you can override a staticmethod in a child class and have a method (classmethod or instancemethod) of the base class call the overridden version of the staticmethod - and eventually ease of use - you don't need to import the function apart from the class (at this point it's bordering on lazyness but I've had a couple cases with dynamic imports etc where it happened to be handy).
A plain function is, well, just a plain function - no class-based dispatch, no inheritance, no fancy stuff. But if it's only a helper function used internally by a couple classes in the same module and not part of the classes nor module API, it's possibly just what you're looking for.
As a last note: you can have "some kind of" privacy in Python. Mostly, prefixing a name (whether an attribute / method / class or plain function) with a single leading underscore means "this is an implementation detail, it's NOT part of the API, you're not even supposed to know it exists, it might change or disappear without notice, so if you use it and your code breaks then it's your problem".
If you want to keep said methods in the class just for structural reasons, you might as well make them static, by using the #staticmethod decorator:
class Foo():
#staticmethod
def my_static_method(*args, **kwargs):
....
Your first argument will not be interpretted as the object itself, and you can use it from either the class or an object from that class. If you still need to access class attributes in your method though, you can make it a class method:
class Bar():
counter = 0
#classmethod
def my_class_method(cls, *args, **kwargs):
cls.counter += 1
...
Your first argument of the class method will obviously be the class instead of the instance.
If you do not use any class or instance attribute, I can see no "theoretical" reason to not make them static. Some IDE's even highlight this as a soft warning to prompt you to make the method static if it does not use or mutate any class/instance attribute.

In python, what is super(classItSelf) doing?

In python, what is super(classItSelf) doing?
I have a project to work on has code such as this:
class Tele(TcInterface):
_signal = signal.SIGUSR1
def __init__(self):
super(Tele, self).__init__()
self._c = None
What is this line doing?
super(Tele, self).__init__()
I am a cpp java code, Really got confused about python stuff.
This calls the __init__() function (constructor) of the super/parent class (TclInterface). This is often necessary, as the superclass constructor is otherwise overridden by __init__() in the subclass.
you need to pass at least self to __init__.
python is different from some traditional OOP languages, which will handle self or this or whatever name you give to the current instance automatically for you.
in python, self is exposed, even in constructor, so that you need to pass in and reference it yourself. and this super(...) here, it basically looks for a proxy, which represents all super classes, and super(...).__init__ is referencing the constructors from the super classes. it's the same concept as you call super() in C++ or Java.
please reference doc for more: https://docs.python.org/2/library/functions.html#super

Python inheritance - referring to specific levels

I'm having trouble with Python (2.7) inheritance. I'm trying to refer from derived classes to parents and back, which is easy enough if you hard-code the classes, but that seems like an ugly approach to me. Is it? Anyway, here we go:
class Alpha(object):
def fie(self):
pass
class Beta(Alpha):
def fie(self):
super(self.__class__, self).fie()
class Gamma(Beta):
pass
Alpha().fie()
Beta().fie()
Gamma().fie()
The last one calls fie as defined on Beta, but since it's called from Gamma, the super will refer to Beta. As such it'll call itself again and starts an infinite recursion.
Is there a way to reference the class for which the function is initially defined? Or the class highest up the chain (besides object)? Or possibly an even better way to accomplish this without hard-coding class names?
Nope - you just have to write it as:
class Beta(Alpha):
def fie(self):
super(Beta, self).fie()
See: http://yergler.net/blog/2011/07/04/super-self/ - and quoted from there (as it explains it better than I could!):
According to the Python 2.7.2 standard library documentation, super “return[s] a proxy object that delegates method calls to a parent or sibling class of type.” So in the case of single inheritance, it delegates access to the super class, it does not return an instance of the super class. In the example above, this means that when you instantiate B, the follow happens:
enter B.__init__()
call super on B and call __init__ on the proxy object
enter A.__init__()
call super on self.__class__ and call __init__ on the proxy object
The problem is that when we get to step four, self still refers to our instance of B, so calling super points back to A again. In technical terms: Ka-bloom.
And within that article is a link to a blog by Raymond Hettinger (and they're always worth reading): http://rhettinger.wordpress.com/2011/05/26/super-considered-super/
NB: read the comment where a user suggests using type(self) (equiv to your self._class_) and why it doesn't work

Categories

Resources