2015/03/30

Python Tips:virtualenvwrapper で virtualenv の名前を変更したい

Python の環境管理ツールである virtualenv の便利ラッパー、 virtualenvwrapper で Python 環境(以下 virtualenv )の名前を変更する方法をご消化します。

結論からいうと、本記事執筆時点で virtualenvwrapper には既存の virtualenv に名前を変更する機能は用意されていないようです。 virtualenv をコピーする cpvirtualenv というコマンドが用意されてはいるのですが、「十分にサポートされていないので注意して使ってください」といった旨の注意書きが公式ページになされており、あまりおすすめでないようです。

ということで virtualenv の名前を変更すればどうすればよいか、なのですが、名前を変更するのではなく「同じ設定で作り直す」のがシンプルで確実だと思います。

具体的には、 Python のバージョンとパッケージを移行すれば大丈夫かと思いますので、そのとおりにコマンドを実行します。


$ # virtualenv で使われている Python のバージョンとパッケージのリストを取得
$ workon old_env
(old_env) $ which python > old_python_version.txt
(old_env) $ pip freeze > old_requirements.txt
(old_env) $ deactivate
$
$ # 新しい名前で環境を作成
$ mkvirtualenv new_env -p $(cat old_python_version.txt)
(new_env) $ pip install -r old_requirements.txt
(new_env) $ deactivate
$
$ # 古い環境を削除
$ rmvirtualenv old_env


old_env 、 new_env は実際の変更前後の virtualenv 名を指定すれば OK です。途中に生成するファイルは無事移行が済んだら削除しておきましょう。

以上です。

2015/03/27

Python Tips:Python で 16/256 階調 RGB カラーをランダムに出力したい

Python を使って CSS に使うような 16 階調の RGB カラーをランダムに生成する方法をご紹介します。

ランダム化の部分には組み込みの random ライブラリ、 16 進数にする部分には format の書式指定を使う方法がシンプルでやりやすいかと思います。以下のコードは Stack Overflow で紹介されていた方法を少し改変したものです。

import random

# 一度きりならこの方法で
rc = lambda: random.randint(0, 255)
print('#{:x}{:x}{:x}'.format(rc(), rc(), rc()))  # => #bd9f7b など(英字は小文字)
print('#{:X}{:X}{:X}'.format(rc(), rc(), rc()))  # => #BD9F7B など(英字は大文字)

# 何度も色を生成したいなら関数化
def generate_random_color():
    return '#{:X}{:X}{:X}'.format(*[random.randint(0, 255) for _ in range(3)])

generate_random_color()  # => #EF2F5B など

Python2 であれば Stack Overflow に紹介されたいたように str 型の % 演算子を使ってもよいのですが、 2015 年現在であれば Python3 互換の format() メソッドを使う方法がおすすめです。

2015/03/03

Python Tips:関数の合成をしたい

Python で関数の合成を行う方法をご紹介します。

「関数の合成」とは、数学でいう関数合成と同じような形でふたつの関数を合体させるような処理のことです。

数学での表記はこんな感じだったでしょうか。
f.g(x) = f(g(x))

以下、これを Python で行う方法を見ていきます。

まずは、ひとつめの関数からふたつめの関数へと受け渡しされる値がひとつの場合から。

引数がひとつだけの場合

# ふたつの関数を合成するための関数を定義する
def compose1(outer_func, inner_func):
    return lambda x: outer_func(inner_func(x))

# abs と int を合成して新たな関数 abs_int を作成する
abs_int = compose1(abs, int)

# 実際に使ってみる
print(abs_int("-12"))  # => 12 
print(abs_int(-4.3))   # => 4
compose1 という関数を使って新たに定義した abs_int は、引数を整数に変換してからさらに絶対値に変換して返す関数となりました。

ただし、この関数では次のように複数の引数を取るケースに対応できません。
abs_sum = compose1(abs, sum)
print(abs_sum(-5, -10))  # => TypeError

もう少し汎用的なものを次に見てみます。

引数が複数の場合

次の compose2 は引数が複数の場合にも、キーワード引数がある場合にも対応しています。
# ふたつの関数を合成するための関数を定義する
# こちらは引数が複数個ある場合でも大丈夫
def compose2(outer_func, inner_func):
    def composed(*args, **kwds):
        return outer_func(inner_func(*args, **kwds))
    return composed

# max の結果に abs を適用する関数を作る
abs_max = compose2(abs, max)
print(abs_max(-5, -10))  # => 5

これを使えば、たとえば標準入力から立て続けに整数を取得したい場合なんかに次のように書くことも可能です。
# input の結果に int を適用する関数を作る
questions = ["age: ", "height: ", "weight: "]
ans = map(compose2(int, input), questions)
qa = {q: a for q, a in zip(questions, ans)}
print(qa)  # => age height weight のキーと値を持った辞書

使いどころは決して多くはないかもしれませんが、ここぞというときに使えるようにしておくと便利かなと思います。

以上です。


参考
python - compose function and functional module - Stack Overflow
Function Composition in Python - Mathieu Larose