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 commentsNoneType
:None
NotImplementedType
:NotImplemented
ellipsis
:Ellipsis
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
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()
.
The GoF book goes on to show how registries work.
- Ensuring a unique instance [...]
- 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 ofInstance
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 havingInstance
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. WhenInstance
needs a singleton, it consults the registry, asking for the singleton by name.
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
How to Get All the Request Headers in Django
Broken References in Virtualenvs
How to Plot Empirical Cdf (Ecdf)
Get the String Within Brackets in Python
Difference Between 'Python Setup.Py Install' and 'Pip Install'
Cannot Redirect Output When I Run Python Script on Windows Using Just Script's Name
How to Calculate the Inverse of the Normal Cumulative Distribution Function in Python
How to Tell Pycharm What Type a Parameter Is Expected to Be
How to Read a File Line-By-Line in Python
Python Socket Receive - Incoming Packets Always Have a Different Size
Python MySQL Connector - Unread Result Found When Using Fetchone
How to Avoid Infinite Recursion with Super()
Loading Initial Data with Django 1.7 and Data Migrations
Python Pandas Dataframe, Is It Pass-By-Value or Pass-By-Reference
Difference Between Exit(0) and Exit(1) in Python