Yes, the fact that you can call a static method through an instance in Python means you get "virtual static" methods. I'm not sure that's an especially compelling use for them. Consider the case where UNIXPrinter is-a Printer, but provides a definition of the printer method that doesn't call the newlines static method. Unless UNIXPrinter provides the unneeded newlines staticmethod anyway, a caller rationally expecting newlines to perform '\r\n' -> '\n' conversion will be awfully surprised when it does not.
That is not to say such an approach never makes sense, but you've increased the maintenance burden on all of your child classes in support of one specific implementation of the printer method. That's a violation of the open/closed principal.
A good use of @classmethod/@staticmethod is when someone is naturally supplied a type (instead of an instance), and they need to perform useful operations on the type. This is common with plugins: you may have a list / dict of registered plugin types, and each type has a static/class method "add_options" that adds command-line options to an argparse / optparse instance, so the plugin can manipulate the command-line. They're necessary in this example because: 1) It's (typically) silly to instantiate an instance of the Plugin just to do command-line parsing. The Plugin shouldn't be instantiated until there is useful work to do. 2) The Plugin class must necessarily provide the entire interface between the main application and the plugin. If it doesn't exist on the Plugin class, the main application cannot call it.
Comment
Certainly by passing the conversion function?
def newlines(s):
return s.replace('\n', '\r')
class Printer(object):
def __init__(self, text, to_newline=newlines):
self.text = text
self.to_newline = to_newline
def printer(self):
return self.to_newline(self.text)
def _to_unix_newline(s):
return s.replace('\r\n', '\n')
def UNIXPrinter(text):
return Printer(text, _to_unix_newline)
Yes, the fact that you can call a static method through an instance in Python means you get "virtual static" methods. I'm not sure that's an especially compelling use for them. Consider the case where UNIXPrinter is-a Printer, but provides a definition of the printer method that doesn't call the newlines static method. Unless UNIXPrinter provides the unneeded newlines staticmethod anyway, a caller rationally expecting newlines to perform '\r\n' -> '\n' conversion will be awfully surprised when it does not.
That is not to say such an approach never makes sense, but you've increased the maintenance burden on all of your child classes in support of one specific implementation of the printer method. That's a violation of the open/closed principal.
A good use of @classmethod/@staticmethod is when someone is naturally supplied a type (instead of an instance), and they need to perform useful operations on the type. This is common with plugins: you may have a list / dict of registered plugin types, and each type has a static/class method "add_options" that adds command-line options to an argparse / optparse instance, so the plugin can manipulate the command-line. They're necessary in this example because:
1) It's (typically) silly to instantiate an instance of the Plugin just to do command-line parsing. The Plugin shouldn't be instantiated until there is useful work to do.
2) The Plugin class must necessarily provide the entire interface between the main application and the plugin. If it doesn't exist on the Plugin class, the main application cannot call it.