2017/12/01

Python のタプルとリストの違い、タプルの使いどころ

今回は基本に立ち返って、 Python の組み込み型である「タプル」と「リスト」の違い、それと「タプルの使いどころ」について説明してみたいと思います。

「 Python タプル リスト 違い 」といったキーワードで Google 検索すると、多くのページで「リストとタプルは記法が異なります」「タプルはイミュータブルです」という説明だけがなされていて、それだけだとなぜタプルが用意されているのか、タプルはどんなときに便利なのかがわからないのではないかと思い、今回このテーマで書いてみようと思いました。

前提として、 Python におけるリストが何なのかというのは読者の方はご存知だという前提でお話ししていきます。

そもそもタプルとは何ぞやというところからまずは見ていきましょう。

タプルとは


Python における「タプル」とは、複数のデータを一直線に並べた「コレクション」タイプのデータ型です。

tuple1 = ('東京都', '神奈川県', '大阪府')
type(tuple1) == tuple  # => True

tuple1[0]  # => '東京都'
tuple1[1:]  # => ('東京都', '大阪府')

見た目上はリストのかっこ []() に変わっただけです。定義の仕方や要素へのアクセス方法もリストとよく似ています。

ただし、タプルはリストとは異なり、いったんオブジェクトを生成した後に変更ができないオブジェクトとなっています。「変更ができない」というのは、厳密には「オブジェクト id を変えずに、要素を追加・変更・削除することができない」という意味です。この性質のことを「イミュータブル」( immutable )と言ったりします。ちなみに、イミュータブルの逆(変更ができるという意味の用語)は「ミュータブル」( mutable )です。

タプルとリストの違い


では、タプルはリストと何が異なるのでしょうか。

上で述べたばかりですが、「リストは変更ができるが、タプルは変更ができない」、これが両者の違いです。上の用語を使うなら、「リストはミュータブルであり、タプルはイミュータブルである」といいます。


「イミュータブル」が意味することとしないこと


タプルを利用する場合には、「タプルはイミュータブルである」ということばの意味を正しく理解しておく必要があります。

「イミュータブル」というのはあくまでも「オブジェクト id を変えずに要素を追加・変更・削除をすることができないこと」のみを表します。逆に言うと、

  • a. タプルを参照している変数に再代入すること
  • b. タプルの中の要素がミュータブルな場合にその要素そのものを変更すること

は特に問題なくできるので、この部分を混同しないように注意が必要です。ことばでの説明だけだと意味がわかりづらいので、以下、サンプルを使ってご説明してみます。

a. タプルを参照している変数に再代入すること

次の例を見てください。

t1 = ('ハート', '7')
t1 = ('ダイヤ', '10')

タプルは変更不可ですが、このコードは問題なく動作します。変数がタプルを参照していても、そこに別のオブジェクトを再代入することは可能です。

これは、ミュータブルかイミュータブルかというポイントというよりもむしろ「 Python には定数(再代入ができないもの)がない」ことと関係していると言えるでしょう。

紛らわしいのは、 += 演算を利用した場合の挙動です。次のコードを見るとタプルが変更可能なように見えるかと思うのですが、いかがでしょうか。

t1 = ('みかん', 'りんご')
t1 += ('バナナ', 'パイナップル')
print(t1)
# => ('みかん', 'りんご', 'バナナ', 'パイナップル')

実はここにはトリックがあって、 += の行では既存のタプルが変更されているのではなく、新しいタプルが生成されています。
左辺の t1 に再代入されているのは新しく作られたタプルオブジェクトです。

同じ += の演算でも、リストの場合はここのところがまったく異なるので注意が必要です。リストの場合は、 += 演算を行っても元のオブジェクトが維持されます。

# タプルは += の結果新しいタプルが生成される
t2 = t1 = ('みかん', 'りんご')
print(id(t1))    # => 4464365064

t1 += ('バナナ', 'パイナップル')
print(id(t1))    # => 4461411048
print(t1 is t2)  # => False

# 一方、リストは += で元のリストが維持される
l2 = l1 = ['みかん', 'りんご']
print(id(l1))    # => 4464250312

l1 += ['バナナ', 'パイナップル']
print(id(l1))    # => 4464250312
print(l1 is l2)  # => True

続いて b の方を見ていきましょう。

b. タプルの中の要素がミュータブルな場合にその要素そのものを変更すること

次のサンプルを見てください(要素数が 1 のタプルを定義するときは () 内の末尾に , を入れる必要があります)。

