开发者

Uninstantiable superclass

So, I'm writing a module for connecting to external account providers (Twitter, Facebook etc) and I have a superclass that is useles开发者_如何学Cs on its own, but contains generic methods that need to be invoked by the subclasses for persisting auth tokens, getting auth tokens and deauthorizing the provider. My question is, is there a way to make it uninstantiable or should I follow the consenting adults rule and just let anyone who uses it make mistakes as they see fit? Other than a docstring is there a good way to denote that someone shouldn't use this superclass on its own?


I'm seconding Sven Marnach's edit: I think you should follow the "consenting adults" rule and mention in the docstring that the class is not meant to be instantiated.

The key phrase in your question is "I have a superclass that is useless on its own." It won't invoke cthulhu when instantiated; it won't cause some kind of catastrophic, hard-to-debug failure somewhere else in your program; it will just be a minor waste of time. That's not worth crippling the class for, I think.


class NoInstantiation:    # "class NoInstantiation(object):" in Python 2.2+ or whatever
    def __new__(cls):
        "This class is not meant to be instantiated, so __new__ returns None."
        return None

This won't stop people from overriding that functionality if they want to, but it should be a fairly decent method of preventing accidental instantiation. If someone does accidentally call it, well, they can't say you didn't warn them.

EDIT: If you really wanted to be nice, you could also print a warning to stderr in __new__() about it or even throw an exception.

EDIT 2: If you go the exception route, you may want to raise the exception within the __init__() method of the superclass instead, as users will likely be overriding __init__() in their subclasses anyway.

EDIT 3: There's also the option of setting __new__ or __init__ equal to None, though the resultant error wouldn't be very informative.


Building on JAB's answer, it might be more convenient to write __new__() like this:

class NoInstantiation(object):
    def __new__(cls, *args, **kwargs):
        if cls is NoInstantiation:
            raise RuntimeError(
                "NoInstantiation isn't meant to be instantiated")
        else:
            return super(NoInstantiation, cls).__new__(cls, *args, **kwargs)

That way, you don't need to overwrite __new__() in derived classes.

Edit: I posted this answer as an improvement of JAB's answer, but I would recommend against actually using the above code. It's somehow intentionally crippling your class. The usual Python way is to clearly document the class is not meant to be instatntiated. But maybe someone finds a way how this is useful anyway -- you never know in what ways people will use your library.


You could use the abstractmethod decorator in the abc module to mark one of the methods that all of the derived classes override as abstract.

In [1]: import abc

In [2]: class C:
   ...:     __metaclass__ = abc.ABCMeta
   ...:     
   ...:     @abc.abstractmethod
   ...:     def my_abstract_method(self, *args) :
   ...:         pass
   ...:     
   ...:     

In [3]: c = C()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)

/home/afoglia/<ipython console> in <module>()

TypeError: Can't instantiate abstract class C with abstract methods my_abstract_method

I do question the class organization though. If this "superclass" is nothing but functions that need to be invoked by subclasses, why is it not just a module that the different mechanism can use? If it's a definition of an interface that derived classes fully implement, (perhaps as a template method pattern), then the abstract methods represent functions that need to be given implementations by the derived class. In that case, I wouldn't even bother making the base non-constructible, and either have people get the necessary derived through a factory method, or let the user figure it out when he calls a function that fails. (Do put a comment in the docstrings though.)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