Which Classes Cannot Be Subclassed

Which classes cannot be subclassed?

There seems to be two reasons for a class to be "final" in Python.

1. Violation of Class Invariant

Classes that follow Singleton pattern have an invariant that there's a limited (pre-determined) number of instances. Any violation of this invariant in a subclass will be inconsistent with the class' intent, and would not work correctly. Examples:

  • bool: True, False; see Guido's comments
  • NoneType: None
  • NotImplementedType: NotImplemented
  • ellipsis: Ellipsis

There may be cases other than the Singleton pattern in this category but I'm not aware of any.

2. No Persuasive Use Case

A class implemented in C requires additional work to allow subclassing (at least in CPython). Doing such work without a convincing use case is not very attractive, so volunteers are less likely to come forward. Examples:

  • function; see Tim Peters' post

Note 1:

I originally thought there were valid use cases, but simply insufficient interest, in subclassing of function and operator.itemgetter. Thanks to @agf for pointing out that the use cases offered here and here are not convincing (see @agf comments to the question).

Note 2:

My concern is that another Python implementation might accidentally allow subclassing a class that's final in CPython. This may result in non-portable code (a use case may be weak, but someone might still write code that subclasses function if their Python supports it). This can be resolved by marking in Python documentation all built-in and standard library classes that cannot be subclassed, and requiring that all implementations follow CPython behavior in that respect.

Note 3:

The message produced by CPython in all the above cases is:

TypeError: type 'bool' is not an acceptable base type

It is quite cryptic, as numerous questions on this subject show. I'll submit a suggestion to add a paragraph to the documentation that explains final classes, and maybe even change the error message to:

TypeError: type 'bool' is final (non-extensible)

Why singleton classes cannot be sub-classed?

Buy or borrow a copy of GoF

The original GoF book says the following in the Implementation part of Singleton. Note: Instance is the same as the Java getInstance().

  1. Ensuring a unique instance [...]
  2. Subclassing the Singleton class. The main issue is not so much defining the subclass but installing its unique instance so that clients will be able to use it. In essence, the variable that refers to the singleton instance must get initialized with an instance of the subclass. The simplest technique is to determine which singleton you want to use in the Singleton's Instance operation. An example in the Sample Code shows how to implement this technique with environment variables.

    Another way to chose the subclass of Singleton is to take the implementation of Instance out of the parent class and put it in the subclass. That lets a C++ programmer decide the class of singleton at link-time (e.g., by linking in an object file containing a different implementation) but keeps it hidden from the clients of the singleton.

    The link approach fixes the choice of singleton class at link-time, which makes it hard to choose the singleton class at run-time. Using conditional statements to determine the subclass is more flexible, but it hard-wires the set of possible Singleton classes. Neither approach is flexible enough in all cases.

    A more flexible approach uses a registry of singletons. Instead of having Instance define the set of possible Singleton classes, the Singleton classes can register their singleton instance by name in a well-known registry.

    The registry maps between string names and singletons. When Instance needs a singleton, it consults the registry, asking for the singleton by name.

The GoF book goes on to show how registries work.

Here's the Sample Code using the environment variable:

Now let's consider what happens when there are subclasses... We'll select the [subtype] through an environment variable [...]

MazeFactory* MazeFactory::Instance () {
if (_instance == 0) {
const char* mazeStyle = getenv("MAZESTYLE");

if (strcmp(mazeStyle, "bombed") == 0 {
_instance = new BombedMazeFactory;

} else if (strcmp(mazeStyle, "enchanted") == 0) }
_instance = new EnchantedMazeFactory;

// ... other possible subclasses

} else { // default
_instance = new MazeFactory;
}
}
return _instance;
}

Different ways in which we can create a class, which can not be sub classed (Extended)?

Make all the constructors in the class private (or give them default access, if you are only concerned with subclasses in another package), including a private no-argument constructor. Any classes which attempt to inherit from such a class will not compile, even if there is no attempt to create objects of the subclass. You can still provide the ability to instantiate such a class with a static getInstance(arguments)-type method.

The clearest and cleanest way to prevent a class from being extended, however, is to declare the class as final.

How does python prevent a class from being subclassed?

The bool type is defined in C, and its tp_flags slot deliberately does not include the Py_TPFLAGS_BASETYPE flag.

C types need to mark themselves explicitly as subclassable.

To do this for custom Python classes, use a metaclass:

class Final(type):
def __new__(cls, name, bases, classdict):
for b in bases:
if isinstance(b, Final):
raise TypeError("type '{0}' is not an acceptable base type".format(b.__name__))
return type.__new__(cls, name, bases, dict(classdict))

class Foo:
__metaclass__ = Final

class Bar(Foo):
pass

gives:

>>> class Bar(Foo):
... pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in __new__
TypeError: type 'Foo' is not an acceptable base type

FBAdViewControllerProxy is a final class and cannot be subclassed. FBAdViewControllerProxy

The Solution was to change podfile to:

target 'Unity-iPhone Tests' do
end
target 'UnityFramework' do
pod 'FBAudienceNetwork', '~> 6.2.0'
end

and then open the project in terminal and run : pod install

Final classes in Python 3.x- something Guido isn't telling me?

You can simulate the same effect from Python 3.x quite easily:

class Final(type):
def __new__(cls, name, bases, classdict):
for b in bases:
if isinstance(b, Final):
raise TypeError("type '{0}' is not an acceptable base type".format(b.__name__))
return type.__new__(cls, name, bases, dict(classdict))

class C(metaclass=Final): pass

class D(C): pass

will give the following output:

Traceback (most recent call last):
File "C:\Temp\final.py", line 10, in <module>
class D(C): pass
File "C:\Temp\final.py", line 5, in __new__
raise TypeError("type '{0}' is not an acceptable base type".format(b.__name__))
TypeError: type 'C' is not an acceptable base type

Class cannot subclass 'QObject' (has type 'Any') using mypy

This error occurs when mypy doesn't have type information for a class (in your case due to a lack of stubs) and you have --disallow-subclassing-any turned on. You can either disable this flag, add typing information, or, as you pointed out, put a # type: ignore to silence the error.



Related Topics



Leave a reply



Submit