# 第 1 要素に dict を持つタプルを定義する
t1 = ({'mark': 'ハート', 'number': '7'}, )

# dict を変更する
t1[0]['mark'] = 'スペード'

print(t1)
# => ({'mark': 'スペード', 'number': '7'}, )

この例では、 dict を要素に持つタプル t1 を定義した後に、その dict を変更しています。 dict 型はミュータブルなので、このコードは特に問題なく動作します。

再代入によって「タプルが持つ参照」そのものを変更することと、「タプルが参照するオブジェクトの中身」を変更することは別であって、タプルが許容していないのは前者の変更のみです。参照されるオブジェクトがミュータブルであれば当然そのオブジェクトの中身は更新できるので、このあたりを混同しないよう注意してください。


タプルの使いどころ


では、なぜ Python にはリストとタプルというよく似た 2 つのコレクション型が用意されているのでしょうか。
リストは他のプログラミング言語で「配列」と呼ばれるものに近く、多くのプログラマーにとってより直観的です。リストだけあれば十分じゃないかとも思えます。

このあたりの疑問点はタプルの具体的な使いどころを見るとすっきり理解できるので、タプルを使うべき場面を具体的に見てましょう。

タプルの使いどころ 1: 変更を許可しない変数を定義する

変更を許可したくない変数を定義したい場合にタプルは便利です。

API_KEYS = ('xxx', 'yyy', 'zzz')

例えば、上のコードのように、外部サービスの API キーを格納したタプルを用意すると、再代入さえしなければ、中身が変わっていないことが保証されているという前提の下でその変数を使いまわすことができます。

関数型プログラミングに見られるような「思わぬ変更が生まれる可能性を最小化してバグの発生源を減らす」という考え方でプログラムを組みたい場合なんかにもタプルは便利です。

タプルの使いどころ 2: dict のキーに使う

dict のキーには hashable なオブジェクトのみが利用できます。

リストは hashable ではないので、 dict のキーに使うことはできません。

例えば、 Python で地図アプリのようなものを考えるとします。この場合、処理の途中で、緯度経度の情報をキーに、その建物の名前を値に入れた辞書を作りたくことがあるかもしれませんが、リストは hashable ではないので緯度経度の情報を格納するためには使えません。しかし、タプルは hashable なので、 dict のキーとして使用することができます。

# リストとタプルが hashable かどうかを確認する
from collections import Hashable

print(isinstance([], Hashable))  # => False
print(isinstance((), Hashable))  # => True

# 緯度経度の情報をキーに、建物名を値に入れた dict を用意する
locations = {
    (35.676, 139.744): '国会議事堂',
    (34.669, 135.431): 'ホグワーツ城',
    (35.039, 135.729): '鹿苑寺金閣',
}

dict 的なデータ型のキーに文字列しか受け付けないような言語の場合は、このような数字のペアに特別な意味がある場合でもそれをキーとすることはできませんが、 Python は組み込み型のタプルを使うことで比較的かんたんにこのようなロジックを実現することができます。

タプルの使いどころ 3: パフォーマンスをよりよくする

パフォーマンスの観点で、タプルはリストよりもよいようです。

ただし、よっぽどパフォーマンスが重要となるシビアな場面で無いかぎり、「リストじゃだめだ!やっぱりタプルじゃないと!」となるようなケースは稀なのではないかと思います。パフォーマンスの観点でデータ型を気にするのであれば、「リストかタプルか」の選択ではなく、もっと他の選択肢を選んだ方がよいような気がします。

・・・こんなところでしょうか。

ポイントは「変更ができないという特徴を活かす」「リストではできないことをやる」といったところになるかと思います。

Python のタプルについて理解を深めたいという方の参考になれば幸いです。

最後に、タプルの挙動を確認するユニットテストのサンプルコードを載せておきます。興味のある方は python3 -m unittest などで走らせてみてください。

# coding: utf-8

import unittest

