Skip to content

Latest commit

 

History

History
62 lines (55 loc) · 3.62 KB

ch11.md

File metadata and controls

62 lines (55 loc) · 3.62 KB

Interfaces: From Protocols to ABCs

Interfaces and Protocols

  • Interface: the collection of methods and attributes that a class or module exposes for use by the rest of the program
  • Statically typed languages like Java define formal interfaces. The code will not compile if a class does not implement every method defined in its interface.
  • Dynamically typed languages like Python, Ruby, and Javascript use Protocols, which are informal interfaces not enforced by the language, but followed by programmers as a best practice.

Python Data model tries to abide by protocols

  • Ex: Sequence Protocol
  • Abstract base class for a sequence:
    • has an abstract __getitem__ method
    • implements concrete __contains__, __iter__ and __reversed__ methods
  • If a programmer implements their own sequence like object with only a __getitem__ method, there are default implementations of the other 3 methods.

Monkey Patching Example

  • Monkey Patching - changing a class or module at runtime, without modifying the source code.
  • French Deck example:
    • FrenchDeck class did not implement a shuffle method
    • Author monkey patches the __setitem__ method by making a direct assignment
      FrenchDeck.__setitem__ = set_card
    • __setitem__ is part of the mutable sequence protocol.
    • The random.shuffle method works on mutable sequences, so it can now be called on FrenchDeck instances.
  • Warning: Monkey Patched code is tightly coupled.

Alex Martelli Guest Essay on ABCs

  • Duck typing requires avoiding use of isinstance to check types.
  • Allows for more flexible programs.
  • Shortcoming of duck typing: unrelated objects may share a method name that behaves differently in each context.
  • Ex:
        Class Artist:
            def draw(self): ...
    
        Class Gunslinger:
            def draw(self): ...
  • Goose typing - account for context by using abstract base classes
    • okay to use isinstance, provided it is only used on ABCs.
  • suggests not implementing custom ABCs, but making use of the ABCs that classes implicitly inherit from through protocols
  • Inheriting from an ABC can be used to communicate intent and give context.

Subclassing ABCs

  • Python defines ABCs for users to inherit from. These should cover a large percentage of use cases, and inheriting from an existing ABC is often a better choice than defining a new one.
    • Exception: if you are writing a framework
  • Implementations of ABCs are checked at runtime, and the interpreter raises a TypeError if a method of an abstract class is not implemented by the subclass.

ABCs from the standard library

  • collections.abc module : python docs
  • numbers module: python docs
    • use for type checks. e.g. isinstance(x, numbers.Integral) instead of isinstance(x, int) where you want to include bool, int, and types from other libraries that have been registered as virtual subclasses of numbers.Integral.

Creating custom ABCs

  • Inherit from abc.ABC
  • use @abstractmethod decorator
  • register method: registers a virtual subclass of an abc. This will change the behavior of isinstance and issubclass calls, but will not require the virtual subclass to implement abstract methods from the base class.

Key Takeaways

  • Following established protocols improves the chances of reusing standard library and third party code.
  • Try implementing existing ABCs from the standard library before creating your own.
  • Implementing ABCs can give you default method implementations for free.