Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preventing a class from direct instantiation in Python

I have a super class with a method that calls other methods that are only defined in its sub classes. That's why, when I create an instance of my super class and call its method, it cannot find the method and raises an error.

Here is an example:

class SuperClass(object):    def method_one(self):     value = self.subclass_method()     print value   class SubClassOne(SuperClass):    def subclass_method(self):     return 'subclass 1'   class SubClassTwo(SuperClass):    def subclass_method(self):     return 'nubclass 2'   s1 = SubClassOne() s1.method_one()  s2 = SubClassTwo() s2.method_one()  c = SuperClass() c.method_one()  # Results: # subclass 1 # nubclass 2 # Traceback (most recent call last): #   File "abst.py", line 28, in <module> #     c.method_one() #   File "abst.py", line 4, in method_one #     value = self.subclass_method() # AttributeError: 'SuperClass' object has no attribute 'subclass_method' 

I was thinking about changing the init of super class and verify the type of object, when a new instance is created. If the object belongs to super class raise an error. However, I'm not too sure if it's the Pythonic way of doing it.

Any recommendations?

like image 841
mohi666 Avatar asked Nov 03 '11 00:11

mohi666


People also ask

How do you prevent a class from creating an object?

Making the class static is the best approach, if you absolutely don't want any instances. This stops anyone from creating instances. The class will be both sealed and abstract, and won't have any constructors.

What is __ new __ in Python?

The __new__() is a static method of the object class. When you create a new object by calling the class, Python calls the __new__() method to create the object first and then calls the __init__() method to initialize the object's attributes.


2 Answers

I would override __new__() in the base class and simply fail to instantiate at all if it's the base class.

class BaseClass:    # Py3      def __new__(cls, *args, **kwargs):         if cls is BaseClass:             raise TypeError(f"only children of '{cls.__name__}' may be instantiated")         return object.__new__(cls, *args, **kwargs) 

This separates concerns a little better than having it in __init__(), and "fails fast."

like image 175
kindall Avatar answered Sep 23 '22 08:09

kindall


Your approach is a typical framework pattern.

Using __init__ to verify that type(self) is not SuperClass is a reasonable way to make sure the SuperClass hasn't been instantiated directly.

The other common approach is to provide stub methods that raise NotImplementedError when called. That is more reliable because it also validates that subclasses have overridden the expected methods.

like image 42
Raymond Hettinger Avatar answered Sep 23 '22 08:09

Raymond Hettinger