class TupleBasicTest(unittest.TestCase):
    '''タプルの基本的な使い方を確認する
    '''

    def test_creation(self):
        # タプルを生成する
        t1 = ('ギン', 'ギラ', 'ギン')
        self.assertIsInstance(t1, tuple)

        # 実践的な場面で使うことはまずないが空のタプルを生成する
        t2 = ()
        self.assertIsInstance(t2, tuple)

        # 要素数が 1 のタプルについては `,` が必須となるため注意が必要
        t3 = ('さりげなし', )
        self.assertIsInstance(t3, tuple)
        s1 = ('さりげなし')
        self.assertIsInstance(s1, str)

    def test_access(self):
        # タプルの要素にアクセスする
        t1 = ('炎', '天', '下')

        self.assertEqual(t1[0], '炎')
        self.assertEqual(t1[1], '天')

        self.assertEqual(t1[-1], '下')

        self.assertEqual(t1[0:2], ('炎', '天'))

    def test_conversion(self):
        l1 = ('岡山', 15)
        self.assertIsInstance(tuple(l1), tuple)

        t1 = ('香川', 18)
        self.assertEqual(list(t1), ['香川', 18])

    def test_methods(self):
        self.assertEqual((3, 4, 4, 5).count(4), 2)
        self.assertEqual((3, 4, 4, 5).index(5), 3)

    def test_in(self):
        self.assertTrue(3 in (3, 4, 4, 5))
        self.assertFalse(108 in (3, 4, 4, 5))


参考

3. Data model — Python 3.6.3 documentation
I'm able to use a mutable object as a dictionary key in python. Is this not disallowed? - Stack Overflow

2017/11/22

Python Tips: Python でインタフェースを使いたい

Python でインタフェースの機能を使う方法をご紹介します。

・・・といっても、 Python 3.6 の時点で Python には言語機能としてのインタフェースは存在しません。具体的にいうと、「継承先に特定のインタフェースの実装を強制できるような仕組み」が Python にはありません。

しかし、標準ライブラリの abc を使うと次の 2 つのことが実現できます。

  • a. 複数のクラスを抽象クラスでまとめる
  • b. 継承先クラスのインスタンス生成時にメソッドの存在チェックをかける

このことをもって、「 Python でも他の言語でいうところの『インタフェース』の機能をある程度は利用できる 」と考えてもよいのではないかな、と個人的には思います。

今回はこの Python におけるインタフェース的な機能を abc で実現する方法をご紹介します。上の a b を順に見ていきましょう。


a. 複数のクラスを抽象クラスでまとめる


最初に、複数のクラスを抽象クラスでまとめる方法を見てみます。

複数の異なるクラスを抽象クラスでまとめることで、それらのクラスのオブジェクトに対して isinstance() が True を返すようなチェック機構を作ることができます。

具体的なコードを見てみましょう。

# coding: utf-8

'''デジタルコンテンツインタフェースを作ってテストする
'''

from abc import ABC


class Movie:
    '''映画
    '''
    pass


class Book:
    '''書籍
    '''
    pass


class DigitalContentInterface(ABC):
    '''デジタルコンテンツのインタフェース
    '''
    pass


# 映画と書籍を DigitalContentInterface の仮想サブクラスとして登録する
DigitalContentInterface.register(Movie)
DigitalContentInterface.register(Book)


def is_digital_content(object):
    '''オブジェクトがデジタルコンテンツかどうかをチェック
    '''
    return isinstance(object, DigitalContentInterface)


# Movie のインスタンスは DigitalContentInterface のインスタンスと認識される
m1 = Movie()
print(is_digital_content(m1))  # => True

# Book のインスタンスも DigitalContentInterface のインスタンスと認識される
b1 = Book()
print(is_digital_content(b1))  # => True

# 登録されていないクラスのインスタンスでは当然 False が返る
d1 = {}
print(is_digital_content(d1))  # => False

ここでは abc.ABC というクラスを継承する形で DigitalContentInterface というインタフェース用のクラスを作成しました。

続いて、クラスメソッド register() を使って、 MovieBook という 2 つのクラスを DigitalContentInterface の仮想サブクラスとして登録しています。

その後に isinstance() でチェックをかけると、 MovieBook のインスタンスは DigitalContentInterface のインスタンスと認識されることが確認できます。

おもしろいですね。

register() メソッドが便利なのは、組み込みのクラスを含む定義済みのクラスも「独自に作ったインタフェース」の仮想サブクラスとして登録できるところです。

# リストは本来(当然) DigitalContentInterface のインスタンスではない
l1 = []
print(is_digital_content(l1))  # => False

# リストクラスを DigitalContentInterface の仮想サブクラスとして登録すると・・・
DigitalContentInterface.register(list)

# リストのインスタンスも DigitalContentInterface のインスタンスと認識されるようになる
print(is_digital_content(l1))  # => True

