PyCon APAC 2023

Let's implement useless Python objects
2023-10-28 , track 2

Let's implement objects that are useless for anything.
For example, an object whose length returned by the len() function is different every time, or an object that returns a bullshit result when you check if a value exists with the in operator.
And through the implementation, you will get a better understanding of Python data types.


The Python objects implemented in this presentation are not useful at all.
However, implementing completely useless objects will give you a better understanding of Python data types.
You will then be able to implement useful objects.

There are two topics covered in this presentation.

The first is understanding what happens behind the scenes of the len() function, the in operator, and the for statement.
For example, if you pass an object obj to the len() function, the result of len(obj) will be obj.__len__().
In other words, if you screw up the implementation of obj.__len__(), the result of len(obj) will also be screwed up.
You will understand what Python does behind the scenes, why you can create useless objects, and how to implement objects that behave correctly.

Second, you will understand how to use the abstract base classes in collections.abc.
Python's built-in containers include lists, tuples, dictionaries, and sets.
And the built-in containers, simply put, consist of the abstract base classes Sized, Container and Iterable in collections.abc.
If you try to implement a useless object and implement it in an absurd way, you will not be able to use it properly.
Using the abstract base class, you can create useless objects whose behaviour is absurd, but which also work with existing Python objects.
Through this experience, you will learn how to use abstract base classes and how to create your own containers correctly.

The basic agenda is as follows

  • Preliminaries: let's create a totally useless object.
  • Basics: start with Sized, Container and Iterable.
  • ElasticSized: an object that changes the return value of the len() function each time it is executed.
  • ForgottenContainer: an object where the result of the in operator changes each time it is executed.
  • ShuffledIterable: An object whose for statement changes the result each time it is executed.
  • Applications: Uncontrolled containers.
  • UncontrolledSequence: An uncontrolled sequence.
  • MisprintedDictionary: A misprinted dictionary.
  • CrowdSet: A crowd set

本発表で実装するPythonオブジェクトはまったく役に立ちません。
しかし、まったく役に立たないオブジェクトを実装すると、Pythonのデータ型の理解が深まります。
そして、役に立つオブジェクトが実装できるようになります。

本発表で扱うテーマは2つあります。

まず、len()関数やin演算子、for文の裏側で何が起きているのかを理解することです。
例えば、オブジェクトobjlen()関数に渡した場合、len(obj)の結果はobj.__len__()を返します。
つまり、obj.__len__()の実装を滅茶苦茶にすれば、len(obj)の結果も無茶苦茶になります。
なぜ役に立たないオブジェクトが作れるのか、そして、どうすれば正しい振る舞いをするオブジェクトが実装できるのかを通して、Pythonが裏側で処理していることを理解します。

2つ目は、collections.abcにある抽象基底クラスの使い方を理解することです。
Pythonの組み込みコンテナとしてリスト、タプル、辞書、集合があります。
そして、組み込みコンテナは、簡単に言えばcollections.abcにある抽象基底クラスSizedContainerIterableからなります。
役に立たないオブジェクトを実装しようとして無茶苦茶に実装しても正しく使えません。
抽象基底クラスの助けを借りることで、振る舞いは無茶苦茶なのに既存のPythonオブジェクトにも協調する役に立たないオブジェクトを作ります。
その経験を通して、抽象基底クラスの使い方や正しい自作コンテナの作り方を学ぶことができます。

基本的なアジェンダは以下の通りです。

  • 前説:まったく役に立たないオブジェクトを作ろう
  • 基本編:SizedContainerIterableから始めよう
  • ElasticSized: 実行するたびにlen()関数の返り値が変化するオブジェクト
  • ForgottenContainer: 実行するたびにin演算子の結果が変化するオブジェクト
  • ShuffledIterablefor文の実行結果が毎回変わるオブジェクト
  • 応用編: 変わり果てたコンテナたち
  • UncontrolledSequence: 無秩序なシーケンス
  • MisprintedDictionary 乱丁した辞書
  • CrowdSet: 烏合の集合