**Background** I've taught myself Python over the past year-and-a-bit, and would consider myself an intermediate Python user at this point, but never studied computing at school/university. As such, my knowledge of theory is a little weak. Python is the only language I know. I'm trying to wrap my head around the Liskov Substitution Principle so that I can write better, more object-oriented code. **Question 1: The Python data model** As we know, in Python 3, all custom classes implicitly inherit from `object`. But the docstring of `object` includes this line: > When called, it accepts no arguments and returns a new featureless instance that has no instance attributes and cannot be given any. With this in mind, how can any python classes that accept a nonzero number of parameters for their constructors be said to comply with the LSP? If I have a class `Foo`, like so: class Foo: def __init__(self, bar): self.bar = bar then, surely this class definition (and all others like it) violates the contract specified by `object`? `object` and `Foo` cannot be used interchangeably, as `object` accepts exactly 0 parameters to its constructor, while `Foo` accepts exactly 1. **Question 2: `collections.Counter`** As Raymond Hettinger [tells us][1], the Python dictionary is an excellent example of the open/closed principle. The `dict` class is "open for extension, closed for modification" -- if you wish to modify some of the prepackaged behaviours of a `dict`, you're advised to inherit from `collections.abc.MutableMapping` or `collections.UserDict` instead. `collections.Counter`, however, is a [direct subclass][2] of `dict`. While it is mostly an extension of `dict` rather than a modification of behaviours already defined in `dict`, this isn't true for [`collection.Counter.fromkeys`][3]. With a standard `dict`, this classmethod is an alternative constructor for a dictionary, but the method is overridden in `Counter` so that it raises an exception. Here is the comment explaining why this is the case: ```none # There is no equivalent method for counters because the semantics # would be ambiguous in cases such as Counter.fromkeys('aaabbc', v=2). # Initializing counters to zero values isn't necessary because zero # is already the default value for counter lookups. Initializing # to one is easily accomplished with Counter(set(iterable)). For # more exotic cases, create a dictionary first using a dictionary # comprehension or dict.fromkeys(). ``` The explanation makes sense -- but surely this violates the LSP? According to the [Wikipedia article][4], the LSP states that "New exceptions cannot be thrown by the methods in the subtype, except if they are subtypes of exceptions thrown by the methods of the supertype." `dict.fromkeys` does not throw a `NotImplementedError`; `Counter.fromkeys` does. **Comments** I'm interested in whether these examples do, in fact, break the LSP. However, I'm also interested in *why* they break the LSP, if indeed they do. In what situations is enforcing the LSP necessary/advisable/useful? In what situations is worrying about the LSP more of a meaningless distraction? Etc. [1]: https://stackoverflow.com/a/38534939/13990016 [2]: https://github.com/python/cpython/blob/01dea5f12b31862999217c091399a318f23b460a/Lib/collections/__init__.py#L522 [3]: https://github.com/python/cpython/blob/01dea5f12b31862999217c091399a318f23b460a/Lib/collections/__init__.py#L637 [4]: https://en.wikipedia.org/wiki/Liskov_substitution_principle