ちなみに、この、特定のクラスを仮想サブクラスとして登録する register() メソッドを使った方法とは別に、クラスメソッド __subclasshook__() を使った方法も用意されています。

公式のサンプルを少し縮めたサンプルを見てみましょう。

class MyIterable(ABC):

    @classmethod
    def __subclasshook__(cls, C):
        if cls is MyIterable:
            if any("__iter__" in B.__dict__ for B in C.__mro__):
                return True
        return NotImplemented

ここでは、 __subclasshook__() メソッドを実装することで「 __iter__() メソッドを実装しているクラスは MyIterable のサブクラスとみなす」というロジックが実現されています。 __subclasshook__() を使えば、このようにより柔軟なロジックで仮想サブクラスを設定することができます(例えば、インタフェースの定義時には具体的な仮想サブクラスがわからない状態でも仮想サブクラスを登録することができます)。

ちなみに、この abc.ABC はメタクラス abc.ABCMeta をよりシンプルに扱えるクラスとして Python 3.4 で導入されました。

a については以上です。続いて b の方を説明していきます。


b. 継承先クラスのインスタンス生成時にメソッドの存在チェックをかける


こちらは、よりインタフェースっぽい感じのふるまいが実現できる機能です。

こちらも先にサンプルコードを見てみましょう。

# coding: utf-8

'''デジタルコンテンツインタフェースでメソッドの実装の強制機能をテストする
'''

from abc import ABC
from abc import abstractmethod


class DigitalContentInterface(ABC):
    '''デジタルコンテンツのインタフェース
    '''

    def __init__(self, title):
        self.title = title

    @abstractmethod
    def format_title(self):
        pass


class Movie(DigitalContentInterface):

    def format_title(self):
        return 'Movie: {}'.format(self.title)


class Book(DigitalContentInterface):
    pass


# Movie のインスタンスは問題なく生成できる
m1 = Movie('From Dusk Till Dawn')
print(m1.format_title())
# => Movie: From Dusk Till Dawn
print(isinstance(m1, DigitalContentInterface))
# => True

# Book のインスタンスは
# Book が format_title() メソッドを定義していないので作成できない
b1 = Book('The Martian')
# TypeError: Can't instantiate abstract class Book with abstract methods format_title

以下、コード内の処理の流れを説明します。

まず最初に、 a と同じような形で abc.ABC クラスを継承した DigitalContentInterface というクラスを定義しています。この中で abc.abstractmethod というデコレータ用の関数を使って format_title() というメソッドをアブストラクトメソッドとして登録しています。

つづいて、 a の register() を使った形ではなく、通常の継承のシンタックスを使って DigitalContentInterface を継承したクラス MovieBook を定義しています。

実際にインスタンスを生成しようとすると、 Movie の方は問題なく生成できますが、 Book の方はアブストラクトメソッド format_title() をきちんと実装していないということで例外が上がって生成できません。

・・・というように、「インスタンス生成時にメソッドの存在チェックをかける」ことができていることが確認できます。

こちらもおもしろいですね。うまく活用できると便利そうです。

ただし、 b の方は使う際に押さえておくべき注意点がいくつかあります。

  • register() を使った方法で登録した仮想サブクラスに対してはチェックが走らない
  • @abstractmethod で登録されたメソッド自身が `pass` 以外の実装を持つことができて、サブクラスから super() で呼び出すことができる

ここで取り上げたのはインスタンスメソッドを使ったパターンだけでしたが、クラスメソッド、スタティックメソッド、プロパティに対しても同様のチェックを行うこともできます。その場合はデコレータの記述順などにも厳密なルールがあるため、興味のある方は利用の前に公式のドキュメントなどでしっかり確かめてから使うようにするとよいかと思います。


以上です。

おもしろいですねー。


参考

abc” Abstract Base Classes — Python documentation
Python でも ABC (Abstract Base Class) を使えば抽象クラスが作れる | CUBE SUGAR STORAGE

2017/11/17

Python Tips: 改行をうまく扱いたい

Python での改行の扱い方についてまとめてみました。わりとピンポイントなテーマになりますが、興味のある方はご参考にしてみていただければと思います。

  • Python における改行コード
  • 改行なしで出力する
  • ファイルの中身を行単位で取得する
  • 文字列の末尾の改行コードを取り除く
  • 文字列を改行で分割する
  • 改行コードをそのまま出力する
  • ソースコード内で改行する

Python における改行コード


