モブプロな人たちのブログ

横浜で Web サービス開発しているエンジニアの日記です。Python 大好き Flask 大好き。たまに SpriteKit でゲーム開発も。

ブログ開始時からの PV 数がようやく 1000 に到達

先ほどチラッとアクセス解析画面を見たら、ようやく 1000 に到達したみたいです。

f:id:kaorr_mob:20180116234822p:plain

継続日数もそろそろ50日に到達しそうといったところです。

f:id:kaorr_mob:20180116235000p:plain

まずは3ヶ月!」を目標に毎日更新を続けていて、次第に習慣化してきた気がします。

とはいえ、相変わらずネタ切れの感覚は消えず・・・、技術書を写経するだけの日もあり、まだまだ課題は山積みです。

まぁ、肩肘張っても仕方がないので、これからもゆるりと進めていければと思っています。

Python で unittest ですべてをテストする

「Effective Python」を久しぶりに読み返して、当時は特に何も思わなかった箇所に引っかかったのでメモを残しておきますシリーズ第6弾。

Effective Python ―Pythonプログラムを改良する59項目

Effective Python ―Pythonプログラムを改良する59項目

Python で unittest ですべてをテストする

ひー!!

いや、ホントそうですよね。

こじんまりと Python 使っていたときはそこまで意識してなかったですが、やはり unittest 大事ですよね。(まぁ、Python に限らずすべての言語で必要だと思いますが。)

写経した結果をぺたりとすると、

# utils.py

def to_str(data):
    if isinstance(data, str):
        return data
    elif isinstance(data, bytes):
        return data.decode('utf-8')
    else:
        raise TypeError('Must supply str or bytes, found: %r' % data)

↑がテスト対象の関数で、

# utils_test.py

from unittest import TestCase, main
from utils import to_str


class UtilsTestCase(TestCase):
    def test_to_str_bytes(self):
        self.assertEqual('hello', to_str(b'hello'))

    def test_to_str_str(self):
        self.assertEqual('hello', to_str('hello'))

    def test_to_str_bad(self):
        self.assertRaises(TypeError, to_str, object())


if __name__ == '__main__':
    main()

↑がテストコードです。

うん、良いですね、unittest って。

Python で リストを返さずにジェネレータを返すことを考える

「Effective Python」を久しぶりに読み返して、当時は特に何も思わなかった箇所に引っかかったのでメモを残しておきますシリーズ第5弾。

Effective Python ―Pythonプログラムを改良する59項目

Effective Python ―Pythonプログラムを改良する59項目

Python で リストを返さずにジェネレータを返すことを考える

ジェネレータ! あまり使ったことなかったです。

リストだとメモリを食いつぶす恐れのある処理などで使うと便利そうというのは分かっていても、なかなかその実装にまでたどり着きませんでした・・・。

実際にコードで見てみると分かりやすいですね。

def index_words(text):
    result = []
    if text:
        result.append(0)
    for index, letter in enumerate(text):
        if letter == ' ':
            result.append(index + 1)
    return result

def index_words_iter(text):
    if text:
        yield 0
    for index, letter in enumerate(text):
        if letter == ' ':
            yield index + 1

if __name__ == '__main__':
    address = 'Four score and seven years ago...'

    result = index_words(address)
    print(result)

    result = index_words_iter(address)
    print(list(result))

index_words() がリストを返すメソッドで、index_words_iter() がジェネレータを返すメソッドです。

メモリ関係の話は抜きにしても、コード自体がスッキリとして、とても見やすいですね!

今後は、リストではなくジェネレータに出来ないか、検討する時間を設けてみたいと思います。

Python で try/except/else/finally の各ブロックを活用する

「Effective Python」を久しぶりに読み返して、当時は特に何も思わなかった箇所に引っかかったのでメモを残しておきますシリーズ第4弾。

Effective Python ―Pythonプログラムを改良する59項目

Effective Python ―Pythonプログラムを改良する59項目

Python で try/except/else/finally の各ブロックを活用する

tryexcept は良く使いますし、finally も使いますが、else をあまり使ったことがないことに気付きました。

else を使うことのメリットは、

どの例外がココのコードで扱われていて、どの例外が上に伝わっていくかを明確にできること

です。

import json

def load_json_key(data, key):
    try:
        result_dict = json.loads(data) # ValueError の可能性
    except ValueError as e:
        print('ValueError!!')
        raise
    else:
        return result_dict[key] # KeyError の可能性

if __name__ == '__main__':
    result_value = load_json_key('{"A": 10, "B": 20}', 'C')
    print(result_value)

上記の例でいうと、

  • json.loads(data) の部分で発生する可能性のある ValueError については、ココのコードで扱うというのが明確になる
  • result_dict[key] の部分で発生する可能性のある KeyError については、ココでは特に何もせず上に伝えるというのが明確になる

ということです。若干、例が分かり難いような気もしますが・・・。

今後は、積極的に try/except/else/finally の各ブロックを活用していきたいと思います。

Python で 可変長位置引数を使って、見た目をすっきりさせる

「Effective Python」を久しぶりに読み返して、当時は特に何も思わなかった箇所に引っかかったのでメモを残しておきますシリーズ第3弾。

Effective Python ―Pythonプログラムを改良する59項目

Effective Python ―Pythonプログラムを改良する59項目

Python で 可変長位置引数を使って、見た目をすっきりさせる

すっきりとはなんぞや? という感じかもしれませんが、具体的にコードを見ると分かりやすいのです。

def log(message, values):
    if not values:
        print(message)
    else:
        values_str = ', '.join(str(x) for x in values)
        print('{0}: {1}'.format(message, values_str))

def log_with_star_args(message, *values):
    if not values:
        print(message)
    else:
        values_str = ', '.join(str(x) for x in values)
        print('{0}: {1}'.format(message, values_str))

if __name__ == '__main__':
    my_numbers = [1, 2]

    # NG
    log('My numbers are', my_numbers)
    log('My numbers are', [3, 4])
    log('Hi there', [])

    # OK
    log_with_star_args('My numbers are', *my_numbers)
    log_with_star_args('My numbers are', 3, 4)
    log_with_star_args('Hi there')

log() を呼んでる方は、第2引数に渡すものがないときに空のリストを渡していますが、log_with_star_args() を呼んでる方は、渡すものがなければ渡さなくて良くなりました。

すっきりしてて良いですね。

なお、可変長位置引数は、仮引数が *args のような記法なので「スター引数(star args)」とも呼ばれます。