Python method call syntax shorthand - python

Is there a reason we call methods in python like object.method instead of Class.method(object)?
Maybe it isn't a strange choice, but personally it made understanding the self parameter much easier when I was shown the second way of calling a method.

Hardcoding the class name basically prevents you from using polymorphism. This is general OOP, not particularly a Python feature.
Your calling code should not need to know, nor care, which exact class object is.
This is immediately a problem for code where object can be a member of either Baseclass or Derivedclass, but much more complex inheritance and method overriding scenarios are possible, and sometimes necessary.

Related

When should a static method be a function?

I am writing a class for an image processing algorithm which has some methods, and notably a few static methods. My IDE keeps telling me to convert static methods to function which leads me to the following question:
When should a static method be turned into a function? When shouldn't it?
There are no set rules in python regarding this decision, but there are style-guides defined e.g. by companies that look to solve the ambiguity of when to use what. One popular example of this would be the Google Python Style Guide:
Never use staticmethod unless forced to in order to integrate with an API defined in an existing library. Write a module level function instead.
My guess is, that your IDE follows this stance of a hard no against the staticmethod. If you decide, that you still want to use staticmethods, you can try to disable the warning by adding # noqa as a comment on the line where the warning is shown. Or you can look in your IDE for a setting to disable this kind of warning globally.
But this is only one opinion. There are some, that do see value in using staticmethods (staticmethod considered beneficial, Why Python Developers Should Use #staticmethod and #classmethod), and there are others that argue against the usage of staticmethods (Thoughts On #staticmethod Usage In Python, #staticmethod considered a code smell)
Another quote that is often cited in this discussion is from Guido van Rossum (creator of Python):
Honestly, staticmethod was something of a mistake -- I was trying to
do something like Java class methods but once it was released I found
what was really needed was classmethod. But it was too late to get rid
of staticmethod.
I have compiled a list of arguments that I found, without any evaluation or order.
Pro module-level function:
Staticmethod lowers the cohesion of the class it is in as it is not using any of the attributes the class provides.
To call the staticmethod any other module needs to import the whole class even if you just want to use that one method.
Staticmethod binds the method to the namespace of the class which makes it longer to write SomeWhatDescriptiveClassName.method instead of method and more work to refactor code if you change the class.
Easier reuse of method in other classes or contexts.
The call signature of a staticmethod is the same as that of a classmethod or instancemethod. This masks the fact that the staticmethod does not actually read or modify any object information especially when being called from an instance. A module-level function makes this explicit.
Pro staticmethod:
Being bound by an API your class has to work in, it can be the only valid option.
Possible usage of polymorphism for the method. Can overwrite the staticmethod in a subclass to change behaviour.
Grouping a method directly to a class it is meant to be used with.
Easier to refactor between classmethod, instancemethod and staticmethod compared to module-level functions.
Having the method under the namespace of the class can help with reducing possible namespace-collisions inside your module and reducing the namespace of your module overall.
As I see it, there are no strong arguments for or against the staticmethod (except being bound by an API). So if you work in an organisation that provides a code standard to follow, just do that. Else it comes down to what helps you best to structure your code for maintainability and readability, and to convey the message of what your code is meant to do and how it is meant to be used.

Advantages of using static methods over instance methods in python

My IDE keeps suggesting I convert my instance methods to static methods. I guess because I haven't referenced any self within these methods.
An example is :
class NotificationViewSet(NSViewSet):
def pre_create_processing(self, request, obj):
log.debug(" creating messages ")
# Ensure data is consistent and belongs to the sending bot.
obj['user_id'] = request.auth.owner.id
obj['bot_id'] = request.auth.id
So my question would be: do I lose anything by just ignoring the IDE suggestions, or is there more to it?
This is a matter of workflow, intentions with your design, and also a somewhat subjective decision.
First of all, you are right, your IDE suggests converting the method to a static method because the method does not use the instance. It is most likely a good idea to follow this suggestion, but you might have a few reasons to ignore it.
Possible reasons to ignore it:
The code is soon to be changed to use the instance (on the other hand, the idea of soon is subjective, so be careful)
The code is legacy and not entirely understood/known
The interface is used in a polymorphic/duck typed way (e.g. you have a collection of objects with this method and you want to call them in a uniform way, but the implementation in this class happens to not need to use the instance - which is a bit of a code smell)
The interface is specified externally and cannot be changed (this is analog to the previous reason)
The AST of the code is read/manipulated either by itself or something that uses it and expects this method to be an instance method (this again is an external dependency on the interface)
I'm sure there can be more, but failing these types of reasons I would follow the suggestion. However, if the method does not belong to the class (e.g. factory method or something similar), I would refactor it to not be part of the class.
I think that you might be mixing up some terminology - the example is not a class method. Class methods receive the class as the first argument, they do not receive the instance. In this case you have a normal instance method that is not using its instance.
If the method does not belong in the class, you can move it out of the class and make it a standard function. Otherwise, if it should be bundled as part of the class, e.g. it's a factory function, then you should probably make it a static method as this (at a minimum) serves as useful documentation to users of your class that the method is coupled to the class, but not dependent on it's state.
Making the method static also has the advantage this it can be overridden in subclasses of the class. If the method was moved outside of the class as a regular function then subclassing is not possible.

Call super().__init__() in classes derived from `object`?

The Python documentation says that the __init__ method of each class is responsible for initializing its super class. But for new-style classes, the ultimate base class is object. Doing dir(object) shows that object itself has an __init__ method and could potentially be initialized. Is there any reason to do that?
I'm inclined to do it for consistency and (slightly) easier refactoring of the class heirarchy, but I wonder if it's strictly necessary or is considered best practice.
You don't need to initialize object; its __init__ is a no-op. It's still good practice, though, as you might want to introduce an intermediate class in the hierarchy later on.
Yes, do it. It's a good habit to get into, and it doesn't hurt.
IMHO it doesn't make any sense at all.
It makes you double check the inheritance to realize that it does nothing
It's the same as adding a pass statement with the overhead of function call.
Quoting the zen: Although practicality beats purity.
Python 3 doesn't require you to declare object as super class.
Yes, and there is a reason why you should do it.
If you ever need to use multi inheritance, python's C3 method resolution order (MRO) will not call all your __init__() base classes.

When is using __call__ a good idea?

What are peoples' opinions on using the __call__. I've only very rarely seen it used, but I think it's a very handy tool to use when you know that a class is going to be used for some default behaviour.
I think your intuition is about right.
Historically, callable objects (or what I've sometimes heard called "functors") have been used in the OO world to simulate closures. In C++ they're frequently indispensable.
However, __call__ has quite a bit of competition in the Python world:
A regular named method, whose behavior can sometimes be a lot more easily deduced from the name. Can convert to a bound method, which can be called like a function.
A closure, obtained by returning a function that's defined in a nested block.
A lambda, which is a limited but quick way of making a closure.
Generators and coroutines, whose bodies hold accumulated state much like a functor can.
I'd say the time to use __call__ is when you're not better served by one of the options above. Check the following criteria, perhaps:
Your object has state.
There is a clear "primary" behavior for your class that's kind of silly to name. E.g. if you find yourself writing run() or doStuff() or go() or the ever-popular and ever-redundant doRun(), you may have a candidate.
Your object has state that exceeds what would be expected of a generator function.
Your object wraps, emulates, or abstracts the concept of a function.
Your object has other auxilliary methods that conceptually belong with your primary behavior.
One example I like is UI command objects. Designed so that their primary task is to execute the comnand, but with extra methods to control their display as a menu item, for example, this seems to me to be the sort of thing you'd still want a callable object for.
Use it if you need your objects to be callable, that's what it's there for
I'm not sure what you mean by default behaviour
One place I have found it particularly useful is when using a wrapper or somesuch where the object is called deep inside some framework/library.
More generally, Python has a lot of double-underscore methods. They're there for a reason: they are the Python way of overloading operators. For instance, if you want a new class in which addition, I don't know, prints "foo", you define the __add__ and __radd__ methods. There's nothing inherently good or bad about this, any more than there's anything good or bad about using for loops.
In fact, using __call__ is often the more Pythonic approach, because it encourages clarity of code. You could replace MyCalculator.calculateValues( foo ) with MyCalculator( foo ), say.
Its usually used when class is used as function with some instance context, like some DecoratorClass which would be used as #DecoratorClass('some param'), so 'some param' would be stored in the instance's namespace and then instance being called as actual decorator.
It is not very useful when your class provides some different methods, since its usually not obvious what would the call do, and explicit is better than implicit in these cases.

Is it a good idea to use super() in Python?

Or should I just explicitly reference the superclasses whose methods I want to call?
It seems brittle to repeat the names of super classes when referencing their constructors, but this page http://fuhm.net/super-harmful/ makes some good arguments against using super().
The book Expert Python Programming has discussed the topic of "super pitfalls" in chapter 3. It is worth reading. Below is the book's conclusion:
Super usage has to be consistent: In a class hierarchy, super should be used everywhere or nowhere. Mixing super and classic calls is a confusing practice. People tend to avoid super, for their code to be more explicit.
Edit: Today I read this part of the book again. I'll copy some more sentences, since super usage is tricky:
Avoid multiple inheritance in your code.
Be consistent with its usage and don't mix new-style and
old-style.
Check the class hierarchy before calling its methods in
your subclass.
You can use super, but as the article says, there are drawbacks. As long as you know them, there is no problem with using the feature. It's like people saying "use composition, not inheritance" or "never use global variables". If the feature exists, there is a reason. Just be sure to understand the why and the what and use them wisely.
super() tries to solve for you the problem of multiple inheritance; it's hard to replicate its semantics and you certainly shouldn't create any new semantics unless you're completely sure.
For single inheritance, there's really no difference between
class X(Y):
def func(self):
Y.func(self)
and
class X(Y):
def func(self):
super().func()
so I guess that's just the question of taste.
I like super() more because it allows you to change the inherited class (for example when you're refactoring and add an intermediate class) without changing it on all the methods.
The problem people have with super is more a problem of multiple inheritance. So it is a little unfair to blame super. Without super multiple inheritance is even worse. Michele Simionato nicely wrapped this up in his blog article on super:
On the other hand, one may wonder if
all super warts aren't hints of some
serious problem underlying. It may
well be that the problem is not with
super, nor with cooperative methods:
the problem may be with multiple
inheritance itself.
So the main lesson is that you should try to avoid multiple inheritance.
In the interest of consistency I always use super, even if for single inheritance it does not really matter (apart from the small advantage of not having to know the parent class name). In Python 3+ super is more convenient, so there one should definitely use super.
Yes, you should use super() over other methods. This is now the standard object inheritance model in Python 3.
Just stick to keyword arguments in your __init__ methods and you shouldn't have too many problems. Additionally you can use **kwargs to support additional parameters that are not defined in levels of the inheritance chain.
I agree that it is brittle, but no less so than using the name of the inherited class.

Categories

Resources