まずは、基本中の基本ですが、今回のお話の前提となる「 Python における改行コード」について見ておきましょう。

Python における改行コードは \n です。

print('五月雨を\nあつめて早し\n最上川')
# =>
# 五月雨を
# あつめて早し
# 最上川
#

print("蛤の\nふたみにわかれ\n行秋ぞ")
# =>
# 蛤の
# ふたみにわかれ
# 行秋ぞ
#

文字列中に \n を入れるとそれが改行コードとして解釈されます。

Python には文字列リテラルの表記が 2 種類ーー通常の引用符と二重引用符がーーありますが、どちらも改行コードに関するふるまいは同じで、改行コードは出力時に改行に変換されます。

改行なしで出力する


組み込みの print() 関数は、デフォルトでは末尾に改行を自動的に追加するふるまいになっています。

print('Hello')
print('world')
# =>
# Hello
# world

この改行を防ぐには 2 の方法があります。

  • a. print() の引数 end を指定する
  • b. print() の代わりに sys.stdout.write() を使う

a. print() の引数 end を指定する

print() 関数の宣言部は次のようになっていて、このうちの end を指定すると、末尾に自動で追加される改行コードを変更することができます。

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

改行なしの出力にしたい場合は単純に空文字を渡せば OK です。

print('Hello', end='')
print('world', end='')
# => Helloworld

b. print() の代わりに sys.stdout.write() を使う

標準ライブラリ syssys.stdout.write()print() と同じように標準出力に書き出すための関数ですが、こちらは末尾に改行を自動追加するようなことはしないので、文字列を渡せばそれがそのまま出力されます。

import sys

sys.stdout.write('Hello')
sys.stdout.write('world')
# => Helloworld

このトピックについては過去にも記事を書いているので、興味のある方はご覧になってみてください。


ファイルの中身を行単位で取得する


テキストファイルの中身を改行までをひとつの区切りとして取得する方法です。方法がいくつかあるのでひとつずつご紹介します。

  • a. ファイルオブジェクトを for ループで回す
  • b. ファイルオブジェクトの readline() メソッドを使う
  • c. ファイルオブジェクトの readlines() メソッドを使う

a. ファイルオブジェクトを for ループで回す

ファイルオブジェクトはイテレータプロトコルを備えているので、ループで回すことができます。その場合の各要素はファイル内の各行となります。

with open(FILE_IN) as f:
    for line in f:
        print(line, end='')
# => ファイルの各行が出力される

各行の末尾には改行コード \n が付いたままになっているので、他のファイルや標準出力に出力する際には末尾の改行が重複しないように気をつける必要があります。

b. ファイルオブジェクトの readline() メソッドを使う

ファイルオブジェクトには readline() というメソッドが備わっており、これを使えば for ループの場合と同様に行単位でファイルの中身を取得することができます。

with open(FILE_IN) as f:
    while True:
        line = f.readline()
        if not line:
            break
        print(line, end='')
# => ファイルの各行が出力される

こちらの場合は readline() の戻り値が空文字列になればファイルの末尾に到達したことになります。ファイル途中の空行の場合は空文字ではなく改行コード \n が 1 つだけ入った文字列が返るので、区別することができます。

a と b を比べると、 pythonic なのはどちらかということ a の方なので、 b で書きたい強い理由が特に無いかぎりは a のパターンで書くのがよいかと思います。

c. ファイルオブジェクトの readlines() メソッドを使う

ファイルオブジェクトの readlines() メソッドは、その名前が示すとおり、ファイルの中身を複数行まとめて取得できるメソッドです。

with open(FILE_IN) as f:
    print(f.readlines())
# => ファイルの全行が行単位で格納されたリスト

ファイルのサイズが巨大な場合にどうなるかは調べていないのでわかりませんが、私が確認したかぎりでは、ファイルの全行を行単位で格納したリストが生成されます。 a 、 b の方法と同じく、こちらの場合も末尾の改行は含まれたままとなっているので注意が必要です。

ちなみに、次の例のように、ファイルオブジェクトの readlines() メソッドに引数を渡すと取得行数を指定することもできます。

with open(FILE_IN) as f:
    while True:
        lines = f.readlines(5):
        if not lines:
            break
        print(lines)
# => ファイルの中身を 5 行ずつ取得したリスト
# ファイルの行数が 5 行よりも少ない場合は、例外などは上がらずファイルの行がすべて格納される

文字列の末尾の改行コードを取り除く


