2016/06/29

Python Tips:長い方のリストに合わせて zip したい

Python で複数のリストのループを回すときに、長い方のリストにあわせてループを回す方法についてご説明します。

Python では、組み込み関数 zip() を使うと、かんたんに複数のリストを同時に回すことができます。

names = ['Rao', 'Toki', 'Jagi', 'Ken']
numbers = [1, 5]

for name, number in zip(names, numbers):
    print([name, number])
# => ['Rao', 1]
# ['Toki', 5]

ただし、ループの回数は長さの短い方のリストに切り詰められます。この場合は names の長さが 4 、 numbers の長さが 2 なので、結果としてループの回数は 2 回となります。

これでよい場合は特に問題ないのですが、ループ回数を長い方にあわせてほしい場合はこれでは困ります。そんなときに便利なのが標準ライブラリ itertools の zip_longest() 関数です。名前がそのまま!ですね。

使い方は zip() とほぼ同じです。

from itertools import zip_longest

names = ['Rao', 'Toki', 'Jagi', 'Ken']
numbers = [1, 5]

for name, number in zip_longest(names, numbers):
    print([name, number])
# => ['Rao', 1]
# ['Toki', 5]
# ['Jagi', None]
# ['Ken', None]

短い方の足りない部分は None で代用されます。

以上です。

max(len(l1), len(l2)) で長い方のリストの長さは取得できるので、自分で実装してもさほど長い処理にはなりませんが、 zip_longest() を使うと Pythonic でわかりやすく書けるので、使えるところではなるべくこちらを使っていきたいところですね。

2016/06/20

Python の三項演算子

Python の三項演算子についてご説明します。

Python では次の形で三項演算を利用することができます。

result = a if cond else b

この場合、条件 cond が True の場合は a 、そうでない場合は b が返されます。

例を挙げてみます。たとえば、次の関数は引数が True と評価される場合だけその値を int() 関数に渡す関数です。

def to_int(num_raw):
    """引数を整数型に変換する
    """
    return int(num_raw) if num_raw else 0

次のように使います。

to_int('5')   # => 5
to_int('12')  # => 12
to_int('')    # => 0  else の値が返される
to_int(None)  # => 0  else の値が返される

int() に空文字列や None を渡すと例外があがるので、この例では引数が空文字列や None の場合の戻り値は 0 にフォールバックするようにしています。

もうひとつ例をあげてみます。次の例では debug フラグが True の場合は p は pprint となり、 False の場合は通常の print となります。

from pprint import pprint

debug = True

# debug フラグが True の場合は pprint を使う、そうでない場合は print を使う
p = pprint if debug else print

p({'first name': 'Taro', 'last name': 'Suzuki',
'country': 'Japan', 'age': 20, 'hobby': 'Tennis'})
# => {'age': 20,
# 'country': 'Japan',
# 'first name': 'Taro',
# 'hobby': 'Tennis',
# 'last name': 'Suzuki'}

以上です。

ちなみに三項演算の if else を重ねて入れ子にすることもできますが、見た目が複雑になり一見でぱっと処理が理解できない式になるので、原則三項演算は入れ子にはせず別の式に分けた方がよいかと思います。

以上です。

ちなみに、三項演算子は英語では「 ternary operator 」や「 ternary conditional operator 」というそうです。


- Does Python have a ternary conditional operator? - Stack Overflow

2016/06/08

Python Tips:Python 3 の nonlocal を使いたい

タイトルそのままですが、 Python 3 の nonlocal の利用方法について説明してみたいと思います。

Python の変数スコープは原則「関数」がスコープの切れ目となっており、関数の内部で定義された変数に関数の外部からアクセスすることはできません。

def myfunc():
    a = 10

print(a)  # => NameError: name 'a' is not defined

一方、関数の内側から関数の外側にある変数にはアクセスすることが可能です。

a = 10

def myfunc():
    print(a)

myfunc()  # => 10

ただし、関数の内側から外側の変数へのアクセスは基本的に「参照」のみが可能です。値を更新するには nonlocal 宣言をしなくてはなりません。

