defaultdictを理解する

collectionsモジュールのdefaultdictについて調べてみら、dictメソッドを上書きして、辞書形式の書き込み可能なインスタンスを返すということがわかった。これを使うと、いちいちその辞書にキーが有るかどうかの処理を書かなくてよくなる。

defaultdict関数の引数に入れたタイプを指定すると自動的にその形式が返ってくる。strだったら””,intだったら0,listだったら[]みたいになる。

例1 (key,val)形式が入っているリストに対してキー名でグルーピングする

from collections import defaultdict

colors = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
d = defaultdict(list)
d["c"].append("foo")
d["c"].append("hoge")
print(d["c"]) #=> [foo,hoge]


for k, v in colors:
    d[k].append(v)


print(d.items())

#=>[('blue', [2, 4]), ('c', ['foo']), ('b', []), ('yellow', [1, 3]), ('red', [1])]

d は{}を返し、d["key"]は初期値として[]を持っているのでd["c"].append("foo")["foo"]を返す。

例2 文字列から文字の頻度を取得する。

from collections import defaultdict
s = "hello world"
d = defaultdict(int)

for i in range(0,len(s)):
    ch = s[i]
    d[ch] += 1
    sorted_chs = sorted(d.items(),key = lambda x:x[1],reverse=True)
    print(sorted_chs)

#=>[('l', 3), ('o', 2), (' ', 1), ('e', 1), ('d', 1), ('h', 1), ('r', 1),
('w', 1)]

defaultdict(int)によってdに対象のキーが存在していなかったら0を返すようになる。

結論

今まではキーチェックを毎回行っていたけど、これを使ったら今まで書いていたコードが結構減らせそう。これを良いきっかけにして今後はdefaultdictを使ってコードダイエットを積極的に行いたい。

__iter__と__next__を理解する

__iter____next__を理解するべく、rangeメソッドをRangeクラスで表現してみた。


class Range:
    def __init__(self,_min,_max,step=1):
    “””
    _min: 最小値
    _max:最大値
    step: ステップ数
    “””
        self._max = _max
        self.num = _min
        self.step = step

    def __iter__(self):
        return self

    def __next__(self):
        ret = self.num
        self.num += self.step
        if self.num > self._max:
            raise StopIteration
        return ret



for i in Range(10,100,10):
    print(i) #-> [10,20,30,40,50,60,70,80,90]
 

__iter____next__は手動で呼ぶこともできるのだけど、どちらもfor文を呼ぶと自動で呼ばれる。 __iter__とfor文の中で自動的に呼ばれるのに対して、__next__は毎回呼ばれる。__iter__で初期化を行って、__next__でその値に対して値を増加させる等の操作を行うようにすればよい。

応用して__iter__でファイルを開いて、__next__でファイルの特定の行数を取得して、raise StopIterationでファイルを閉じるとファイルの処理をfor文で書ける。


class Lines:
    """
    イテレータを使用して、Fileを開く
    """
    def __init__(self,filepath):
        self.filename = filepath

    def __iter__(self):
        """初期化"""
        self.idx = 0

        self._file = open(self.filename)
        self._file_body = [line for line in
                      self._file.read().split("\n") if len(line) is
                      not None]
        self.line_num = len(self._file_body)
        return self

    def __next__(self):
        if self.idx >= self.line_num:
            self._file.close()
            print("finished")
            raise StopIteration
        else:
            ret = self._file_body[self.idx]
            self.idx += 1
            return ret




for line in Lines("/Users/haradashinya/.vimrc"):
    print(line)
 

Flaskをずっと使ってきたけど、そろそろDjangoの使い方も覚えた方がいい気がする

最近Webアプリを作ることが多いけど、前より考え方が変わってきつつある。 特に仕事で作る場合はしっかりとした管理画面を作ったり、イロイロとちゃんとしないといけない。 前はFlaskみたいな小さいやつのほうが小回りがきくと思っていたけど画面数が増大するに連れ、油断していると フォームのバリデーションチェックやViewの切り分け、様々なヘルパーメソッドを毎回毎回、書いている感じになっている。

これぐらい毎回決まりきったコードを書くぐらいだったら、今まで使ったこと無いけどDjangoみたいな フルスタックなフレームワークを習得しようと思う。 趣味で書くのだったら相変わらずFlaskは最高だと思っているけど、DjangoもPython3に対応したし、そろそろ触って見る時期かな。 管理画面が楽に作れるらしいのでそこに期待してます。

辞書にキーを動的に追加していく

collections.defaultdictを使うと、毎回毎回キーが 格納されているかどうかをチェックして、キーをセットする 手間が省けて便利。


import collections

tree = lambda: collections.defaultdict(tree)


root = tree()
root["menu"]["id"] = "field"
root["menu"]["items"] = [1,2,3]


print(data["menu"]["id"])

 

Crontabの使い方

crontabというツールを使用すると定期的にコマンドを発行してくれます。 自分はこれを使用してDBのバックアップを取ったり、サイトを巡回プログラムを走らせています。 毎回調べるのも面倒なので、ここに簡単な流れを記しておきます。

設定方法

crontab -e でcrontabファイルを開いて編集できます。

フォーマットは * * * echo “hello”

となり、左から分、時、日、月、曜日(0-7)となります。

サンプル

1時間に1回処理を行う。

0 * * * * echo "called hourly"

1日に1回処理を行う。

0 1 * * * echo "called daily"

毎月10日の9時に処理を行う。

0 9 10 * * echo "called monthly"

確認

crontabが動いているかどうかは/var/log/syslogの中を除くと確認できます。

tail -f /var/log/syslog | grep CRON