続いて、文字列の末尾の改行コードを取り除く方法です。上の「テキストファイルの中身を行単位で取得する」ときなどに、各行を前処理したい場合などに利用することがあるかと思います。

方法としては、おそらく rstrip() メソッドを使う方法が最もシンプルで、なおかつ間違いがありません。

with open(FILE_IN) as f:
    for line in f:
        trimmed = line.rstrip('\n')
        print(trimmed)
# => ファイルの各行が表示される

ちなみに、 for ループで各行を取得した場合には、行の先頭に改行文字列があることは無いので、ここの rstrip()strip() に置き換えても同じ結果を得ることができます。ただ、 strip() よりも rstrip() を使った方がコードの意図をより明確に示すことができるので、このようなケースでは私は rstrip() を好んで使っています。

文字列を改行で分割する


間に改行が挟まった文字列を改行のところで分解する方法についてです。

こちらは、文字列型の splitlines() メソッドを使うのがよいでしょう。

haiku = '夏草や\n兵どもが\n夢の跡'
lines = haiku.splitlines()
print(lines)
# => ['夏草や', '兵どもが', '夢の跡']

名前そのままの挙動でわかりやすいですね。

ちなみに、 splitlines()keepends という引数を受け取ることができます。これは「改行コードを残すかどうか」を指定するためのフラグで、デフォルト値は False になっています。 True にすると、戻り値のリストの各要素の末尾に改行コードが残ったままになります。

haiku = '夏草や\n兵どもが\n夢の跡'
lines = haiku.splitlines(keepends=True)
print(lines)
# => ['夏草や\n', '兵どもが\n', '夢の跡']

同様の処理は、文字列型の split() メソッドで行うこともできますが、区切り文字が改行コードなら、 splitlines() を使う方が意図をより明確に示せるのでよいかなと思います。

改行コードをそのまま出力する


次は、改行コードをそのまま出力する方法についてです。

改行コードを変換せずにそのまま出力するには、 repr() 関数をかませるか、フォーマット文字列シンタックスの変換フラグ !rrepr() )を使うとよいかと思います。どちらも得られる結果は同じです。

haiku = '石山の\n石より白し\n秋の風'
print(repr(haiku))
# => '石山の\n石より白し\n秋の風'

haiku = '石山の\n石より白し\n秋の風'
print('{!r}'.format(haiku))
# => '石山の\n石より白し\n秋の風'

ソースコード内で改行する


以上のお話はすべて「文字列の中の改行」についてのお話でしたが、これは文字列の中ではなく、 Python のソースコードの中で改行するにはどうすればよいか、というお話です。

Python は、 C 言語のように文の末尾に ; を付ける必要がない代わりに、通常は行末がそのままひとつの文の終わりを意味することになっています。では、メソッドチェーンなどで一文が長くなるときにはどうやって改行したらよいのでしょうか。メジャーなやり方は、大きく分けて 2 つあります。

  • a. 改行を \ でエスケープする
  • b. かっこの中で改行する

a. 改行を \ でエスケープする

コード中の改行を文の終わりにしたくない場合は、 \ (バックスラッシュ)を使えば OK です。改行の直前に \ を置きましょう。

Address.select() \
    .where(Address.geo_lng.is_null(False)) \
    .where(Address.geo_lat.is_null(False))

b. かっこの中で改行する

Python では通常文末が文の終わりを示すことになりますが、かっこの中だけはわりと自由に改行することができます。ここで「かっこ」というのは、 [](){} のことを指しています。

例えば、リスト内包は次のように改行を入れて書くことができます。

[x * 5
    for x in range(10)
    if x % 2 == 0]

また、関数やメソッドの () 内の引数は途中で自由に改行することができます。

Address.select(
    Address.title,
    Address.geo_lng,
    Address.geo_lat)

この方法を使えば、例えば、メソッドチェーンが長くなる場合に、式全体を () でくくることで、各行の行末に毎回 \ を入れる手間を省くことができます。

(Address.select()
    .where(Address.geo_lng.is_null(False))
    .where(Address.geo_lat.is_null(False)))

・・・

というわけで、以上です。

このあたりは基本的なところではありますが、他の言語を長く触っていて久しぶりに Python に戻ってきたときなんかによく忘れていたりするので、パッと確認できるようにしておくと便利かと思います。

Python の改行の扱い方をまとめて押さえておきたいときにぜひ参考にしてみてください。