nonlocal を使った例はこちら。

# coding: utf8

def gen_counter():
        """呼び出すごとにカウントを上げるカウンタを生成する
        """

    # クロージャ _counter で利用する現在のカウント
    count = 0

    def _counter(reset=False):
          # 関数の外にある count を更新したいので nonlocal 宣言をする
        nonlocal count

        if reset:
            count = 0
        count += 1
        return count

    return _counter


# カウンタを使用する
c1 = gen_counter()

# nonlocal のおかげで更新した count の値が保持できることの確認
print(c1())  # => 1
print(c1())  # => 2
print(c1())  # => 3

print(c1(reset=True))  # => 1
print(c1())  # => 2

nonlocal 宣言をすることで、 _counter() 関数の外側にある count 変数を _counter() の内側で更新することができています。

この例では nonlocal 宣言をしないとむしろ、「 UnboundLocalError: local variable 'count' referenced before assignment 」というエラーが出てしまって実行する自体できません。

ただし、関数の内側から外側の変数の「代入」はできないということについては 1 点注意が必要です。ミュータブル( mutable )なデータ型の場合は「代入」はできなくてもその中身を変更することはできてしまいます。ミュータブルなデータ型の代表はリストです。

def gen_stack():
        """スタックを生成する
        """
    stack = []

    def _stack(value=False):
        if value:
            # 変数 stack は関数の外側にあるが変更が可能
            stack.append(value)
        else:
            # 変数 stack は関数の外側にあるが変更が可能
            return stack.pop()

    return _stack


q = gen_stack()

# スタックに値を入れる
q(3)  # stack: [3]
q(5)  # stack: [3, 5]
q(7)  # stack: [3, 5, 7]

# スタックから値を取り出す
print(q())  # => 7  stack: [3, 5]
print(q())  # => 5  stack: [3]
print(q())  # => 3  stack: []

以上です。

複雑になる場合はムリに関数と nonlocal を使わずクラスを使うのがよさそうなのでこのあたりでハマることはあまりないかとは思いますが、挙動を正しく理解していないと思わぬバグが生まれるので注意が必要ですね。

2016/06/02

Python Tips:Sublime Text で pep8 のオートフォーマッタを使いたい

エディタ「 Sublime Text 」で pep8 のオートフォーマッタを利用する方法についてです。対象バージョンは Sublime Text 2 と 3 の両方です。

「方法」といっても手順はかんたんで、「 Python PEP8 Autoformat 」という Sublime Text パッケージをインストールするだけです。

1. Sublime Text を開いてコマンドパレットを開く
2. 「 Package Control: Install Package 」を選択
3. 「 Python PEP8 Autoformat 」を選択
4. インストール完了

Python PEP8 Autoformat にはオートフォーマッタの本体である Python の pep8 パッケージが同梱されているので、パッケージを別途インストールする必要などはありません。 Python PEP8 Autoformat をインストールしたらすぐに使いはじめることができます。

.py ファイルを保存したときに自動で走らせたい場合は設定ファイルにその旨を書き込めば OK です。

1. ( Sublime Text 2 の場合) Preferences → Package Settings → Python PEP8 Autoformat → Settings User
2. パッケージディレクトリの「 User 」ディレクトリ内の「 pep8_autoformat.sublime-settings 」というファイルが開く
3. 以下の内容を記入して保存

{
    // autoformat code on save
    "autoformat_on_save": true
}

ファイルの保存後に .py ファイルを適当に保存すると、 pep8 でのオートフォーマット処理が走ることが確認できることと思います。

以上です。

(私は深掘りできていませんが)その他 pep8 パッケージが持つ各種オプションも利用できるようなので、カスタマイズして本格的に使用したい場合は公式のページをぜひ覗いてみてください。

こういうオートフォーマッタは強力で、一度使うととても便利なのでやめられなくなりますね。

Python PEP8 Autoformat - Packages - Package Control
Pythonにまつわるアイデア:PEP 8 - Life with Python